What changed, and why it matters
This commit is a performance optimization, not a security fix. It changes Eclair so that cryptographic channel keys are computed once when channels are loaded from the database at startup, then passed around with the channel data, instead of being recomputed every time they are needed. This reduces CPU work when many channels are active. There is no indication in the commit that it fixes a vulnerability or changes security behavior.
No security action required. Treat as routine performance refactor. Reviewers may optionally verify that channel key validation still occurs exactly once per channel at startup and that no code path bypasses validateSeed().
Security signals we found
No security-relevant behavioral change identified
Refactor moves key computation earlier in lifecycle
Seed validation logic preserved
No new input surface or trust boundary introduced
No mention of vulnerability, CVE, bug bounty, or security issue in commit message
Evidence from the diff
The refactor introduces PersistentChannelDataWithKeys, a wrapper that pairs PersistentChannelData with its ChannelKeys. DBChecker now computes keys once per channel via withChannelKeys(nodeParams) and validates the seed. Peer, Switchboard, PostRestartHtlcCleaner, and Setup are updated to carry PersistentChannelDataWithKeys and access .channelData or .channelKeys as needed. PostRestartHtlcCleaner no longer recomputes channelKeys inside getHtlcsRelayedOut; it uses the precomputed keys from the wrapper. The change is purely structural/performance-oriented.
Changed components
eclair-core DBCheckereclair-core Setupeclair-core channel ChannelDataeclair-core io Peereclair-core io Switchboardeclair-core payment relay PostRestartHtlcCleanerInspect captured patch +96 / −85
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 bacd948..59c3433 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 c21f718..b5440fc 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 548ae94..49b33b2 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 63b373f..d37e1c0 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 c455056..85f87af 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 9236f04..93a4cde 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 5a93b17..18c6242 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 ff3d2f2..02d8037 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 ab4bdca..d44a64a 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 5c630d6..b346bcc 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:
Why this scored 17/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.