diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/DBChecker.scala b/eclair-core/src/main/scala/fr/acinq/eclair/DBChecker.scala index bacd948555..59c3433367 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/DBChecker.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/DBChecker.scala @@ -16,7 +16,7 @@ package fr.acinq.eclair -import fr.acinq.eclair.channel.{ChannelDataWithCommitments, PersistentChannelData} +import fr.acinq.eclair.channel.PersistentChannelDataWithKeys import fr.acinq.eclair.router.Router import fr.acinq.eclair.wire.protocol.NodeAnnouncement import grizzled.slf4j.Logging @@ -31,18 +31,16 @@ object DBChecker extends Logging { * - it is compatible with the current version of eclair * - channel keys can be re-generated from the channel seed */ - def checkChannelsDB(nodeParams: NodeParams): Seq[PersistentChannelData] = { + def checkChannelsDB(nodeParams: NodeParams): Seq[PersistentChannelDataWithKeys] = { Try(nodeParams.db.channels.listLocalChannels()) match { case Success(channels) => - channels.foreach { - case data: ChannelDataWithCommitments => - val channelKeys = nodeParams.channelKeyManager.channelKeys(data.channelParams.channelConfig, data.channelParams.localParams.fundingKeyPath) - if (!data.commitments.validateSeed(channelKeys)) { - throw InvalidChannelSeedException(data.channelId) - } - case _ => () - } - channels + channels.map(channel => { + val channelWithKeys = channel.withChannelKeys(nodeParams) + if (!channelWithKeys.validateSeed()) { + throw InvalidChannelSeedException(channel.channelId) + } + channelWithKeys + }) case Failure(t) => throw IncompatibleDBException(t) } } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala b/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala index c21f718541..b5440fc7ba 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala @@ -389,7 +389,7 @@ class Setup(val datadir: File, txPublisherFactory = Channel.SimpleTxPublisherFactory(nodeParams, bitcoinClient) channelFactory = Peer.SimpleChannelFactory(nodeParams, watcher, relayer, bitcoinClient, txPublisherFactory) - pendingChannelsRateLimiter = system.spawn(Behaviors.supervise(PendingChannelsRateLimiter(nodeParams, router.toTyped, channels)).onFailure(typed.SupervisorStrategy.resume), name = "pending-channels-rate-limiter") + pendingChannelsRateLimiter = system.spawn(Behaviors.supervise(PendingChannelsRateLimiter(nodeParams, router.toTyped, channels.map(_.channelData))).onFailure(typed.SupervisorStrategy.resume), name = "pending-channels-rate-limiter") peerFactory = Switchboard.SimplePeerFactory(nodeParams, bitcoinClient, channelFactory, pendingChannelsRateLimiter, register, router.toTyped) switchboard = system.actorOf(SimpleSupervisor.props(Switchboard.props(nodeParams, peerFactory), "switchboard", SupervisorStrategy.Resume)) @@ -403,7 +403,7 @@ class Setup(val datadir: File, balanceActor = system.spawn(BalanceActor(bitcoinClient, nodeParams.channelConf.minDepth, channelsListener, nodeParams.balanceCheckInterval), name = "balance-actor") postman = system.spawn(Behaviors.supervise(Postman(nodeParams, switchboard, router.toTyped, register, offerManager)).onFailure(typed.SupervisorStrategy.restart), name = "postman") peerScorer_opt = if (nodeParams.peerScoringConfig.enabled) { - val statsTracker = system.spawn(Behaviors.supervise(PeerStatsTracker(nodeParams.peerStatsTrackerConfig, nodeParams.db.audit, channels)).onFailure(typed.SupervisorStrategy.restart), name = "peer-stats-tracker") + val statsTracker = system.spawn(Behaviors.supervise(PeerStatsTracker(nodeParams.peerStatsTrackerConfig, nodeParams.db.audit, channels.map(_.channelData))).onFailure(typed.SupervisorStrategy.restart), name = "peer-stats-tracker") Some(system.spawn(Behaviors.supervise(PeerScorer(nodeParams, bitcoinClient, statsTracker, register)).onFailure(typed.SupervisorStrategy.restart), name = "peer-scorer")) } else None diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelData.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelData.scala index 548ae9497f..49b33b287b 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelData.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelData.scala @@ -23,12 +23,13 @@ import fr.acinq.eclair.blockchain.fee.{ConfirmationTarget, FeeratePerKw} import fr.acinq.eclair.channel.Helpers.Closing import fr.acinq.eclair.channel.fund.InteractiveTxBuilder._ import fr.acinq.eclair.channel.fund.{InteractiveTxBuilder, InteractiveTxSigningSession} +import fr.acinq.eclair.crypto.keymanager.ChannelKeys import fr.acinq.eclair.io.Peer import fr.acinq.eclair.reputation.Reputation import fr.acinq.eclair.transactions.CommitmentSpec import fr.acinq.eclair.transactions.Transactions._ import fr.acinq.eclair.wire.protocol.{ChannelAnnouncement, ChannelReady, ChannelReestablish, ChannelUpdate, ClosingSigned, CommitSig, FailureReason, FundingCreated, FundingSigned, Init, LiquidityAds, OnionRoutingPacket, OpenChannel, OpenDualFundedChannel, Shutdown, SpliceInit, Stfu, TxInitRbf, TxSignatures, UpdateAddHtlc, UpdateFailHtlc, UpdateFailMalformedHtlc, UpdateFulfillHtlc} -import fr.acinq.eclair.{Alias, BlockHeight, CltvExpiry, CltvExpiryDelta, Features, InitFeature, MilliSatoshi, MilliSatoshiLong, RealShortChannelId, TimestampMilli, UInt64} +import fr.acinq.eclair.{Alias, BlockHeight, CltvExpiry, CltvExpiryDelta, Features, InitFeature, MilliSatoshi, MilliSatoshiLong, NodeParams, RealShortChannelId, TimestampMilli, UInt64} import scodec.bits.ByteVector import java.util.UUID @@ -549,7 +550,22 @@ case object Nothing extends TransientChannelData { sealed trait PersistentChannelData extends ChannelData { def remoteNodeId: PublicKey def channelParams: ChannelParams + def withChannelKeys(nodeParams: NodeParams): PersistentChannelDataWithKeys = { + val channelKeys = nodeParams.channelKeyManager.channelKeys(channelParams.channelConfig, channelParams.localParams.fundingKeyPath) + PersistentChannelDataWithKeys(this, channelKeys) + } +} + +case class PersistentChannelDataWithKeys(channelData: PersistentChannelData, channelKeys: ChannelKeys) { + val channelId: ByteVector32 = channelData.channelId + val remoteNodeId: PublicKey = channelData.remoteNodeId + + def validateSeed(): Boolean = channelData match { + case c: ChannelDataWithCommitments => c.commitments.validateSeed(channelKeys) + case _: DATA_WAIT_FOR_DUAL_FUNDING_SIGNED => true + } } + sealed trait ChannelDataWithoutCommitments extends PersistentChannelData { val channelId: ByteVector32 = channelParams.channelId val remoteNodeId: PublicKey = channelParams.remoteNodeId diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala b/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala index 63b373fb79..d37e1c0342 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/io/Peer.scala @@ -83,13 +83,12 @@ class Peer(val nodeParams: NodeParams, case Event(init: Init, _) => pendingOnTheFlyFunding = init.pendingOnTheFlyFunding val channels = init.storedChannels.map { state => - val channelKeys = nodeParams.channelKeyManager.channelKeys(state.channelParams.channelConfig, state.channelParams.localParams.fundingKeyPath) - val channel = spawnChannel(channelKeys) - channel ! INPUT_RESTORED(state) + val channel = spawnChannel(state.channelKeys) + channel ! INPUT_RESTORED(state.channelData) FinalChannelId(state.channelId) -> channel }.toMap // We only connect to nodes with whom we have a channel, which aren't mobile wallets. - val autoReconnect = init.storedChannels.exists(c => !c.channelParams.remoteParams.initFeatures.hasFeature(Features.WakeUpNotificationClient)) + val autoReconnect = init.storedChannels.exists(c => !c.channelData.channelParams.remoteParams.initFeatures.hasFeature(Features.WakeUpNotificationClient)) context.system.eventStream.publish(PeerCreated(self, remoteNodeId)) // When we restart, we will attempt to reconnect right away, but then we'll wait. // We don't fetch our peer's features from the DB: if the connection succeeds, we will get them from their init message, which saves a DB call. @@ -1121,7 +1120,7 @@ object Peer { case object DISCONNECTED extends State case object CONNECTED extends State - case class Init(storedChannels: Set[PersistentChannelData], pendingOnTheFlyFunding: Map[ByteVector32, OnTheFlyFunding.Pending]) + case class Init(storedChannels: Set[PersistentChannelDataWithKeys], pendingOnTheFlyFunding: Map[ByteVector32, OnTheFlyFunding.Pending]) case class Connect(nodeId: PublicKey, address_opt: Option[NodeAddress], replyTo: ActorRef, isPersistent: Boolean) { def uri: Option[NodeURI] = address_opt.map(NodeURI(nodeId, _)) } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/io/Switchboard.scala b/eclair-core/src/main/scala/fr/acinq/eclair/io/Switchboard.scala index c455056c66..85f87afb4a 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/io/Switchboard.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/io/Switchboard.scala @@ -54,10 +54,10 @@ class Switchboard(nodeParams: NodeParams, peerFactory: Switchboard.PeerFactory) // Check if channels that are still in CLOSING state have actually been closed. This can happen when the app is stopped // just after a channel state has transitioned to CLOSED and before it has effectively been removed. // Closed channels will be removed, other channels will be restored. - val (channels, closedChannels) = init.channels.partition(c => Closing.isClosed(c, None).isEmpty) + val (channels, closedChannels) = init.channels.partition(c => Closing.isClosed(c.channelData, None).isEmpty) closedChannels.foreach(c => { log.info("channel {} was closed before restarting, updating the DB", c.channelId) - val closingData_opt = (c, Closing.isClosed(c, None)) match { + val closingData_opt = (c.channelData, Closing.isClosed(c.channelData, None)) match { case (c: DATA_CLOSING, Some(closingType)) => Some(DATA_CLOSED(c, closingType)) case _ => None } @@ -71,7 +71,7 @@ class Switchboard(nodeParams: NodeParams, peerFactory: Switchboard.PeerFactory) (peersWithOnTheFlyFunding -- peersWithChannels.keySet).foreach { case (remoteNodeId, pending) => createOrGetPeer(remoteNodeId, Set.empty, pending) } - val peerCapacities = channels.map { + val peerCapacities = channels.map(_.channelData).map { case channelData: ChannelDataWithoutCommitments => (channelData.remoteNodeId, 0L) case channelData: ChannelDataWithCommitments => (channelData.remoteNodeId, channelData.commitments.capacity.toLong) }.groupMapReduce[PublicKey, Long](_._1)(_._2)(_ + _) @@ -152,9 +152,9 @@ class Switchboard(nodeParams: NodeParams, peerFactory: Switchboard.PeerFactory) */ def getPeer(remoteNodeId: PublicKey): Option[ActorRef] = context.child(peerActorName(remoteNodeId)) - def createPeer(remoteNodeId: PublicKey): ActorRef = peerFactory.spawn(context, remoteNodeId) + private def createPeer(remoteNodeId: PublicKey): ActorRef = peerFactory.spawn(context, remoteNodeId) - def createOrGetPeer(remoteNodeId: PublicKey, offlineChannels: Set[PersistentChannelData], pendingOnTheFlyFunding: Map[ByteVector32, OnTheFlyFunding.Pending]): ActorRef = { + private def createOrGetPeer(remoteNodeId: PublicKey, offlineChannels: Set[PersistentChannelDataWithKeys], pendingOnTheFlyFunding: Map[ByteVector32, OnTheFlyFunding.Pending]): ActorRef = { getPeer(remoteNodeId) match { case Some(peer) => peer case None => @@ -190,7 +190,7 @@ object Switchboard { def peerActorName(remoteNodeId: PublicKey): String = s"peer-$remoteNodeId" // @formatter:off - case class Init(channels: Seq[PersistentChannelData]) + case class Init(channels: Seq[PersistentChannelDataWithKeys]) case object GetPeers case class GetPeerInfo(replyTo: typed.ActorRef[PeerInfoResponse], remoteNodeId: PublicKey) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/payment/relay/PostRestartHtlcCleaner.scala b/eclair-core/src/main/scala/fr/acinq/eclair/payment/relay/PostRestartHtlcCleaner.scala index 9236f0430b..93a4cdea47 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/payment/relay/PostRestartHtlcCleaner.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/payment/relay/PostRestartHtlcCleaner.scala @@ -71,9 +71,9 @@ class PostRestartHtlcCleaner(nodeParams: NodeParams, register: ActorRef, initial val channels = listLocalChannels(init.channels) val onTheFlyPayments = nodeParams.db.liquidity.listPendingOnTheFlyPayments().values.flatten.toSet val nonStandardIncomingHtlcs: Seq[IncomingHtlc] = nodeParams.pluginParams.collect { case p: CustomCommitmentsPlugin => p.getIncomingHtlcs(nodeParams, log) }.flatten - val htlcsIn: Seq[IncomingHtlc] = getIncomingHtlcs(channels, nodeParams.db.payments, nodeParams.privateKey, nodeParams.features) ++ nonStandardIncomingHtlcs + val htlcsIn: Seq[IncomingHtlc] = getIncomingHtlcs(channels.map(_.channelData), nodeParams.db.payments, nodeParams.privateKey, nodeParams.features) ++ nonStandardIncomingHtlcs val nonStandardRelayedOutHtlcs: Map[Origin.Cold, Set[(ByteVector32, Long)]] = nodeParams.pluginParams.collect { case p: CustomCommitmentsPlugin => p.getHtlcsRelayedOut(htlcsIn, nodeParams, log) }.flatten.toMap - val relayedOut: Map[Origin.Cold, Set[(ByteVector32, Long)]] = getHtlcsRelayedOut(nodeParams, channels, htlcsIn) ++ nonStandardRelayedOutHtlcs + val relayedOut: Map[Origin.Cold, Set[(ByteVector32, Long)]] = getHtlcsRelayedOut(channels, htlcsIn) ++ nonStandardRelayedOutHtlcs val settledHtlcs: Set[(ByteVector32, Long)] = nodeParams.db.pendingCommands.listSettlementCommands().map { case (channelId, cmd) => (channelId, cmd.id) }.toSet val notRelayed = htlcsIn.filterNot(htlcIn => { @@ -310,7 +310,7 @@ object PostRestartHtlcCleaner { def props(nodeParams: NodeParams, register: ActorRef, initialized: Option[Promise[Done]] = None): Props = Props(new PostRestartHtlcCleaner(nodeParams, register, initialized)) - case class Init(channels: Seq[PersistentChannelData]) + case class Init(channels: Seq[PersistentChannelDataWithKeys]) case object GetBrokenHtlcs @@ -405,10 +405,9 @@ object PostRestartHtlcCleaner { .toMap /** @return pending outgoing HTLCs, grouped by their upstream origin. */ - private def getHtlcsRelayedOut(nodeParams: NodeParams, channels: Seq[PersistentChannelData], htlcsIn: Seq[IncomingHtlc])(implicit log: LoggingAdapter): Map[Origin.Cold, Set[(ByteVector32, Long)]] = { + private def getHtlcsRelayedOut(channels: Seq[PersistentChannelDataWithKeys], htlcsIn: Seq[IncomingHtlc])(implicit log: LoggingAdapter): Map[Origin.Cold, Set[(ByteVector32, Long)]] = { val htlcsOut = channels - .collect { case c: ChannelDataWithCommitments => c } - .flatMap { c => + .collect { case PersistentChannelDataWithKeys(c: ChannelDataWithCommitments, channelKeys) => // Filter out HTLCs that will never reach the blockchain or have already been settled on-chain. val htlcsToIgnore: Set[Long] = c match { case d: DATA_CLOSING => @@ -429,7 +428,6 @@ object PostRestartHtlcCleaner { case Some(_: Closing.MutualClose) => Set.empty case None => Set.empty } - val channelKeys = nodeParams.channelKeyManager.channelKeys(d.commitments.channelParams.channelConfig, d.commitments.localChannelParams.fundingKeyPath) val timedOutHtlcs: Set[Long] = (closingType_opt match { case Some(c: Closing.LocalClose) => confirmedTxs.flatMap(tx => Closing.trimmedOrTimedOutHtlcs(channelKeys, d.commitments.latest, c.localCommit, tx)) case Some(c: Closing.RemoteClose) => confirmedTxs.flatMap(tx => Closing.trimmedOrTimedOutHtlcs(channelKeys, d.commitments.latest, c.remoteCommit, tx)) @@ -444,7 +442,7 @@ object PostRestartHtlcCleaner { c.commitments.originChannels.collect { case (outgoingHtlcId, origin: Origin.Cold) if !htlcsToIgnore.contains(outgoingHtlcId) => (origin, c.channelId, outgoingHtlcId) } - } + }.flatten groupByOrigin(htlcsOut, htlcsIn) } @@ -454,8 +452,8 @@ object PostRestartHtlcCleaner { * and before it has effectively been removed. Such closed channels will automatically be removed once the channel is * restored. */ - private def listLocalChannels(channels: Seq[PersistentChannelData]): Seq[PersistentChannelData] = - channels.filterNot(c => Closing.isClosed(c, None).isDefined) + private def listLocalChannels(channels: Seq[PersistentChannelDataWithKeys]): Seq[PersistentChannelDataWithKeys] = + channels.filterNot(c => Closing.isClosed(c.channelData, None).isDefined) /** * We store [[CMD_FULFILL_HTLC]]/[[CMD_FAIL_HTLC]]/[[CMD_FAIL_MALFORMED_HTLC]] in a database diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/integration/basic/fixtures/MinimalNodeFixture.scala b/eclair-core/src/test/scala/fr/acinq/eclair/integration/basic/fixtures/MinimalNodeFixture.scala index 5a93b17dbc..18c6242efb 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/integration/basic/fixtures/MinimalNodeFixture.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/integration/basic/fixtures/MinimalNodeFixture.scala @@ -107,7 +107,7 @@ object MinimalNodeFixture extends Assertions with Eventually with IntegrationPat val switchboard = system.actorOf(Switchboard.props(nodeParams, peerFactory), "switchboard") val paymentFactory = PaymentInitiator.SimplePaymentFactory(nodeParams, router, register) val paymentInitiator = system.actorOf(PaymentInitiator.props(nodeParams, paymentFactory), "payment-initiator") - val channels = nodeParams.db.channels.listLocalChannels() + val channels = nodeParams.db.channels.listLocalChannels().map(_.withChannelKeys(nodeParams)) val postman = system.spawn(Behaviors.supervise(Postman(nodeParams, switchboard, router.toTyped, register, offerManager)).onFailure(typed.SupervisorStrategy.restart), name = "postman") switchboard ! Switchboard.Init(channels) relayer ! PostRestartHtlcCleaner.Init(channels) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/io/PeerSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/io/PeerSpec.scala index ff3d2f2172..02d80379cc 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/io/PeerSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/io/PeerSpec.scala @@ -113,7 +113,7 @@ class PeerSpec extends FixtureSpec { def cleanupFixture(fixture: FixtureParam): Unit = fixture.cleanup() - def connect(remoteNodeId: PublicKey, peer: TestFSMRef[Peer.State, Peer.Data, Peer], peerConnection: TestProbe, switchboard: TestProbe, channels: Set[PersistentChannelData] = Set.empty, remoteInit: protocol.Init = protocol.Init(Bob.nodeParams.features.initFeatures()), initializePeer: Boolean = true, peerStorage: Option[ByteVector] = None)(implicit system: ActorSystem): Unit = { + def connect(remoteNodeId: PublicKey, peer: TestFSMRef[Peer.State, Peer.Data, Peer], peerConnection: TestProbe, switchboard: TestProbe, channels: Set[PersistentChannelDataWithKeys] = Set.empty, remoteInit: protocol.Init = protocol.Init(Bob.nodeParams.features.initFeatures()), initializePeer: Boolean = true, peerStorage: Option[ByteVector] = None)(implicit system: ActorSystem): Unit = { // let's simulate a connection if (initializePeer) { switchboard.send(peer, Peer.Init(channels, Map.empty)) @@ -134,7 +134,7 @@ class PeerSpec extends FixtureSpec { import f._ val probe = TestProbe() system.eventStream.subscribe(probe.ref, classOf[PeerCreated]) - connect(remoteNodeId, peer, peerConnection, switchboard, channels = Set(ChannelCodecsSpec.normal)) + connect(remoteNodeId, peer, peerConnection, switchboard, channels = Set(ChannelCodecsSpec.normal.withChannelKeys(nodeParams))) probe.expectMsg(PeerCreated(peer.ref, remoteNodeId)) probe.send(peer, Peer.GetPeerInfo(None)) val peerInfo = probe.expectMsgType[PeerInfo] @@ -216,7 +216,7 @@ class PeerSpec extends FixtureSpec { nodeParams.db.network.addNode(ann) val probe = TestProbe() - probe.send(peer, Peer.Init(Set(ChannelCodecsSpec.normal), Map.empty)) + probe.send(peer, Peer.Init(Set(ChannelCodecsSpec.normal.withChannelKeys(nodeParams)), Map.empty)) // assert our mock server got an incoming connection (the client was spawned with the address from node_announcement) eventually { @@ -236,7 +236,7 @@ class PeerSpec extends FixtureSpec { val probe = TestProbe() val localInit = protocol.Init(peer.underlyingActor.nodeParams.features.initFeatures()) val remoteInit = protocol.Init(peer.underlyingActor.nodeParams.features.initFeatures().add(Features.WakeUpNotificationClient, FeatureSupport.Optional)) - val mobileWalletChannel = ChannelCodecsSpec.normal.copy(commitments = ChannelCodecsSpec.normal.commitments.updateInitFeatures(localInit, remoteInit)) + val mobileWalletChannel = ChannelCodecsSpec.normal.copy(commitments = ChannelCodecsSpec.normal.commitments.updateInitFeatures(localInit, remoteInit)).withChannelKeys(nodeParams) probe.send(peer, Peer.Init(Set(mobileWalletChannel), Map.empty)) // the reconnection task will stay in the idle state monitor.expectNoMessage(100 millis) @@ -246,7 +246,7 @@ class PeerSpec extends FixtureSpec { import f._ val probe = TestProbe() - connect(remoteNodeId, peer, peerConnection, switchboard, channels = Set(ChannelCodecsSpec.normal)) + connect(remoteNodeId, peer, peerConnection, switchboard, channels = Set(ChannelCodecsSpec.normal.withChannelKeys(nodeParams))) probe.send(peer, Peer.Connect(remoteNodeId, None, probe.ref, isPersistent = true)) probe.expectMsgType[PeerConnection.ConnectionResult.AlreadyConnected] @@ -257,7 +257,7 @@ class PeerSpec extends FixtureSpec { val listener = TestProbe() system.eventStream.subscribe(listener.ref, classOf[UnknownMessageReceived]) - connect(remoteNodeId, peer, peerConnection, switchboard, channels = Set(ChannelCodecsSpec.normal)) + connect(remoteNodeId, peer, peerConnection, switchboard, channels = Set(ChannelCodecsSpec.normal.withChannelKeys(nodeParams))) peerConnection.send(peer, UnknownMessage(tag = TestConstants.pluginParams.messageTags.head, data = ByteVector.empty)) listener.expectMsgType[UnknownMessageReceived] @@ -269,7 +269,7 @@ class PeerSpec extends FixtureSpec { import f._ val probe = TestProbe() - connect(remoteNodeId, peer, peerConnection, switchboard, channels = Set(ChannelCodecsSpec.normal)) + connect(remoteNodeId, peer, peerConnection, switchboard, channels = Set(ChannelCodecsSpec.normal.withChannelKeys(nodeParams))) probe.send(peer, Peer.GetPeerInfo(Some(probe.ref.toTyped))) assert(probe.expectMsgType[Peer.PeerInfo].state == Peer.CONNECTED) @@ -300,7 +300,7 @@ class PeerSpec extends FixtureSpec { val peerConnection2 = TestProbe() val peerConnection3 = TestProbe() - connect(remoteNodeId, peer, peerConnection, switchboard, channels = Set(ChannelCodecsSpec.normal)) + connect(remoteNodeId, peer, peerConnection, switchboard, channels = Set(ChannelCodecsSpec.normal.withChannelKeys(nodeParams))) channel.expectMsg(INPUT_RESTORED(ChannelCodecsSpec.normal)) val (localInit, remoteInit) = { val inputReconnected = channel.expectMsgType[INPUT_RECONNECTED] @@ -339,7 +339,7 @@ class PeerSpec extends FixtureSpec { monitor.expectMsg(FSM.CurrentState(reconnectionTask, ReconnectionTask.IDLE)) val probe = TestProbe() - probe.send(peer, Peer.Init(Set(ChannelCodecsSpec.normal), Map.empty)) + probe.send(peer, Peer.Init(Set(ChannelCodecsSpec.normal.withChannelKeys(nodeParams)), Map.empty)) // the reconnection task will wait a little... monitor.expectMsg(FSM.Transition(reconnectionTask, ReconnectionTask.IDLE, ReconnectionTask.WAITING)) @@ -357,7 +357,7 @@ class PeerSpec extends FixtureSpec { test("send recommended feerates when feerate changes") { f => import f._ - connect(remoteNodeId, peer, peerConnection, switchboard, channels = Set(ChannelCodecsSpec.normal)) + connect(remoteNodeId, peer, peerConnection, switchboard, channels = Set(ChannelCodecsSpec.normal.withChannelKeys(nodeParams))) // We regularly update our internal feerates. val bitcoinCoreFeerates = FeeratesPerKw(FeeratePerKw(253 sat), FeeratePerKw(400 sat), FeeratePerKw(500 sat), FeeratePerKw(1000 sat), FeeratePerKw(1500 sat)) @@ -648,7 +648,7 @@ class PeerSpec extends FixtureSpec { test("handle final channelId assigned in state DISCONNECTED") { f => import f._ val probe = TestProbe() - connect(remoteNodeId, peer, peerConnection, switchboard, channels = Set(ChannelCodecsSpec.normal)) + connect(remoteNodeId, peer, peerConnection, switchboard, channels = Set(ChannelCodecsSpec.normal.withChannelKeys(nodeParams))) peer ! ConnectionDown(peerConnection.ref) probe.send(peer, Peer.GetPeerInfo(Some(probe.ref.toTyped))) val peerInfo1 = probe.expectMsgType[Peer.PeerInfo] @@ -665,7 +665,7 @@ class PeerSpec extends FixtureSpec { import f._ val probe = TestProbe() system.eventStream.subscribe(probe.ref, classOf[LastChannelClosed]) - connect(remoteNodeId, peer, peerConnection, switchboard, channels = Set(ChannelCodecsSpec.normal)) + connect(remoteNodeId, peer, peerConnection, switchboard, channels = Set(ChannelCodecsSpec.normal.withChannelKeys(nodeParams))) probe.send(channel.ref, PoisonPill) probe.expectMsg(LastChannelClosed(peer, remoteNodeId)) } @@ -674,7 +674,7 @@ class PeerSpec extends FixtureSpec { import f._ val probe = TestProbe() system.eventStream.subscribe(probe.ref, classOf[LastChannelClosed]) - connect(remoteNodeId, peer, peerConnection, switchboard, channels = Set(ChannelCodecsSpec.normal)) + connect(remoteNodeId, peer, peerConnection, switchboard, channels = Set(ChannelCodecsSpec.normal.withChannelKeys(nodeParams))) peer ! ConnectionDown(peerConnection.ref) probe.send(channel.ref, PoisonPill) probe.expectMsg(LastChannelClosed(peer, remoteNodeId)) @@ -682,7 +682,7 @@ class PeerSpec extends FixtureSpec { test("reply to relay request") { f => import f._ - connect(remoteNodeId, peer, peerConnection, switchboard, channels = Set(ChannelCodecsSpec.normal)) + connect(remoteNodeId, peer, peerConnection, switchboard, channels = Set(ChannelCodecsSpec.normal.withChannelKeys(nodeParams))) val Right(msg) = buildMessage(randomKey(), randomKey(), Nil, Recipient(remoteNodeId, None), TlvStream.empty) val messageId = randomBytes32() val probe = TestProbe() @@ -703,7 +703,7 @@ class PeerSpec extends FixtureSpec { import f._ val probe = TestProbe() val unknownMessage = UnknownMessage(60003, ByteVector32.One) - connect(remoteNodeId, peer, peerConnection, switchboard, channels = Set(ChannelCodecsSpec.normal)) + connect(remoteNodeId, peer, peerConnection, switchboard, channels = Set(ChannelCodecsSpec.normal.withChannelKeys(nodeParams))) probe.send(peer, Peer.RelayUnknownMessage(unknownMessage)) peerConnection.expectMsgType[UnknownMessage] } @@ -777,19 +777,19 @@ class PeerSpec extends FixtureSpec { val channel = ChannelCodecsSpec.normal val peerConnection1 = peerConnection nodeParams.db.peers.updateStorage(remoteNodeId, hex"abcdef") - connect(remoteNodeId, peer, peerConnection1, switchboard, channels = Set(channel), peerStorage = Some(hex"abcdef")) + connect(remoteNodeId, peer, peerConnection1, switchboard, channels = Set(channel.withChannelKeys(nodeParams)), peerStorage = Some(hex"abcdef")) peer ! ChannelReadyForPayments(ActorRef.noSender, channel.remoteNodeId, channel.channelId, channel.commitments.latest.fundingTxId, channel.commitments.latest.fundingTxIndex) peerConnection1.send(peer, PeerStorageStore(hex"deadbeef")) peerConnection1.send(peer, PeerStorageStore(hex"0123456789")) // We disconnect and reconnect, sending the last backup we received. val peerConnection2 = TestProbe() - connect(remoteNodeId, peer, peerConnection2, switchboard, channels = Set(ChannelCodecsSpec.normal), initializePeer = false, peerStorage = Some(hex"0123456789")) + connect(remoteNodeId, peer, peerConnection2, switchboard, channels = Set(ChannelCodecsSpec.normal.withChannelKeys(nodeParams)), initializePeer = false, peerStorage = Some(hex"0123456789")) peerConnection2.send(peer, PeerStorageStore(hex"1111")) // We reconnect again. val peerConnection3 = TestProbe() - connect(remoteNodeId, peer, peerConnection3, switchboard, channels = Set(ChannelCodecsSpec.normal), initializePeer = false, peerStorage = Some(hex"1111")) + connect(remoteNodeId, peer, peerConnection3, switchboard, channels = Set(ChannelCodecsSpec.normal.withChannelKeys(nodeParams)), initializePeer = false, peerStorage = Some(hex"1111")) // Because of the delayed writes, we may not have stored the latest value immediately, but we will eventually store it. eventually { assert(nodeParams.db.peers.getStorage(remoteNodeId).contains(hex"1111")) @@ -892,7 +892,7 @@ class PeerSpec extends FixtureSpec { nodeParams.db.peers.addOrUpdatePeerFeatures(remoteNodeId, nodeInfo.features) // We initialize ourselves after a restart, but our peer doesn't reconnect immediately to us. - switchboard.send(peer, Peer.Init(Set(ChannelCodecsSpec.normal), Map.empty)) + switchboard.send(peer, Peer.Init(Set(ChannelCodecsSpec.normal.withChannelKeys(nodeParams)), Map.empty)) // When we request information about the peer, we will fetch it from the DB. val probe = TestProbe() probe.send(peer, Peer.GetPeerInfo(Some(probe.ref.toTyped))) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/io/SwitchboardSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/io/SwitchboardSpec.scala index ab4bdca2ab..d44a64ad6f 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/io/SwitchboardSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/io/SwitchboardSpec.scala @@ -7,7 +7,7 @@ import com.softwaremill.quicklens.ModifyPimp import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey import fr.acinq.bitcoin.scalacompat.{ByteVector64, Satoshi} import fr.acinq.eclair.TestConstants._ -import fr.acinq.eclair.channel.{ChannelIdAssigned, DATA_NORMAL, PersistentChannelData, Upstream} +import fr.acinq.eclair.channel.{ChannelIdAssigned, DATA_NORMAL, PersistentChannelDataWithKeys, Upstream} import fr.acinq.eclair.io.Peer.PeerNotFound import fr.acinq.eclair.io.Switchboard._ import fr.acinq.eclair.payment.relay.{OnTheFlyFunding, OnTheFlyFundingSpec} @@ -31,16 +31,16 @@ class SwitchboardSpec extends TestKitBaseClass with AnyFunSuiteLike { // If we have a channel with that remote peer, we will automatically reconnect. val switchboard = TestActorRef(new Switchboard(nodeParams, FakePeerFactory(probe, peer))) - switchboard ! Switchboard.Init(List(ChannelCodecsSpec.normal)) + switchboard ! Switchboard.Init(List(ChannelCodecsSpec.normal.withChannelKeys(nodeParams))) probe.expectMsg(remoteNodeId) - peer.expectMsg(Peer.Init(Set(ChannelCodecsSpec.normal), Map.empty)) + peer.expectMsg(Peer.Init(Set(ChannelCodecsSpec.normal.withChannelKeys(nodeParams)), Map.empty)) } test("on initialization create peers with pending on-the-fly funding proposals") { val nodeParams = Alice.nodeParams // We have a channel with one of our peer, and a pending on-the-fly funding with them as well. - val channel = ChannelCodecsSpec.normal + val channel = ChannelCodecsSpec.normal.withChannelKeys(nodeParams) val remoteNodeId1 = channel.remoteNodeId val paymentHash1 = randomBytes32() val pendingOnTheFly1 = OnTheFlyFunding.Pending( @@ -105,7 +105,7 @@ class SwitchboardSpec extends TestKitBaseClass with AnyFunSuiteLike { peer.expectMsg(Peer.Disconnect(remoteNodeId)) } - def sendFeatures(nodeParams: NodeParams, channels: Seq[PersistentChannelData], remoteNodeId: PublicKey, expectedFeatures: Features[InitFeature], expectedSync: Boolean): Unit = { + def sendFeatures(nodeParams: NodeParams, channels: Seq[PersistentChannelDataWithKeys], remoteNodeId: PublicKey, expectedFeatures: Features[InitFeature], expectedSync: Boolean): Unit = { val (probe, peer, peerConnection) = (TestProbe(), TestProbe(), TestProbe()) val switchboard = TestActorRef(new Switchboard(nodeParams, FakePeerFactory(probe, peer))) switchboard ! Switchboard.Init(channels) @@ -119,7 +119,7 @@ class SwitchboardSpec extends TestKitBaseClass with AnyFunSuiteLike { test("sync if no whitelist is defined and peer has channels") { val nodeParams = Alice.nodeParams.modify(_.routerConf.syncConf.whitelist).setTo(Set.empty) val remoteNodeId = ChannelCodecsSpec.normal.commitments.remoteNodeId - sendFeatures(nodeParams, List(ChannelCodecsSpec.normal), remoteNodeId, nodeParams.features.initFeatures(), expectedSync = true) + sendFeatures(nodeParams, List(ChannelCodecsSpec.normal.withChannelKeys(nodeParams)), remoteNodeId, nodeParams.features.initFeatures(), expectedSync = true) } test("sync if no whitelist is defined and peer creates a channel") { @@ -160,7 +160,7 @@ class SwitchboardSpec extends TestKitBaseClass with AnyFunSuiteLike { test("don't sync if whitelist doesn't contain peer") { val nodeParams = Alice.nodeParams.modify(_.routerConf.syncConf.whitelist).setTo(Set(randomKey().publicKey, randomKey().publicKey, randomKey().publicKey)).modify(_.routerConf.syncConf.peerLimit).setTo(0) val remoteNodeId = ChannelCodecsSpec.normal.commitments.remoteNodeId - sendFeatures(nodeParams, List(ChannelCodecsSpec.normal), remoteNodeId, nodeParams.features.initFeatures(), expectedSync = false) + sendFeatures(nodeParams, List(ChannelCodecsSpec.normal.withChannelKeys(nodeParams)), remoteNodeId, nodeParams.features.initFeatures(), expectedSync = false) } def dummyDataNormal(remoteNodeId: PublicKey, capacity: Satoshi): DATA_NORMAL = { @@ -182,7 +182,7 @@ class SwitchboardSpec extends TestKitBaseClass with AnyFunSuiteLike { dummyDataNormal(alice, Satoshi(600)), dummyDataNormal(bob, Satoshi(1000)), dummyDataNormal(carol, Satoshi(2000)), - )) + ).map(_.withChannelKeys(nodeParams))) switchboard ! PeerConnection.Authenticated(peerConnection.ref, alice, outgoing = true) assert(peerConnection.expectMsgType[PeerConnection.InitializeConnection].doSync) @@ -207,7 +207,7 @@ class SwitchboardSpec extends TestKitBaseClass with AnyFunSuiteLike { dummyDataNormal(alice, Satoshi(600)), dummyDataNormal(bob, Satoshi(1000)), dummyDataNormal(carol, Satoshi(2000)), - )) + ).map(_.withChannelKeys(nodeParams))) switchboard ! PeerConnection.Authenticated(peerConnection.ref, alice, outgoing = true) assert(!peerConnection.expectMsgType[PeerConnection.InitializeConnection].doSync) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/payment/PostRestartHtlcCleanerSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/payment/PostRestartHtlcCleanerSpec.scala index 5c630d6e68..b346bccad1 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/payment/PostRestartHtlcCleanerSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/payment/PostRestartHtlcCleanerSpec.scala @@ -116,11 +116,11 @@ class PostRestartHtlcCleanerSpec extends TestKitBaseClass with FixtureAnyFunSuit val channel = TestProbe() val (relayer, _) = f.createRelayer(nodeParams) - relayer ! PostRestartHtlcCleaner.Init(channels) + relayer ! PostRestartHtlcCleaner.Init(channels.map(_.withChannelKeys(nodeParams))) register.expectNoMessage(100 millis) // nothing should happen while channels are still offline. // channel 1 goes to NORMAL state: - system.eventStream.publish(ChannelStateChanged(channel.ref, channels.head.commitments.channelId, system.deadLetters, a, OFFLINE, NORMAL, Some(channels.head.commitments))) + system.eventStream.publish(ChannelStateChanged(channel.ref, channels.head.channelId, system.deadLetters, a, OFFLINE, NORMAL, Some(channels.head.commitments))) channel.expectMsgAllOf( CMD_FAIL_HTLC(1, FailureReason.LocalFailure(TemporaryNodeFailure()), None, commit = true), CMD_FAIL_MALFORMED_HTLC(4, ByteVector32.Zeroes, FailureMessageCodecs.BADONION | FailureMessageCodecs.PERM | 24, commit = true) @@ -128,7 +128,7 @@ class PostRestartHtlcCleanerSpec extends TestKitBaseClass with FixtureAnyFunSuit channel.expectNoMessage(100 millis) // channel 2 goes to NORMAL state: - system.eventStream.publish(ChannelStateChanged(channel.ref, channels(1).commitments.channelId, system.deadLetters, a, OFFLINE, NORMAL, Some(channels(1).commitments))) + system.eventStream.publish(ChannelStateChanged(channel.ref, channels(1).channelId, system.deadLetters, a, OFFLINE, NORMAL, Some(channels(1).commitments))) channel.expectMsgAllOf( CMD_FAIL_HTLC(0, FailureReason.LocalFailure(TemporaryNodeFailure()), None, commit = true), CMD_FAIL_HTLC(4, FailureReason.LocalFailure(TemporaryNodeFailure()), None, commit = true) @@ -182,11 +182,11 @@ class PostRestartHtlcCleanerSpec extends TestKitBaseClass with FixtureAnyFunSuit val channel = TestProbe() val (relayer, _) = f.createRelayer(nodeParams) - relayer ! PostRestartHtlcCleaner.Init(channels) + relayer ! PostRestartHtlcCleaner.Init(channels.map(_.withChannelKeys(nodeParams))) // Upstream channels go back to the NORMAL state, but HTLCs are kept because the on-the-fly proposal was funded. - system.eventStream.publish(ChannelStateChanged(channel.ref, channels.head.commitments.channelId, system.deadLetters, a, OFFLINE, NORMAL, Some(channels(0).commitments))) + system.eventStream.publish(ChannelStateChanged(channel.ref, channels.head.channelId, system.deadLetters, a, OFFLINE, NORMAL, Some(channels(0).commitments))) channel.expectNoMessage(100 millis) - system.eventStream.publish(ChannelStateChanged(channel.ref, channels(1).commitments.channelId, system.deadLetters, a, OFFLINE, NORMAL, Some(channels(1).commitments))) + system.eventStream.publish(ChannelStateChanged(channel.ref, channels(1).channelId, system.deadLetters, a, OFFLINE, NORMAL, Some(channels(1).commitments))) channel.expectNoMessage(100 millis) } @@ -219,7 +219,7 @@ class PostRestartHtlcCleanerSpec extends TestKitBaseClass with FixtureAnyFunSuit val channel = TestProbe() val (relayer, _) = f.createRelayer(nodeParams) - relayer ! PostRestartHtlcCleaner.Init(channels) + relayer ! PostRestartHtlcCleaner.Init(channels.map(_.withChannelKeys(nodeParams))) register.expectNoMessage(100 millis) // nothing should happen while channels are still offline. // channel 1 goes to NORMAL state: @@ -267,7 +267,7 @@ class PostRestartHtlcCleanerSpec extends TestKitBaseClass with FixtureAnyFunSuit val testCase = setupLocalPayments(nodeParams) val (relayer, _) = createRelayer(nodeParams) - relayer ! PostRestartHtlcCleaner.Init(List(testCase.channel)) + relayer ! PostRestartHtlcCleaner.Init(List(testCase.channel.withChannelKeys(nodeParams))) register.expectNoMessage(100 millis) sender.send(relayer, testCase.fails(1)) @@ -297,7 +297,7 @@ class PostRestartHtlcCleanerSpec extends TestKitBaseClass with FixtureAnyFunSuit val testCase = setupLocalPayments(nodeParams) val (relayer, _) = f.createRelayer(nodeParams) - relayer ! PostRestartHtlcCleaner.Init(List(testCase.channel)) + relayer ! PostRestartHtlcCleaner.Init(List(testCase.channel.withChannelKeys(nodeParams))) register.expectNoMessage(100 millis) sender.send(relayer, testCase.fulfills(1)) @@ -335,7 +335,7 @@ class PostRestartHtlcCleanerSpec extends TestKitBaseClass with FixtureAnyFunSuit val testCase = setupTrampolinePayments() val initialized = Promise[Done]() val postRestart = system.actorOf(PostRestartHtlcCleaner.props(nodeParams, register.ref, Some(initialized))) - postRestart ! PostRestartHtlcCleaner.Init(testCase.channels) + postRestart ! PostRestartHtlcCleaner.Init(testCase.channels.map(_.withChannelKeys(nodeParams))) awaitCond(initialized.isCompleted) register.expectNoMessage(100 millis) @@ -438,7 +438,7 @@ class PostRestartHtlcCleanerSpec extends TestKitBaseClass with FixtureAnyFunSuit val channels = stored(data_upstream_1, data_upstream_2, data_upstream_3, data_downstream) val (relayer, _) = f.createRelayer(nodeParams) - relayer ! PostRestartHtlcCleaner.Init(channels) + relayer ! PostRestartHtlcCleaner.Init(channels.map(_.withChannelKeys(nodeParams))) register.expectNoMessage(100 millis) // nothing should happen while channels are still offline. val (channel_upstream_1, channel_upstream_2, channel_upstream_3) = (TestProbe(), TestProbe(), TestProbe()) @@ -478,7 +478,7 @@ class PostRestartHtlcCleanerSpec extends TestKitBaseClass with FixtureAnyFunSuit nodeParams.db.pendingCommands.addSettlementCommand(channelId_ab_1, CMD_FAIL_HTLC(4, FailureReason.LocalFailure(PermanentChannelFailure()), None)) val (_, postRestart) = f.createRelayer(nodeParams) - postRestart ! PostRestartHtlcCleaner.Init(List(channelData)) + postRestart ! PostRestartHtlcCleaner.Init(List(channelData.withChannelKeys(nodeParams))) sender.send(postRestart, PostRestartHtlcCleaner.GetBrokenHtlcs) val brokenHtlcs = sender.expectMsgType[PostRestartHtlcCleaner.BrokenHtlcs] assert(brokenHtlcs.relayedOut.isEmpty) @@ -520,7 +520,7 @@ class PostRestartHtlcCleanerSpec extends TestKitBaseClass with FixtureAnyFunSuit assert(Closing.isClosed(downstreamChannel, None).isEmpty) val (_, postRestart) = f.createRelayer(nodeParams) - postRestart ! PostRestartHtlcCleaner.Init(channels) + postRestart ! PostRestartHtlcCleaner.Init(channels.map(_.withChannelKeys(nodeParams))) sender.send(postRestart, PostRestartHtlcCleaner.GetBrokenHtlcs) val brokenHtlcs = sender.expectMsgType[PostRestartHtlcCleaner.BrokenHtlcs] assert(brokenHtlcs.relayedOut.isEmpty) @@ -532,7 +532,7 @@ class PostRestartHtlcCleanerSpec extends TestKitBaseClass with FixtureAnyFunSuit val testCase = setupChannelRelayedPayments() val (relayer, _) = f.createRelayer(nodeParams) - relayer ! PostRestartHtlcCleaner.Init(testCase.channels) + relayer ! PostRestartHtlcCleaner.Init(testCase.channels.map(_.withChannelKeys(nodeParams))) register.expectNoMessage(100 millis) sender.send(relayer, buildForwardFail(testCase.downstream, testCase.upstream)) @@ -554,7 +554,7 @@ class PostRestartHtlcCleanerSpec extends TestKitBaseClass with FixtureAnyFunSuit val channels = List(data_ab, data_bc) val (relayer, _) = f.createRelayer(nodeParams) - relayer ! PostRestartHtlcCleaner.Init(channels) + relayer ! PostRestartHtlcCleaner.Init(channels.map(_.withChannelKeys(nodeParams))) register.expectNoMessage(100 millis) sender.send(relayer, buildForwardFail(htlc_bc.add, upstream)) @@ -567,7 +567,7 @@ class PostRestartHtlcCleanerSpec extends TestKitBaseClass with FixtureAnyFunSuit val testCase = setupChannelRelayedPayments() val (relayer, _) = f.createRelayer(nodeParams) - relayer ! PostRestartHtlcCleaner.Init(testCase.channels) + relayer ! PostRestartHtlcCleaner.Init(testCase.channels.map(_.withChannelKeys(nodeParams))) register.expectNoMessage(100 millis) sender.send(relayer, buildForwardFulfill(testCase.downstream, testCase.upstream, preimage1)) @@ -584,7 +584,7 @@ class PostRestartHtlcCleanerSpec extends TestKitBaseClass with FixtureAnyFunSuit val testCase = setupTrampolinePayments() val (relayer, _) = f.createRelayer(nodeParams) - relayer ! PostRestartHtlcCleaner.Init(testCase.channels) + relayer ! PostRestartHtlcCleaner.Init(testCase.channels.map(_.withChannelKeys(nodeParams))) register.expectNoMessage(100 millis) // This downstream HTLC has two upstream HTLCs. @@ -615,7 +615,7 @@ class PostRestartHtlcCleanerSpec extends TestKitBaseClass with FixtureAnyFunSuit val testCase = setupTrampolinePayments() val (relayer, _) = f.createRelayer(nodeParams) - relayer ! PostRestartHtlcCleaner.Init(testCase.channels) + relayer ! PostRestartHtlcCleaner.Init(testCase.channels.map(_.withChannelKeys(nodeParams))) register.expectNoMessage(100 millis) // This downstream HTLC has two upstream HTLCs. @@ -645,7 +645,7 @@ class PostRestartHtlcCleanerSpec extends TestKitBaseClass with FixtureAnyFunSuit val testCase = setupTrampolinePayments() val (relayer, _) = f.createRelayer(nodeParams) - relayer ! PostRestartHtlcCleaner.Init(testCase.channels) + relayer ! PostRestartHtlcCleaner.Init(testCase.channels.map(_.withChannelKeys(nodeParams))) register.expectNoMessage(100 millis) sender.send(relayer, buildForwardFail(testCase.downstream_2_1, testCase.upstream_2)) @@ -683,7 +683,7 @@ class PostRestartHtlcCleanerSpec extends TestKitBaseClass with FixtureAnyFunSuit val data_bc = ChannelCodecsSpec.makeChannelDataNormal(htlc_bc, Map(1L -> Origin.Cold(upstreamChannel), 2L -> Origin.Cold(upstreamTrampoline))) val (relayer, _) = f.createRelayer(nodeParams) - relayer ! PostRestartHtlcCleaner.Init(Seq(data_ab, data_bc)) + relayer ! PostRestartHtlcCleaner.Init(Seq(data_ab, data_bc).map(_.withChannelKeys(nodeParams))) // HTLC failures are not relayed upstream, as we will retry until we reach the HTLC timeout. sender.send(relayer, buildForwardFail(htlc_bc(0).add, Upstream.Cold.Channel(htlc_ab(0).add, a))) @@ -729,7 +729,7 @@ class PostRestartHtlcCleanerSpec extends TestKitBaseClass with FixtureAnyFunSuit val channel = TestProbe() val (relayer, _) = f.createRelayer(nodeParams1) - relayer ! PostRestartHtlcCleaner.Init(List(c)) + relayer ! PostRestartHtlcCleaner.Init(List(c).map(_.withChannelKeys(nodeParams))) register.expectNoMessage(100 millis) // nothing should happen while channels are still offline. // Standard channel goes to NORMAL state: