From 1020a0bb77f37fa77f5f71e8dad752b76968f6ac Mon Sep 17 00:00:00 2001 From: t-bast Date: Wed, 18 Jun 2025 17:05:27 +0200 Subject: [PATCH 1/4] Don't update local params in `OpenChannelInterceptor` We previously allowed plugins to update parts of our `LocalParams` in the `OpenChannelInterceptor` flow: this was an attempt to allow adding funds to a dual-funded channel that wasn't initiated by us and set `max-htlc-value-in-flight` correctly (taking into account the added funding amount). This isn't used yet, and we will compute `max-htlc-value-in-flight` later in the following commits, so we remove this option, which simplifies the code. --- .../scala/fr/acinq/eclair/PluginParams.scala | 6 ++--- .../eclair/io/OpenChannelInterceptor.scala | 25 +++---------------- .../io/OpenChannelInterceptorSpec.scala | 20 ++++++--------- 3 files changed, 13 insertions(+), 38 deletions(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/PluginParams.scala b/eclair-core/src/main/scala/fr/acinq/eclair/PluginParams.scala index 18032a6e32..ddc9705a3b 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/PluginParams.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/PluginParams.scala @@ -20,7 +20,7 @@ import akka.actor.typed.ActorRef import akka.event.LoggingAdapter import fr.acinq.bitcoin.scalacompat.{ByteVector32, Satoshi} import fr.acinq.eclair.channel.Origin -import fr.acinq.eclair.io.OpenChannelInterceptor.{DefaultParams, OpenChannelNonInitiator} +import fr.acinq.eclair.io.OpenChannelInterceptor.OpenChannelNonInitiator import fr.acinq.eclair.payment.relay.PostRestartHtlcCleaner.IncomingHtlc import fr.acinq.eclair.wire.protocol.{Error, LiquidityAds} @@ -61,13 +61,13 @@ trait CustomCommitmentsPlugin extends PluginParams { // @formatter:off trait InterceptOpenChannelCommand -case class InterceptOpenChannelReceived(replyTo: ActorRef[InterceptOpenChannelResponse], openChannelNonInitiator: OpenChannelNonInitiator, defaultParams: DefaultParams) extends InterceptOpenChannelCommand { +case class InterceptOpenChannelReceived(replyTo: ActorRef[InterceptOpenChannelResponse], openChannelNonInitiator: OpenChannelNonInitiator) extends InterceptOpenChannelCommand { val remoteFundingAmount: Satoshi = openChannelNonInitiator.open.fold(_.fundingSatoshis, _.fundingAmount) val temporaryChannelId: ByteVector32 = openChannelNonInitiator.open.fold(_.temporaryChannelId, _.temporaryChannelId) } sealed trait InterceptOpenChannelResponse -case class AcceptOpenChannel(temporaryChannelId: ByteVector32, defaultParams: DefaultParams, addFunding_opt: Option[LiquidityAds.AddFunding]) extends InterceptOpenChannelResponse +case class AcceptOpenChannel(temporaryChannelId: ByteVector32, addFunding_opt: Option[LiquidityAds.AddFunding]) extends InterceptOpenChannelResponse case class RejectOpenChannel(temporaryChannelId: ByteVector32, error: Error) extends InterceptOpenChannelResponse // @formatter:on diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/io/OpenChannelInterceptor.scala b/eclair-core/src/main/scala/fr/acinq/eclair/io/OpenChannelInterceptor.scala index 38de795c39..6743cbba69 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/io/OpenChannelInterceptor.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/io/OpenChannelInterceptor.scala @@ -31,7 +31,7 @@ import fr.acinq.eclair.io.Peer.{OpenChannelResponse, SpawnChannelNonInitiator} import fr.acinq.eclair.io.PendingChannelsRateLimiter.AddOrRejectChannel import fr.acinq.eclair.wire.protocol import fr.acinq.eclair.wire.protocol.{Error, LiquidityAds, NodeAddress} -import fr.acinq.eclair.{AcceptOpenChannel, CltvExpiryDelta, Features, InitFeature, InterceptOpenChannelPlugin, InterceptOpenChannelReceived, InterceptOpenChannelResponse, Logs, MilliSatoshi, NodeParams, RejectOpenChannel, UInt64} +import fr.acinq.eclair.{AcceptOpenChannel, Features, InitFeature, InterceptOpenChannelPlugin, InterceptOpenChannelReceived, InterceptOpenChannelResponse, Logs, NodeParams, RejectOpenChannel} import scodec.bits.ByteVector import scala.concurrent.duration.{DurationInt, FiniteDuration} @@ -70,13 +70,6 @@ object OpenChannelInterceptor { private case object PluginTimeout extends QueryPluginCommands // @formatter:on - /** DefaultParams are a subset of ChannelData.LocalParams that can be modified by an InterceptOpenChannelPlugin */ - case class DefaultParams(dustLimit: Satoshi, - maxHtlcValueInFlightMsat: UInt64, - htlcMinimum: MilliSatoshi, - toSelfDelay: CltvExpiryDelta, - maxAcceptedHtlcs: Int) - def apply(peer: ActorRef[Any], nodeParams: NodeParams, remoteNodeId: PublicKey, wallet: OnChainPubkeyCache, pendingChannelsRateLimiter: ActorRef[PendingChannelsRateLimiter.Command], pluginTimeout: FiniteDuration = 1 minute): Behavior[Command] = Behaviors.setup { context => Behaviors.withMdc(Logs.mdc(remoteNodeId_opt = Some(remoteNodeId))) { @@ -239,12 +232,10 @@ private class OpenChannelInterceptor(peer: ActorRef[Any], Behaviors.withTimers { timers => timers.startSingleTimer(PluginTimeout, pluginTimeout) val pluginResponseAdapter = context.messageAdapter[InterceptOpenChannelResponse](PluginOpenChannelResponse) - val defaultParams = DefaultParams(localParams.dustLimit, localParams.maxHtlcValueInFlightMsat, localParams.htlcMinimum, localParams.toSelfDelay, localParams.maxAcceptedHtlcs) - plugin.openChannelInterceptor ! InterceptOpenChannelReceived(pluginResponseAdapter, request, defaultParams) + plugin.openChannelInterceptor ! InterceptOpenChannelReceived(pluginResponseAdapter, request) receiveCommandMessage[QueryPluginCommands](context, "queryPlugin") { case PluginOpenChannelResponse(pluginResponse: AcceptOpenChannel) => - val localParams1 = updateLocalParams(localParams, pluginResponse.defaultParams) - peer ! SpawnChannelNonInitiator(request.open, channelConfig, channelType, pluginResponse.addFunding_opt, localParams1, request.peerConnection.toClassic) + peer ! SpawnChannelNonInitiator(request.open, channelConfig, channelType, pluginResponse.addFunding_opt, localParams, request.peerConnection.toClassic) timers.cancel(PluginTimeout) waitForRequest() case PluginOpenChannelResponse(pluginResponse: RejectOpenChannel) => @@ -328,14 +319,4 @@ private class OpenChannelInterceptor(peer: ActorRef[Any], ) } - private def updateLocalParams(localParams: LocalParams, defaultParams: DefaultParams): LocalParams = { - localParams.copy( - dustLimit = defaultParams.dustLimit, - maxHtlcValueInFlightMsat = defaultParams.maxHtlcValueInFlightMsat, - htlcMinimum = defaultParams.htlcMinimum, - toSelfDelay = defaultParams.toSelfDelay, - maxAcceptedHtlcs = defaultParams.maxAcceptedHtlcs - ) - } - } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/io/OpenChannelInterceptorSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/io/OpenChannelInterceptorSpec.scala index 66e1887b73..9b32f48dcb 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/io/OpenChannelInterceptorSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/io/OpenChannelInterceptorSpec.scala @@ -30,14 +30,14 @@ import fr.acinq.eclair.channel.ChannelTypes.UnsupportedChannelType import fr.acinq.eclair.channel._ import fr.acinq.eclair.channel.fsm.Channel import fr.acinq.eclair.channel.states.ChannelStateTestsTags -import fr.acinq.eclair.io.OpenChannelInterceptor.{DefaultParams, OpenChannelInitiator, OpenChannelNonInitiator} +import fr.acinq.eclair.io.OpenChannelInterceptor.{OpenChannelInitiator, OpenChannelNonInitiator} import fr.acinq.eclair.io.Peer.{OpenChannelResponse, OutgoingMessage, SpawnChannelInitiator, SpawnChannelNonInitiator} import fr.acinq.eclair.io.PeerSpec.{createOpenChannelMessage, createOpenDualFundedChannelMessage} import fr.acinq.eclair.io.PendingChannelsRateLimiter.AddOrRejectChannel import fr.acinq.eclair.transactions.Transactions.{ClosingTx, InputInfo} import fr.acinq.eclair.wire.internal.channel.ChannelCodecsSpec import fr.acinq.eclair.wire.protocol.{ChannelReestablish, ChannelTlv, Error, IPAddress, LiquidityAds, NodeAddress, OpenChannel, OpenChannelTlv, Shutdown, TlvStream} -import fr.acinq.eclair.{AcceptOpenChannel, BlockHeight, CltvExpiryDelta, FeatureSupport, Features, InitFeature, InterceptOpenChannelCommand, InterceptOpenChannelPlugin, InterceptOpenChannelReceived, MilliSatoshiLong, RejectOpenChannel, TestConstants, UInt64, UnknownFeature, randomBytes32, randomKey} +import fr.acinq.eclair.{AcceptOpenChannel, BlockHeight, FeatureSupport, Features, InitFeature, InterceptOpenChannelCommand, InterceptOpenChannelPlugin, InterceptOpenChannelReceived, MilliSatoshiLong, RejectOpenChannel, TestConstants, UInt64, UnknownFeature, randomBytes32, randomKey} import org.scalatest.funsuite.FixtureAnyFunSuiteLike import org.scalatest.{Outcome, Tag} import scodec.bits.ByteVector @@ -47,7 +47,6 @@ import scala.concurrent.duration.DurationInt class OpenChannelInterceptorSpec extends ScalaTestWithActorTestKit(ConfigFactory.load("application")) with FixtureAnyFunSuiteLike { val remoteNodeId: Crypto.PublicKey = randomKey().publicKey - val defaultParams: DefaultParams = DefaultParams(100 sat, UInt64(100000), 100 msat, CltvExpiryDelta(288), 10) val openChannel: OpenChannel = createOpenChannelMessage() val remoteAddress: NodeAddress = IPAddress(InetAddress.getLoopbackAddress, 19735) val defaultFeatures: Features[InitFeature] = Features(Map[InitFeature, FeatureSupport](StaticRemoteKey -> Optional, AnchorOutputsZeroFeeHtlcTx -> Optional)) @@ -103,13 +102,8 @@ class OpenChannelInterceptorSpec extends ScalaTestWithActorTestKit(ConfigFactory val openChannelNonInitiator = OpenChannelNonInitiator(remoteNodeId, Left(openChannel), defaultFeatures, defaultFeatures, peerConnection.ref, remoteAddress) openChannelInterceptor ! openChannelNonInitiator pendingChannelsRateLimiter.expectMessageType[AddOrRejectChannel].replyTo ! PendingChannelsRateLimiter.AcceptOpenChannel - pluginInterceptor.expectMessageType[InterceptOpenChannelReceived].replyTo ! AcceptOpenChannel(randomBytes32(), defaultParams, addFunding_opt = None) - val updatedLocalParams = peer.expectMessageType[SpawnChannelNonInitiator].localParams - assert(updatedLocalParams.dustLimit == defaultParams.dustLimit) - assert(updatedLocalParams.htlcMinimum == defaultParams.htlcMinimum) - assert(updatedLocalParams.maxAcceptedHtlcs == defaultParams.maxAcceptedHtlcs) - assert(updatedLocalParams.maxHtlcValueInFlightMsat == defaultParams.maxHtlcValueInFlightMsat) - assert(updatedLocalParams.toSelfDelay == defaultParams.toSelfDelay) + pluginInterceptor.expectMessageType[InterceptOpenChannelReceived].replyTo ! AcceptOpenChannel(randomBytes32(), addFunding_opt = None) + assert(peer.expectMessageType[SpawnChannelNonInitiator].addFunding_opt.isEmpty) } test("add liquidity if interceptor plugin requests it") { f => @@ -119,7 +113,7 @@ class OpenChannelInterceptorSpec extends ScalaTestWithActorTestKit(ConfigFactory openChannelInterceptor ! openChannelNonInitiator pendingChannelsRateLimiter.expectMessageType[AddOrRejectChannel].replyTo ! PendingChannelsRateLimiter.AcceptOpenChannel val addFunding = LiquidityAds.AddFunding(100_000 sat, None) - pluginInterceptor.expectMessageType[InterceptOpenChannelReceived].replyTo ! AcceptOpenChannel(randomBytes32(), defaultParams, Some(addFunding)) + pluginInterceptor.expectMessageType[InterceptOpenChannelReceived].replyTo ! AcceptOpenChannel(randomBytes32(), Some(addFunding)) assert(peer.expectMessageType[SpawnChannelNonInitiator].addFunding_opt.contains(addFunding)) } @@ -222,7 +216,7 @@ class OpenChannelInterceptorSpec extends ScalaTestWithActorTestKit(ConfigFactory assert(peer.expectMessageType[OutgoingMessage].msg.asInstanceOf[Error].channelId == ByteVector32.One) // original request accepted after plugin accepts it - pluginInterceptor.expectMessageType[InterceptOpenChannelReceived].replyTo ! AcceptOpenChannel(randomBytes32(), defaultParams, None) + pluginInterceptor.expectMessageType[InterceptOpenChannelReceived].replyTo ! AcceptOpenChannel(randomBytes32(), None) assert(peer.expectMessageType[SpawnChannelNonInitiator].open == Left(openChannel)) eventListener.expectMessageType[ChannelAborted] } @@ -242,7 +236,7 @@ class OpenChannelInterceptorSpec extends ScalaTestWithActorTestKit(ConfigFactory val openChannelNonInitiator = OpenChannelNonInitiator(remoteNodeId, Left(openChannel), staticRemoteKeyFeatures, staticRemoteKeyFeatures, peerConnection.ref, remoteAddress) openChannelInterceptor ! openChannelNonInitiator pendingChannelsRateLimiter.expectMessageType[AddOrRejectChannel].replyTo ! PendingChannelsRateLimiter.AcceptOpenChannel - pluginInterceptor.expectMessageType[InterceptOpenChannelReceived].replyTo ! AcceptOpenChannel(randomBytes32(), defaultParams, Some(LiquidityAds.AddFunding(50_000 sat, None))) + pluginInterceptor.expectMessageType[InterceptOpenChannelReceived].replyTo ! AcceptOpenChannel(randomBytes32(), Some(LiquidityAds.AddFunding(50_000 sat, None))) peer.expectMessageType[SpawnChannelNonInitiator] } From 9e2b502e9e0c891997dc219bc9952f66c14445e8 Mon Sep 17 00:00:00 2001 From: t-bast Date: Thu, 19 Jun 2025 17:50:12 +0200 Subject: [PATCH 2/4] Split channel params and commit params We extract some of the channel parameters that are currently in our `LocalParams` and `RemoteParams` classes into a `CommitParams` class. While we currently simply create instances of that class based on our `LocalParams` and `RemoteParams`, the goal is to later move those values out of `LocalParams` and `RemoteParams` to clearly split params that apply to the channel for its entire lifetime from params that can be updated on a per-commitment basis. This is mostly straightforward refactoring, but there is one detail worth reviewing in-depth: we preivously used the `to_self_delay` from the *remote* parameters when creating our *local* commitments. We now instead initially set the `to_self_delay` in our *local* `CommitParams` based on the remote `to_remote_delay`, which has been renamed to make it more clear. This is a bit subtle, but hopefully will be better contained once we split `CommitParams` from `ChannelParams` in a future PR. We also refactor our unit tests to simplify the creation of the "init" messages. This should make it less painful whenever we have to update these tests. --- .../main/scala/fr/acinq/eclair/Features.scala | 1 + .../fr/acinq/eclair/channel/ChannelData.scala | 103 ++++++---- .../acinq/eclair/channel/ChannelEvents.scala | 2 +- .../fr/acinq/eclair/channel/Commitments.scala | 190 +++++++++--------- .../fr/acinq/eclair/channel/Helpers.scala | 86 ++++---- .../fr/acinq/eclair/channel/fsm/Channel.scala | 164 ++++++++------- .../channel/fsm/ChannelOpenDualFunded.scala | 88 ++++---- .../channel/fsm/ChannelOpenSingleFunded.scala | 136 ++++++------- .../channel/fsm/CommonFundingHandlers.scala | 2 +- .../eclair/channel/fsm/CommonHandlers.scala | 8 +- .../channel/fsm/DualFundingHandlers.scala | 2 +- .../eclair/channel/fsm/ErrorHandlers.scala | 24 +-- .../channel/publish/ReplaceableTxFunder.scala | 4 +- .../fr/acinq/eclair/db/DbEventHandler.scala | 4 +- .../eclair/io/OpenChannelInterceptor.scala | 14 +- .../main/scala/fr/acinq/eclair/io/Peer.scala | 58 +++++- .../io/PendingChannelsRateLimiter.scala | 8 +- .../payment/relay/OnTheFlyFunding.scala | 2 +- .../relay/PostRestartHtlcCleaner.scala | 14 +- .../channel/version0/ChannelCodecs0.scala | 8 +- .../channel/version0/ChannelTypes0.scala | 8 +- .../channel/version1/ChannelCodecs1.scala | 6 +- .../channel/version2/ChannelCodecs2.scala | 6 +- .../channel/version3/ChannelCodecs3.scala | 8 +- .../channel/version3/ChannelTypes3.scala | 2 +- .../channel/version4/ChannelCodecs4.scala | 14 +- .../000003-DATA_NORMAL/fundee/data.json | 6 +- .../000003-DATA_NORMAL/funder/data.json | 6 +- .../020002-DATA_NORMAL/funder/data.json | 6 +- .../funder/data.json | 6 +- .../funder/data.json | 6 +- .../funder/data.json | 6 +- .../fundee/data.json | 6 +- .../funder/data.json | 6 +- .../fundee/data.json | 6 +- .../funder/data.json | 6 +- .../04000e-DATA_NORMAL/announced/data.json | 6 +- .../splicing-private/data.json | 6 +- .../scala/fr/acinq/eclair/TestConstants.scala | 8 +- .../eclair/channel/CommitmentsSpec.scala | 12 +- .../fr/acinq/eclair/channel/FuzzySpec.scala | 12 +- .../channel/InteractiveTxBuilderSpec.scala | 26 ++- .../fr/acinq/eclair/channel/RestoreSpec.scala | 2 +- .../publish/ReplaceableTxPublisherSpec.scala | 6 +- .../ChannelStateTestsHelperMethods.scala | 114 +++++++++-- .../a/WaitForAcceptChannelStateSpec.scala | 57 ++---- ...tForAcceptDualFundedChannelStateSpec.scala | 13 +- .../a/WaitForOpenChannelStateSpec.scala | 35 ++-- ...aitForOpenDualFundedChannelStateSpec.scala | 17 +- .../WaitForDualFundingCreatedStateSpec.scala | 13 +- .../b/WaitForDualFundingSignedStateSpec.scala | 28 +-- .../b/WaitForFundingCreatedStateSpec.scala | 14 +- .../b/WaitForFundingInternalStateSpec.scala | 11 +- .../b/WaitForFundingSignedStateSpec.scala | 21 +- .../c/WaitForChannelReadyStateSpec.scala | 24 +-- ...WaitForDualFundingConfirmedStateSpec.scala | 17 +- .../c/WaitForDualFundingReadyStateSpec.scala | 10 +- .../c/WaitForFundingConfirmedStateSpec.scala | 17 +- .../states/e/NormalQuiescentStateSpec.scala | 4 +- .../states/e/NormalSplicesStateSpec.scala | 24 +-- .../channel/states/e/NormalStateSpec.scala | 137 +++++++------ .../channel/states/f/ShutdownStateSpec.scala | 2 +- .../states/g/NegotiatingStateSpec.scala | 22 +- .../channel/states/h/ClosingStateSpec.scala | 48 ++--- .../fr/acinq/eclair/db/ChannelsDbSpec.scala | 12 +- .../db/RevokedHtlcInfoCleanerSpec.scala | 4 +- .../integration/ChannelIntegrationSpec.scala | 16 +- .../zeroconf/ZeroConfActivationSpec.scala | 12 +- .../ZeroConfAliasIntegrationSpec.scala | 10 +- .../io/OpenChannelInterceptorSpec.scala | 5 +- .../scala/fr/acinq/eclair/io/PeerSpec.scala | 17 +- .../io/PendingChannelsRateLimiterSpec.scala | 14 +- .../fr/acinq/eclair/io/SwitchboardSpec.scala | 3 +- .../eclair/json/JsonSerializersSpec.scala | 12 +- .../eclair/payment/PaymentPacketSpec.scala | 6 +- .../payment/relay/OnTheFlyFundingSpec.scala | 10 +- .../internal/channel/ChannelCodecsSpec.scala | 13 +- .../channel/version2/ChannelCodecs2Spec.scala | 18 +- .../channel/version4/ChannelCodecs4Spec.scala | 18 +- 79 files changed, 965 insertions(+), 933 deletions(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/Features.scala b/eclair-core/src/main/scala/fr/acinq/eclair/Features.scala index abaeac49db..080a2e4e27 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/Features.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/Features.scala @@ -259,6 +259,7 @@ object Features { val mandatory = 26 } + // Note that this is a permanent channel feature because it permanently affects the channel reserve, which is set at 1%. case object DualFunding extends Feature with InitFeature with NodeFeature with PermanentChannelFeature { val rfcName = "option_dual_fund" val mandatory = 28 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 35ad9d112d..d55b4515c0 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 @@ -91,6 +91,12 @@ case object ERR_INFORMATION_LEAK extends ChannelState 8888888888 Y8P 8888888888 888 Y888 888 "Y8888P" */ +case class ProposedCommitParams(localDustLimit: Satoshi, + localHtlcMinimum: MilliSatoshi, + localMaxHtlcValueInFlight: UInt64, + localMaxAcceptedHtlcs: Int, + toRemoteDelay: CltvExpiryDelta) + case class INPUT_INIT_CHANNEL_INITIATOR(temporaryChannelId: ByteVector32, fundingAmount: Satoshi, dualFunded: Boolean, @@ -100,7 +106,8 @@ case class INPUT_INIT_CHANNEL_INITIATOR(temporaryChannelId: ByteVector32, pushAmount_opt: Option[MilliSatoshi], requireConfirmedInputs: Boolean, requestFunding_opt: Option[LiquidityAds.RequestFunding], - localParams: LocalParams, + localChannelParams: LocalChannelParams, + proposedCommitParams: ProposedCommitParams, remote: ActorRef, remoteInit: Init, channelFlags: ChannelFlags, @@ -114,7 +121,8 @@ case class INPUT_INIT_CHANNEL_NON_INITIATOR(temporaryChannelId: ByteVector32, dualFunded: Boolean, pushAmount_opt: Option[MilliSatoshi], requireConfirmedInputs: Boolean, - localParams: LocalParams, + localChannelParams: LocalChannelParams, + proposedCommitParams: ProposedCommitParams, remote: ActorRef, remoteInit: Init, channelConfig: ChannelConfig, @@ -530,7 +538,7 @@ sealed trait ChannelDataWithoutCommitments extends PersistentChannelData { sealed trait ChannelDataWithCommitments extends PersistentChannelData { val channelId: ByteVector32 = commitments.channelId val remoteNodeId: PublicKey = commitments.remoteNodeId - val channelParams: ChannelParams = commitments.params + val channelParams: ChannelParams = commitments.channelParams def commitments: Commitments } @@ -540,24 +548,24 @@ final case class DATA_WAIT_FOR_OPEN_CHANNEL(initFundee: INPUT_INIT_CHANNEL_NON_I final case class DATA_WAIT_FOR_ACCEPT_CHANNEL(initFunder: INPUT_INIT_CHANNEL_INITIATOR, lastSent: OpenChannel) extends TransientChannelData { val channelId: ByteVector32 = initFunder.temporaryChannelId } -final case class DATA_WAIT_FOR_FUNDING_INTERNAL(params: ChannelParams, +final case class DATA_WAIT_FOR_FUNDING_INTERNAL(channelParams: ChannelParams, fundingAmount: Satoshi, pushAmount: MilliSatoshi, commitTxFeerate: FeeratePerKw, remoteFundingPubKey: PublicKey, remoteFirstPerCommitmentPoint: PublicKey, replyTo: akka.actor.typed.ActorRef[Peer.OpenChannelResponse]) extends TransientChannelData { - val channelId: ByteVector32 = params.channelId + val channelId: ByteVector32 = channelParams.channelId } -final case class DATA_WAIT_FOR_FUNDING_CREATED(params: ChannelParams, +final case class DATA_WAIT_FOR_FUNDING_CREATED(channelParams: ChannelParams, fundingAmount: Satoshi, pushAmount: MilliSatoshi, commitTxFeerate: FeeratePerKw, remoteFundingPubKey: PublicKey, remoteFirstPerCommitmentPoint: PublicKey) extends TransientChannelData { - val channelId: ByteVector32 = params.channelId + val channelId: ByteVector32 = channelParams.channelId } -final case class DATA_WAIT_FOR_FUNDING_SIGNED(params: ChannelParams, +final case class DATA_WAIT_FOR_FUNDING_SIGNED(channelParams: ChannelParams, remoteFundingPubKey: PublicKey, fundingTx: Transaction, fundingTxFee: Satoshi, @@ -566,7 +574,7 @@ final case class DATA_WAIT_FOR_FUNDING_SIGNED(params: ChannelParams, remoteCommit: RemoteCommit, lastSent: FundingCreated, replyTo: akka.actor.typed.ActorRef[Peer.OpenChannelResponse]) extends TransientChannelData { - val channelId: ByteVector32 = params.channelId + val channelId: ByteVector32 = channelParams.channelId } final case class DATA_WAIT_FOR_FUNDING_CONFIRMED(commitments: Commitments, waitingSince: BlockHeight, // how long have we been waiting for the funding tx to confirm @@ -628,7 +636,7 @@ final case class DATA_NEGOTIATING(commitments: Commitments, closingTxProposed: List[List[ClosingTxProposed]], // one list for every negotiation (there can be several in case of disconnection) bestUnpublishedClosingTx_opt: Option[ClosingTx]) extends ChannelDataWithCommitments { require(closingTxProposed.nonEmpty, "there must always be a list for the current negotiation") - require(!commitments.params.localParams.paysClosingFees || closingTxProposed.forall(_.nonEmpty), "initiator must have at least one closing signature for every negotiation attempt because it initiates the closing") + require(!commitments.localChannelParams.paysClosingFees || closingTxProposed.forall(_.nonEmpty), "initiator must have at least one closing signature for every negotiation attempt because it initiates the closing") } final case class DATA_NEGOTIATING_SIMPLE(commitments: Commitments, lastClosingFeerate: FeeratePerKw, @@ -656,45 +664,54 @@ final case class DATA_CLOSING(commitments: Commitments, final case class DATA_WAIT_FOR_REMOTE_PUBLISH_FUTURE_COMMITMENT(commitments: Commitments, remoteChannelReestablish: ChannelReestablish) extends ChannelDataWithCommitments -/** - * @param initFeatures current connection features, or last features used if the channel is disconnected. Note that these - * features are updated at each reconnection and may be different from the channel permanent features - * (see [[ChannelFeatures]]). - */ -case class LocalParams(nodeId: PublicKey, - fundingKeyPath: DeterministicWallet.KeyPath, - dustLimit: Satoshi, - maxHtlcValueInFlightMsat: UInt64, - initialRequestedChannelReserve_opt: Option[Satoshi], - htlcMinimum: MilliSatoshi, - toSelfDelay: CltvExpiryDelta, - maxAcceptedHtlcs: Int, - isChannelOpener: Boolean, - paysCommitTxFees: Boolean, - upfrontShutdownScript_opt: Option[ByteVector], - walletStaticPaymentBasepoint: Option[PublicKey], - initFeatures: Features[InitFeature]) { +case class LocalChannelParams(nodeId: PublicKey, + fundingKeyPath: DeterministicWallet.KeyPath, + dustLimit: Satoshi, + maxHtlcValueInFlightMsat: UInt64, + // Channel reserve applied to the remote peer, if we're not using [[Features.DualFunding]] (in + // which case the reserve is set to 1%). If the channel is spliced, this initial value will be + // ignored in favor of a 1% reserve of the resulting capacity. + initialRequestedChannelReserve_opt: Option[Satoshi], + htlcMinimum: MilliSatoshi, + toRemoteDelay: CltvExpiryDelta, + maxAcceptedHtlcs: Int, + isChannelOpener: Boolean, + paysCommitTxFees: Boolean, + upfrontShutdownScript_opt: Option[ByteVector], + walletStaticPaymentBasepoint: Option[PublicKey], + // Current connection features, or last features used if the channel is disconnected. Note that + // these features are updated at each reconnection and may be different from the channel permanent + // features (see [[ChannelFeatures]]). + initFeatures: Features[InitFeature]) { // The node responsible for the commit tx fees is also the node paying the mutual close fees. // The other node's balance may be empty, which wouldn't allow them to pay the closing fees. val paysClosingFees: Boolean = paysCommitTxFees -} -/** - * @param initFeatures see [[LocalParams.initFeatures]] - */ -case class RemoteParams(nodeId: PublicKey, - dustLimit: Satoshi, - maxHtlcValueInFlightMsat: UInt64, - initialRequestedChannelReserve_opt: Option[Satoshi], + val proposedCommitParams: ProposedCommitParams = ProposedCommitParams(dustLimit, htlcMinimum, maxHtlcValueInFlightMsat, maxAcceptedHtlcs, toRemoteDelay) +} + +case class RemoteChannelParams(nodeId: PublicKey, + dustLimit: Satoshi, + maxHtlcValueInFlightMsat: UInt64, + // See comment in LocalChannelParams for details. + initialRequestedChannelReserve_opt: Option[Satoshi], + htlcMinimum: MilliSatoshi, + toRemoteDelay: CltvExpiryDelta, + maxAcceptedHtlcs: Int, + revocationBasepoint: PublicKey, + paymentBasepoint: PublicKey, + delayedPaymentBasepoint: PublicKey, + htlcBasepoint: PublicKey, + // See comment in LocalChannelParams for details. + initFeatures: Features[InitFeature], + upfrontShutdownScript_opt: Option[ByteVector]) + +/** Configuration parameters that apply to local or remote commitment transactions, and may be updated dynamically. */ +case class CommitParams(dustLimit: Satoshi, htlcMinimum: MilliSatoshi, - toSelfDelay: CltvExpiryDelta, + maxHtlcValueInFlight: UInt64, maxAcceptedHtlcs: Int, - revocationBasepoint: PublicKey, - paymentBasepoint: PublicKey, - delayedPaymentBasepoint: PublicKey, - htlcBasepoint: PublicKey, - initFeatures: Features[InitFeature], - upfrontShutdownScript_opt: Option[ByteVector]) + toSelfDelay: CltvExpiryDelta) /** * The [[nonInitiatorPaysCommitFees]] parameter is set to true when the sender wants the receiver to pay the commitment transaction fees. diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelEvents.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelEvents.scala index f827873337..3a264041eb 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelEvents.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelEvents.scala @@ -62,7 +62,7 @@ case class LocalChannelUpdate(channel: ActorRef, channelId: ByteVector32, aliase * However we only include the real scid if option_scid_alias is disabled, because we otherwise want to hide it. */ def scidsForRouting: Seq[ShortChannelId] = { - val canUseRealScid = !commitments.params.channelFeatures.hasFeature(Features.ScidAlias) + val canUseRealScid = !commitments.channelParams.channelFeatures.hasFeature(Features.ScidAlias) if (canUseRealScid) { announcement_opt.map(_.shortChannelId).toSeq :+ aliases.localAlias } else { diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala index 6f7ea25f7c..b9b2798409 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala @@ -22,12 +22,11 @@ import scodec.bits.ByteVector case class ChannelParams(channelId: ByteVector32, channelConfig: ChannelConfig, channelFeatures: ChannelFeatures, - localParams: LocalParams, remoteParams: RemoteParams, + localParams: LocalChannelParams, remoteParams: RemoteChannelParams, channelFlags: ChannelFlags) { - require(channelFeatures.paysDirectlyToWallet == localParams.walletStaticPaymentBasepoint.isDefined, s"localParams.walletStaticPaymentBasepoint must be defined only for commitments that pay directly to our wallet (channel features: $channelFeatures") require(channelFeatures.hasFeature(Features.DualFunding) == localParams.initialRequestedChannelReserve_opt.isEmpty, "custom local channel reserve is incompatible with dual-funded channels") - require(channelFeatures.hasFeature(Features.DualFunding) == remoteParams.initialRequestedChannelReserve_opt.isEmpty, "custom remote channel reserve is incompatible with dual-funded channels") + require(channelFeatures.hasFeature(Features.DualFunding) == localParams.initialRequestedChannelReserve_opt.isEmpty, "custom remote channel reserve is incompatible with dual-funded channels") val commitmentFormat: CommitmentFormat = channelFeatures.commitmentFormat val announceChannel: Boolean = channelFlags.announceChannel @@ -35,6 +34,9 @@ case class ChannelParams(channelId: ByteVector32, val localNodeId: PublicKey = localParams.nodeId val remoteNodeId: PublicKey = remoteParams.nodeId + val localCommitParams: CommitParams = CommitParams(localParams.dustLimit, localParams.htlcMinimum, localParams.maxHtlcValueInFlightMsat, localParams.maxAcceptedHtlcs, remoteParams.toRemoteDelay) + val remoteCommitParams: CommitParams = CommitParams(remoteParams.dustLimit, remoteParams.htlcMinimum, remoteParams.maxHtlcValueInFlightMsat, remoteParams.maxAcceptedHtlcs, localParams.toRemoteDelay) + // We can safely cast to millisatoshis since we verify that it's less than a valid millisatoshi amount. val maxHtlcAmount: MilliSatoshi = Seq(localParams.maxHtlcValueInFlightMsat, remoteParams.maxHtlcValueInFlightMsat, UInt64(MilliSatoshi.MaxMoney.toLong)).min.toBigInt.toLong.msat @@ -46,7 +48,7 @@ case class ChannelParams(channelId: ByteVector32, */ def updateFeatures(localInit: Init, remoteInit: Init): ChannelParams = copy( localParams = localParams.copy(initFeatures = localInit.features), - remoteParams = remoteParams.copy(initFeatures = remoteInit.features) + remoteParams = remoteParams.copy(initFeatures = remoteInit.features), ) /** @@ -57,16 +59,16 @@ case class ChannelParams(channelId: ByteVector32, /** Channel reserve that applies to our funds. */ def localChannelReserveForCapacity(capacity: Satoshi, isSplice: Boolean): Satoshi = if (channelFeatures.hasFeature(Features.DualFunding) || isSplice) { - (capacity / 100).max(remoteParams.dustLimit) + (capacity / 100).max(remoteCommitParams.dustLimit) } else { - remoteParams.initialRequestedChannelReserve_opt.get // this is guarded by a require() in Params + remoteParams.initialRequestedChannelReserve_opt.get // this is guarded by a require() in ChannelParams } /** Channel reserve that applies to our peer's funds. */ def remoteChannelReserveForCapacity(capacity: Satoshi, isSplice: Boolean): Satoshi = if (channelFeatures.hasFeature(Features.DualFunding) || isSplice) { - (capacity / 100).max(localParams.dustLimit) + (capacity / 100).max(localCommitParams.dustLimit) } else { - localParams.initialRequestedChannelReserve_opt.get // this is guarded by a require() in Params + localParams.initialRequestedChannelReserve_opt.get // this is guarded by a require() in ChannelParams } /** @@ -192,7 +194,7 @@ object LocalCommit { def fromCommitSig(params: ChannelParams, commitKeys: LocalCommitmentKeys, fundingTxId: TxId, fundingKey: PrivateKey, remoteFundingPubKey: PublicKey, commitInput: InputInfo, commit: CommitSig, localCommitIndex: Long, spec: CommitmentSpec): Either[ChannelException, LocalCommit] = { - val (localCommitTx, htlcTxs) = Commitment.makeLocalTxs(params, commitKeys, localCommitIndex, fundingKey, remoteFundingPubKey, commitInput, spec) + val (localCommitTx, htlcTxs) = Commitment.makeLocalTxs(params, params.localCommitParams, commitKeys, localCommitIndex, fundingKey, remoteFundingPubKey, commitInput, spec) val remoteCommitSigOk = params.commitmentFormat match { case _: SegwitV0CommitmentFormat => localCommitTx.checkRemoteSig(fundingKey.publicKey, remoteFundingPubKey, ChannelSpendSignature.IndividualSignature(commit.signature)) case _: SimpleTaprootChannelCommitmentFormat => ??? @@ -224,7 +226,7 @@ case class RemoteCommit(index: Long, spec: CommitmentSpec, txId: TxId, remotePer def sign(params: ChannelParams, channelKeys: ChannelKeys, fundingTxIndex: Long, remoteFundingPubKey: PublicKey, commitInput: InputInfo): CommitSig = { val fundingKey = channelKeys.fundingKey(fundingTxIndex) val commitKeys = RemoteCommitmentKeys(params, channelKeys, remotePerCommitmentPoint) - val (remoteCommitTx, htlcTxs) = Commitment.makeRemoteTxs(params, commitKeys, index, fundingKey, remoteFundingPubKey, commitInput, spec) + val (remoteCommitTx, htlcTxs) = Commitment.makeRemoteTxs(params, params.remoteCommitParams, commitKeys, index, fundingKey, remoteFundingPubKey, commitInput, spec) val sortedHtlcTxs = htlcTxs.sortBy(_.input.outPoint.index) val htlcSigs = sortedHtlcTxs.map(_.localSig(commitKeys)) params.commitmentFormat match { @@ -322,11 +324,11 @@ case class Commitment(fundingTxIndex: Long, val balanceNoFees = (reduced.toRemote - localChannelReserve(params)).max(0 msat) if (localParams.paysCommitTxFees) { // The initiator always pays the on-chain fees, so we must subtract that from the amount we can send. - val commitFees = commitTxTotalCostMsat(remoteParams.dustLimit, reduced, commitmentFormat) + val commitFees = commitTxTotalCostMsat(remoteCommitParams.dustLimit, reduced, commitmentFormat) // the initiator needs to keep a "funder fee buffer" (see explanation above) - val funderFeeBuffer = commitTxTotalCostMsat(remoteParams.dustLimit, reduced.copy(commitTxFeerate = reduced.commitTxFeerate * 2), commitmentFormat) + htlcOutputFee(reduced.commitTxFeerate * 2, commitmentFormat) + val funderFeeBuffer = commitTxTotalCostMsat(remoteCommitParams.dustLimit, reduced.copy(commitTxFeerate = reduced.commitTxFeerate * 2), commitmentFormat) + htlcOutputFee(reduced.commitTxFeerate * 2, commitmentFormat) val amountToReserve = commitFees.max(funderFeeBuffer) - if (balanceNoFees - amountToReserve < offeredHtlcTrimThreshold(remoteParams.dustLimit, reduced, commitmentFormat)) { + if (balanceNoFees - amountToReserve < offeredHtlcTrimThreshold(remoteCommitParams.dustLimit, reduced, commitmentFormat)) { // htlc will be trimmed (balanceNoFees - amountToReserve).max(0 msat) } else { @@ -352,11 +354,11 @@ case class Commitment(fundingTxIndex: Long, balanceNoFees } else { // The initiator always pays the on-chain fees, so we must subtract that from the amount we can receive. - val commitFees = commitTxTotalCostMsat(localParams.dustLimit, reduced, commitmentFormat) + val commitFees = commitTxTotalCostMsat(localCommitParams.dustLimit, reduced, commitmentFormat) // we expected the initiator to keep a "funder fee buffer" (see explanation above) - val funderFeeBuffer = commitTxTotalCostMsat(localParams.dustLimit, reduced.copy(commitTxFeerate = reduced.commitTxFeerate * 2), commitmentFormat) + htlcOutputFee(reduced.commitTxFeerate * 2, commitmentFormat) + val funderFeeBuffer = commitTxTotalCostMsat(localCommitParams.dustLimit, reduced.copy(commitTxFeerate = reduced.commitTxFeerate * 2), commitmentFormat) + htlcOutputFee(reduced.commitTxFeerate * 2, commitmentFormat) val amountToReserve = commitFees.max(funderFeeBuffer) - if (balanceNoFees - amountToReserve < receivedHtlcTrimThreshold(localParams.dustLimit, reduced, commitmentFormat)) { + if (balanceNoFees - amountToReserve < receivedHtlcTrimThreshold(localCommitParams.dustLimit, reduced, commitmentFormat)) { // htlc will be trimmed (balanceNoFees - amountToReserve).max(0 msat) } else { @@ -471,10 +473,10 @@ case class Commitment(fundingTxIndex: Long, val outgoingHtlcs = reduced.htlcs.collect(DirectedHtlc.incoming) // note that the initiator pays the fee, so if sender != initiator, both sides will have to afford this payment - val fees = commitTxTotalCost(params.remoteParams.dustLimit, reduced, params.commitmentFormat) + val fees = commitTxTotalCost(params.remoteCommitParams.dustLimit, reduced, params.commitmentFormat) // the initiator needs to keep an extra buffer to be able to handle a x2 feerate increase and an additional htlc to avoid // getting the channel stuck (see https://github.com/lightningnetwork/lightning-rfc/issues/728). - val funderFeeBuffer = commitTxTotalCostMsat(params.remoteParams.dustLimit, reduced.copy(commitTxFeerate = reduced.commitTxFeerate * 2), params.commitmentFormat) + htlcOutputFee(reduced.commitTxFeerate * 2, params.commitmentFormat) + val funderFeeBuffer = commitTxTotalCostMsat(params.remoteCommitParams.dustLimit, reduced.copy(commitTxFeerate = reduced.commitTxFeerate * 2), params.commitmentFormat) + htlcOutputFee(reduced.commitTxFeerate * 2, params.commitmentFormat) // NB: increasing the feerate can actually remove htlcs from the commit tx (if they fall below the trim threshold) // which may result in a lower commit tx fee; this is why we take the max of the two. val missingForSender = reduced.toRemote - localChannelReserve(params) - (if (params.localParams.paysCommitTxFees) fees.max(funderFeeBuffer.truncateToSatoshi) else 0.sat) @@ -509,19 +511,19 @@ case class Commitment(fundingTxIndex: Long, if (allowedHtlcValueInFlight < htlcValueInFlight) { return Left(HtlcValueTooHighInFlight(params.channelId, maximum = allowedHtlcValueInFlight, actual = htlcValueInFlight)) } - if (Seq(params.localParams.maxAcceptedHtlcs, params.remoteParams.maxAcceptedHtlcs).min < outgoingHtlcs.size) { - return Left(TooManyAcceptedHtlcs(params.channelId, maximum = Seq(params.localParams.maxAcceptedHtlcs, params.remoteParams.maxAcceptedHtlcs).min)) + if (Seq(params.localCommitParams.maxAcceptedHtlcs, params.remoteCommitParams.maxAcceptedHtlcs).min < outgoingHtlcs.size) { + return Left(TooManyAcceptedHtlcs(params.channelId, maximum = Seq(params.localCommitParams.maxAcceptedHtlcs, params.remoteCommitParams.maxAcceptedHtlcs).min)) } // If sending this htlc would overflow our dust exposure, we reject it. val maxDustExposure = feeConf.feerateToleranceFor(params.remoteNodeId).dustTolerance.maxExposure val localReduced = DustExposure.reduceForDustExposure(localCommit.spec, changes.localChanges.all, changes.remoteChanges.all) - val localDustExposureAfterAdd = DustExposure.computeExposure(localReduced, params.localParams.dustLimit, params.commitmentFormat) + val localDustExposureAfterAdd = DustExposure.computeExposure(localReduced, params.localCommitParams.dustLimit, params.commitmentFormat) if (localDustExposureAfterAdd > maxDustExposure) { return Left(LocalDustHtlcExposureTooHigh(params.channelId, maxDustExposure, localDustExposureAfterAdd)) } val remoteReduced = DustExposure.reduceForDustExposure(remoteCommit1.spec, changes.remoteChanges.all, changes.localChanges.all) - val remoteDustExposureAfterAdd = DustExposure.computeExposure(remoteReduced, params.remoteParams.dustLimit, params.commitmentFormat) + val remoteDustExposureAfterAdd = DustExposure.computeExposure(remoteReduced, params.remoteCommitParams.dustLimit, params.commitmentFormat) if (remoteDustExposureAfterAdd > maxDustExposure) { return Left(RemoteDustHtlcExposureTooHigh(params.channelId, maxDustExposure, remoteDustExposureAfterAdd)) } @@ -545,7 +547,7 @@ case class Commitment(fundingTxIndex: Long, val incomingHtlcs = reduced.htlcs.collect(DirectedHtlc.incoming) // note that the initiator pays the fee, so if sender != initiator, both sides will have to afford this payment - val fees = commitTxTotalCost(params.localParams.dustLimit, reduced, params.commitmentFormat) + val fees = commitTxTotalCost(params.localCommitParams.dustLimit, reduced, params.commitmentFormat) // NB: we don't enforce the funderFeeReserve (see sendAdd) because it would confuse a remote initiator that doesn't have this mitigation in place // We could enforce it once we're confident a large portion of the network implements it. val missingForSender = reduced.toRemote - remoteChannelReserve(params) - (if (params.localParams.paysCommitTxFees) 0.sat else fees) @@ -565,12 +567,12 @@ case class Commitment(fundingTxIndex: Long, // NB: we need the `toSeq` because otherwise duplicate amountMsat would be removed (since incomingHtlcs is a Set). val htlcValueInFlight = incomingHtlcs.toSeq.map(_.amountMsat).sum - if (params.localParams.maxHtlcValueInFlightMsat < htlcValueInFlight) { - return Left(HtlcValueTooHighInFlight(params.channelId, maximum = params.localParams.maxHtlcValueInFlightMsat, actual = htlcValueInFlight)) + if (params.localCommitParams.maxHtlcValueInFlight < htlcValueInFlight) { + return Left(HtlcValueTooHighInFlight(params.channelId, maximum = params.localCommitParams.maxHtlcValueInFlight, actual = htlcValueInFlight)) } - if (incomingHtlcs.size > params.localParams.maxAcceptedHtlcs) { - return Left(TooManyAcceptedHtlcs(params.channelId, maximum = params.localParams.maxAcceptedHtlcs)) + if (incomingHtlcs.size > params.localCommitParams.maxAcceptedHtlcs) { + return Left(TooManyAcceptedHtlcs(params.channelId, maximum = params.localCommitParams.maxAcceptedHtlcs)) } Right(()) @@ -581,7 +583,7 @@ case class Commitment(fundingTxIndex: Long, val reduced = CommitmentSpec.reduce(remoteCommit.spec, changes.remoteChanges.acked, changes.localChanges.proposed) // a node cannot spend pending incoming htlcs, and need to keep funds above the reserve required by the counterparty, after paying the fee // we look from remote's point of view, so if local is initiator remote doesn't pay the fees - val fees = commitTxTotalCost(params.remoteParams.dustLimit, reduced, params.commitmentFormat) + val fees = commitTxTotalCost(params.remoteCommitParams.dustLimit, reduced, params.commitmentFormat) val missing = reduced.toRemote.truncateToSatoshi - localChannelReserve(params) - fees if (missing < 0.sat) { return Left(CannotAffordFees(params.channelId, missing = -missing, reserve = localChannelReserve(params), fees = fees)) @@ -592,12 +594,12 @@ case class Commitment(fundingTxIndex: Long, // this is the commitment as it would be if our update_fee was immediately signed by both parties (it is only an // estimate because there can be concurrent updates) val localReduced = DustExposure.reduceForDustExposure(localCommit.spec, changes.localChanges.all, changes.remoteChanges.all) - val localDustExposureAfterFeeUpdate = DustExposure.computeExposure(localReduced, targetFeerate, params.localParams.dustLimit, params.commitmentFormat) + val localDustExposureAfterFeeUpdate = DustExposure.computeExposure(localReduced, targetFeerate, params.localCommitParams.dustLimit, params.commitmentFormat) if (localDustExposureAfterFeeUpdate > maxDustExposure) { return Left(LocalDustHtlcExposureTooHigh(params.channelId, maxDustExposure, localDustExposureAfterFeeUpdate)) } val remoteReduced = DustExposure.reduceForDustExposure(remoteCommit.spec, changes.remoteChanges.all, changes.localChanges.all) - val remoteDustExposureAfterFeeUpdate = DustExposure.computeExposure(remoteReduced, targetFeerate, params.remoteParams.dustLimit, params.commitmentFormat) + val remoteDustExposureAfterFeeUpdate = DustExposure.computeExposure(remoteReduced, targetFeerate, params.remoteCommitParams.dustLimit, params.commitmentFormat) if (remoteDustExposureAfterFeeUpdate > maxDustExposure) { return Left(RemoteDustHtlcExposureTooHigh(params.channelId, maxDustExposure, remoteDustExposureAfterFeeUpdate)) } @@ -620,7 +622,7 @@ case class Commitment(fundingTxIndex: Long, // (it also means that we need to check the fee of the initial commitment tx somewhere) val reduced = CommitmentSpec.reduce(localCommit.spec, changes.localChanges.acked, changes.remoteChanges.proposed) // a node cannot spend pending incoming htlcs, and need to keep funds above the reserve required by the counterparty, after paying the fee - val fees = commitTxTotalCost(params.localParams.dustLimit, reduced, params.commitmentFormat) + val fees = commitTxTotalCost(params.localCommitParams.dustLimit, reduced, params.commitmentFormat) val missing = reduced.toRemote.truncateToSatoshi - remoteChannelReserve(params) - fees if (missing < 0.sat) { return Left(CannotAffordFees(params.channelId, missing = -missing, reserve = remoteChannelReserve(params), fees = fees)) @@ -629,14 +631,14 @@ case class Commitment(fundingTxIndex: Long, if (feeConf.feerateToleranceFor(params.remoteNodeId).dustTolerance.closeOnUpdateFeeOverflow) { val maxDustExposure = feeConf.feerateToleranceFor(params.remoteNodeId).dustTolerance.maxExposure val localReduced = DustExposure.reduceForDustExposure(localCommit.spec, changes.localChanges.all, changes.remoteChanges.all) - val localDustExposureAfterFeeUpdate = DustExposure.computeExposure(localReduced, targetFeerate, params.localParams.dustLimit, params.commitmentFormat) + val localDustExposureAfterFeeUpdate = DustExposure.computeExposure(localReduced, targetFeerate, params.localCommitParams.dustLimit, params.commitmentFormat) if (localDustExposureAfterFeeUpdate > maxDustExposure) { return Left(LocalDustHtlcExposureTooHigh(params.channelId, maxDustExposure, localDustExposureAfterFeeUpdate)) } // this is the commitment as it would be if their update_fee was immediately signed by both parties (it is only an // estimate because there can be concurrent updates) val remoteReduced = DustExposure.reduceForDustExposure(remoteCommit.spec, changes.remoteChanges.all, changes.localChanges.all) - val remoteDustExposureAfterFeeUpdate = DustExposure.computeExposure(remoteReduced, targetFeerate, params.remoteParams.dustLimit, params.commitmentFormat) + val remoteDustExposureAfterFeeUpdate = DustExposure.computeExposure(remoteReduced, targetFeerate, params.remoteCommitParams.dustLimit, params.commitmentFormat) if (remoteDustExposureAfterFeeUpdate > maxDustExposure) { return Left(RemoteDustHtlcExposureTooHigh(params.channelId, maxDustExposure, remoteDustExposureAfterFeeUpdate)) } @@ -649,7 +651,7 @@ case class Commitment(fundingTxIndex: Long, // remote commitment will include all local proposed changes + remote acked changes val spec = CommitmentSpec.reduce(remoteCommit.spec, changes.remoteChanges.acked, changes.localChanges.proposed) val fundingKey = channelKeys.fundingKey(fundingTxIndex) - val (remoteCommitTx, htlcTxs) = Commitment.makeRemoteTxs(params, commitKeys, remoteCommit.index + 1, fundingKey, remoteFundingPubKey, commitInput, spec) + val (remoteCommitTx, htlcTxs) = Commitment.makeRemoteTxs(params, params.remoteCommitParams, commitKeys, remoteCommit.index + 1, fundingKey, remoteFundingPubKey, commitInput, spec) val htlcSigs = htlcTxs.sortBy(_.input.outPoint.index).map(_.localSig(commitKeys)) // NB: IN/OUT htlcs are inverted because this is the remote commit @@ -691,7 +693,7 @@ case class Commitment(fundingTxIndex: Long, def fullySignedLocalCommitTx(params: ChannelParams, channelKeys: ChannelKeys): Transaction = { val fundingKey = channelKeys.fundingKey(fundingTxIndex) val commitKeys = localKeys(params, channelKeys) - val (unsignedCommitTx, _) = Commitment.makeLocalTxs(params, commitKeys, localCommit.index, fundingKey, remoteFundingPubKey, localCommit.input, localCommit.spec) + val (unsignedCommitTx, _) = Commitment.makeLocalTxs(params, params.localCommitParams, commitKeys, localCommit.index, fundingKey, remoteFundingPubKey, localCommit.input, localCommit.spec) localCommit.remoteSig match { case remoteSig: ChannelSpendSignature.IndividualSignature => val localSig = unsignedCommitTx.sign(fundingKey, remoteFundingPubKey) @@ -709,36 +711,38 @@ case class Commitment(fundingTxIndex: Long, /** Return the HTLC transactions for our local commit and the corresponding remote signatures. */ def htlcTxs(params: ChannelParams, fundingKey: PrivateKey, commitKeys: LocalCommitmentKeys): Seq[(UnsignedHtlcTx, ByteVector64)] = { - val (_, htlcTxs) = Commitment.makeLocalTxs(params, commitKeys, localCommit.index, fundingKey, remoteFundingPubKey, localCommit.input, localCommit.spec) + val (_, htlcTxs) = Commitment.makeLocalTxs(params, params.localCommitParams, commitKeys, localCommit.index, fundingKey, remoteFundingPubKey, localCommit.input, localCommit.spec) htlcTxs.sortBy(_.input.outPoint.index).zip(localCommit.htlcRemoteSigs) } } object Commitment { - def makeLocalTxs(params: ChannelParams, + def makeLocalTxs(channelParams: ChannelParams, + commitParams: CommitParams, commitKeys: LocalCommitmentKeys, commitTxNumber: Long, localFundingKey: PrivateKey, remoteFundingPubKey: PublicKey, commitmentInput: InputInfo, spec: CommitmentSpec): (CommitTx, Seq[UnsignedHtlcTx]) = { - val outputs = makeCommitTxOutputs(localFundingKey.publicKey, remoteFundingPubKey, commitKeys.publicKeys, params.localParams.paysCommitTxFees, params.localParams.dustLimit, params.remoteParams.toSelfDelay, spec, params.commitmentFormat) - val commitTx = makeCommitTx(commitmentInput, commitTxNumber, commitKeys.ourPaymentBasePoint, params.remoteParams.paymentBasepoint, params.localParams.isChannelOpener, outputs) - val htlcTxs = makeHtlcTxs(commitTx.tx, outputs, params.commitmentFormat) + val outputs = makeCommitTxOutputs(localFundingKey.publicKey, remoteFundingPubKey, commitKeys.publicKeys, channelParams.localParams.paysCommitTxFees, commitParams.dustLimit, commitParams.toSelfDelay, spec, channelParams.commitmentFormat) + val commitTx = makeCommitTx(commitmentInput, commitTxNumber, commitKeys.ourPaymentBasePoint, channelParams.remoteParams.paymentBasepoint, channelParams.localParams.isChannelOpener, outputs) + val htlcTxs = makeHtlcTxs(commitTx.tx, outputs, channelParams.commitmentFormat) (commitTx, htlcTxs) } - def makeRemoteTxs(params: ChannelParams, + def makeRemoteTxs(channelParams: ChannelParams, + commitParams: CommitParams, commitKeys: RemoteCommitmentKeys, commitTxNumber: Long, localFundingKey: PrivateKey, remoteFundingPubKey: PublicKey, commitmentInput: InputInfo, spec: CommitmentSpec): (CommitTx, Seq[UnsignedHtlcTx]) = { - val outputs = makeCommitTxOutputs(remoteFundingPubKey, localFundingKey.publicKey, commitKeys.publicKeys, !params.localParams.paysCommitTxFees, params.remoteParams.dustLimit, params.localParams.toSelfDelay, spec, params.commitmentFormat) - val commitTx = makeCommitTx(commitmentInput, commitTxNumber, params.remoteParams.paymentBasepoint, commitKeys.ourPaymentBasePoint, !params.localParams.isChannelOpener, outputs) - val htlcTxs = makeHtlcTxs(commitTx.tx, outputs, params.commitmentFormat) + val outputs = makeCommitTxOutputs(remoteFundingPubKey, localFundingKey.publicKey, commitKeys.publicKeys, !channelParams.localParams.paysCommitTxFees, commitParams.dustLimit, commitParams.toSelfDelay, spec, channelParams.commitmentFormat) + val commitTx = makeCommitTx(commitmentInput, commitTxNumber, channelParams.remoteParams.paymentBasepoint, commitKeys.ourPaymentBasePoint, !channelParams.localParams.isChannelOpener, outputs) + val htlcTxs = makeHtlcTxs(commitTx.tx, outputs, channelParams.commitmentFormat) (commitTx, htlcTxs) } } @@ -751,38 +755,41 @@ case class AnnouncedCommitment(commitment: Commitment, announcement: ChannelAnno } /** Subset of Commitments when we want to work with a single, specific commitment. */ -case class FullCommitment(params: ChannelParams, changes: CommitmentChanges, +case class FullCommitment(channelParams: ChannelParams, changes: CommitmentChanges, fundingTxIndex: Long, firstRemoteCommitIndex: Long, remoteFundingPubKey: PublicKey, localFundingStatus: LocalFundingStatus, remoteFundingStatus: RemoteFundingStatus, localCommit: LocalCommit, remoteCommit: RemoteCommit, nextRemoteCommit_opt: Option[NextRemoteCommit]) { - val channelId: ByteVector32 = params.channelId + val channelId: ByteVector32 = channelParams.channelId val shortChannelId_opt: Option[RealShortChannelId] = localFundingStatus match { case f: LocalFundingStatus.ConfirmedFundingTx => Some(f.shortChannelId) case _ => None } - val localParams: LocalParams = params.localParams - val remoteParams: RemoteParams = params.remoteParams + val localChannelParams: LocalChannelParams = channelParams.localParams + val localCommitParams: CommitParams = channelParams.localCommitParams + val remoteChannelParams: RemoteChannelParams = channelParams.remoteParams + val remoteCommitParams: CommitParams = channelParams.remoteCommitParams val commitInput: InputInfo = localCommit.input val fundingTxId: TxId = commitInput.outPoint.txid val commitTxIds: CommitTxIds = CommitTxIds(localCommit.txId, remoteCommit.txId, nextRemoteCommit_opt.map(_.commit.txId)) val capacity: Satoshi = commitInput.txOut.amount + val commitmentFormat: CommitmentFormat = channelParams.commitmentFormat val commitment: Commitment = Commitment(fundingTxIndex, firstRemoteCommitIndex, remoteFundingPubKey, localFundingStatus, remoteFundingStatus, localCommit, remoteCommit, nextRemoteCommit_opt) - def localKeys(channelKeys: ChannelKeys): LocalCommitmentKeys = commitment.localKeys(params, channelKeys) + def localKeys(channelKeys: ChannelKeys): LocalCommitmentKeys = commitment.localKeys(channelParams, channelKeys) - def remoteKeys(channelKeys: ChannelKeys, remotePerCommitmentPoint: PublicKey): RemoteCommitmentKeys = commitment.remoteKeys(params, channelKeys, remotePerCommitmentPoint) + def remoteKeys(channelKeys: ChannelKeys, remotePerCommitmentPoint: PublicKey): RemoteCommitmentKeys = commitment.remoteKeys(channelParams, channelKeys, remotePerCommitmentPoint) - def localChannelReserve: Satoshi = commitment.localChannelReserve(params) + def localChannelReserve: Satoshi = commitment.localChannelReserve(channelParams) - def remoteChannelReserve: Satoshi = commitment.remoteChannelReserve(params) + def remoteChannelReserve: Satoshi = commitment.remoteChannelReserve(channelParams) - def fullySignedLocalCommitTx(channelKeys: ChannelKeys): Transaction = commitment.fullySignedLocalCommitTx(params, channelKeys) + def fullySignedLocalCommitTx(channelKeys: ChannelKeys): Transaction = commitment.fullySignedLocalCommitTx(channelParams, channelKeys) - def htlcTxs(channelKeys: ChannelKeys): Seq[(UnsignedHtlcTx, ByteVector64)] = commitment.htlcTxs(params, channelKeys) + def htlcTxs(channelKeys: ChannelKeys): Seq[(UnsignedHtlcTx, ByteVector64)] = commitment.htlcTxs(channelParams, channelKeys) - def htlcTxs(fundingKey: PrivateKey, commitKeys: LocalCommitmentKeys): Seq[(UnsignedHtlcTx, ByteVector64)] = commitment.htlcTxs(params, fundingKey, commitKeys) + def htlcTxs(fundingKey: PrivateKey, commitKeys: LocalCommitmentKeys): Seq[(UnsignedHtlcTx, ByteVector64)] = commitment.htlcTxs(channelParams, fundingKey, commitKeys) def specs2String: String = { s"""specs: @@ -813,7 +820,7 @@ case class WaitForRev(sentAfterLocalCommitIndex: Long) * commitment, which funding tx is not yet confirmed, and will be pruned when it confirms * @param remoteChannelData_opt peer backup */ -case class Commitments(params: ChannelParams, +case class Commitments(channelParams: ChannelParams, changes: CommitmentChanges, active: Seq[Commitment], inactive: Seq[Commitment] = Nil, @@ -826,10 +833,13 @@ case class Commitments(params: ChannelParams, require(active.nonEmpty, "there must be at least one active commitment") - val channelId: ByteVector32 = params.channelId - val localNodeId: PublicKey = params.localNodeId - val remoteNodeId: PublicKey = params.remoteNodeId - val announceChannel: Boolean = params.announceChannel + val channelId: ByteVector32 = channelParams.channelId + val localNodeId: PublicKey = channelParams.localNodeId + val remoteNodeId: PublicKey = channelParams.remoteNodeId + val announceChannel: Boolean = channelParams.announceChannel + + val localChannelParams: LocalChannelParams = channelParams.localParams + val remoteChannelParams: RemoteChannelParams = channelParams.remoteParams // Commitment numbers are the same for all active commitments. val localCommitIndex: Long = active.head.localCommit.index @@ -838,13 +848,13 @@ case class Commitments(params: ChannelParams, // While we have multiple active commitments, we use the most restrictive one. val capacity: Satoshi = active.map(_.capacity).min - lazy val availableBalanceForSend: MilliSatoshi = active.map(_.availableBalanceForSend(params, changes)).min - lazy val availableBalanceForReceive: MilliSatoshi = active.map(_.availableBalanceForReceive(params, changes)).min + lazy val availableBalanceForSend: MilliSatoshi = active.map(_.availableBalanceForSend(channelParams, changes)).min + lazy val availableBalanceForReceive: MilliSatoshi = active.map(_.availableBalanceForReceive(channelParams, changes)).min val all: Seq[Commitment] = active ++ inactive // We always use the last commitment that was created, to make sure we never go back in time. - val latest: FullCommitment = FullCommitment(params, changes, active.head.fundingTxIndex, active.head.firstRemoteCommitIndex, active.head.remoteFundingPubKey, active.head.localFundingStatus, active.head.remoteFundingStatus, active.head.localCommit, active.head.remoteCommit, active.head.nextRemoteCommit_opt) + val latest: FullCommitment = FullCommitment(channelParams, changes, active.head.fundingTxIndex, active.head.firstRemoteCommitIndex, active.head.remoteFundingPubKey, active.head.localFundingStatus, active.head.remoteFundingStatus, active.head.localCommit, active.head.remoteCommit, active.head.nextRemoteCommit_opt) val lastLocalLocked_opt: Option[Commitment] = active.filter(_.localFundingStatus.isInstanceOf[LocalFundingStatus.Locked]).sortBy(_.fundingTxIndex).lastOption val lastRemoteLocked_opt: Option[Commitment] = active.filter(c => c.remoteFundingStatus == RemoteFundingStatus.Locked).sortBy(_.fundingTxIndex).lastOption @@ -864,7 +874,7 @@ case class Commitments(params: ChannelParams, def getIncomingHtlcCrossSigned(htlcId: Long): Option[UpdateAddHtlc] = active.head.getIncomingHtlcCrossSigned(htlcId) // @formatter:on - def updateInitFeatures(localInit: Init, remoteInit: Init): Commitments = this.copy(params = params.updateFeatures(localInit, remoteInit)) + def updateInitFeatures(localInit: Init, remoteInit: Init): Commitments = this.copy(channelParams = channelParams.updateFeatures(localInit, remoteInit)) /** * @param cmd add HTLC command @@ -884,9 +894,9 @@ case class Commitments(params: ChannelParams, } // even if remote advertises support for 0 msat htlc, we limit ourselves to values strictly positive, hence the max(1 msat) - val htlcMinimum = params.remoteParams.htlcMinimum.max(1 msat) + val htlcMinimum = channelParams.remoteCommitParams.htlcMinimum.max(1 msat) if (cmd.amount < htlcMinimum) { - return Left(HtlcValueTooSmall(params.channelId, minimum = htlcMinimum, actual = cmd.amount)) + return Left(HtlcValueTooSmall(channelId, minimum = htlcMinimum, actual = cmd.amount)) } val add = UpdateAddHtlc(channelId, changes.localNextHtlcId, cmd.amount, cmd.paymentHash, cmd.cltvExpiry, cmd.onion, cmd.nextPathKey_opt, cmd.confidence, cmd.fundingFee_opt) @@ -894,7 +904,7 @@ case class Commitments(params: ChannelParams, val changes1 = changes.addLocalProposal(add).copy(localNextHtlcId = changes.localNextHtlcId + 1) val originChannels1 = originChannels + (add.id -> cmd.origin) // we verify that this htlc is allowed in every active commitment - active.map(_.canSendAdd(add.amountMsat, params, changes1, feerates, feeConf)) + active.map(_.canSendAdd(add.amountMsat, channelParams, changes1, feerates, feeConf)) .collectFirst { case Left(f) => Left(f) } .getOrElse(Right(copy(changes = changes1, originChannels = originChannels1), add)) } @@ -905,14 +915,14 @@ case class Commitments(params: ChannelParams, } // we used to not enforce a strictly positive minimum, hence the max(1 msat) - val htlcMinimum = params.localParams.htlcMinimum.max(1 msat) + val htlcMinimum = channelParams.localCommitParams.htlcMinimum.max(1 msat) if (add.amountMsat < htlcMinimum) { return Left(HtlcValueTooSmall(channelId, minimum = htlcMinimum, actual = add.amountMsat)) } val changes1 = changes.addRemoteProposal(add).copy(remoteNextHtlcId = changes.remoteNextHtlcId + 1) // we verify that this htlc is allowed in every active commitment - active.map(_.canReceiveAdd(add.amountMsat, params, changes1, feerates, feeConf)) + active.map(_.canReceiveAdd(add.amountMsat, channelParams, changes1, feerates, feeConf)) .collectFirst { case Left(f) => Left(f) } .getOrElse(Right(copy(changes = changes1))) } @@ -923,7 +933,7 @@ case class Commitments(params: ChannelParams, // we have already sent a fail/fulfill for this htlc Left(UnknownHtlcId(channelId, cmd.id)) case Some(htlc) if htlc.paymentHash == Crypto.sha256(cmd.r) => - payment.Monitoring.Metrics.recordIncomingPaymentDistribution(params.remoteNodeId, htlc.amountMsat) + payment.Monitoring.Metrics.recordIncomingPaymentDistribution(remoteNodeId, htlc.amountMsat) val fulfill = OutgoingPaymentPacket.buildHtlcFulfill(nodeSecret, useAttributionData, cmd, htlc) Right((copy(changes = changes.addLocalProposal(fulfill)), fulfill)) case Some(_) => Left(InvalidHtlcPreimage(channelId, cmd.id)) @@ -934,7 +944,7 @@ case class Commitments(params: ChannelParams, getOutgoingHtlcCrossSigned(fulfill.id) match { case Some(htlc) if htlc.paymentHash == Crypto.sha256(fulfill.paymentPreimage) => originChannels.get(fulfill.id) match { case Some(origin) => - payment.Monitoring.Metrics.recordOutgoingPaymentDistribution(params.remoteNodeId, htlc.amountMsat) + payment.Monitoring.Metrics.recordOutgoingPaymentDistribution(remoteNodeId, htlc.amountMsat) Right(copy(changes = changes.addRemoteProposal(fulfill)), origin, htlc) case None => Left(UnknownHtlcId(channelId, fulfill.id)) } @@ -995,35 +1005,35 @@ case class Commitments(params: ChannelParams, } def sendFee(cmd: CMD_UPDATE_FEE, feeConf: OnChainFeeConf): Either[ChannelException, (Commitments, UpdateFee)] = { - if (!params.localParams.paysCommitTxFees) { + if (!channelParams.localParams.paysCommitTxFees) { Left(NonInitiatorCannotSendUpdateFee(channelId)) } else { val fee = UpdateFee(channelId, cmd.feeratePerKw) // update_fee replace each other, so we can remove previous ones val changes1 = changes.copy(localChanges = changes.localChanges.copy(proposed = changes.localChanges.proposed.filterNot(_.isInstanceOf[UpdateFee]) :+ fee)) - active.map(_.canSendFee(cmd.feeratePerKw, params, changes1, feeConf)) + active.map(_.canSendFee(cmd.feeratePerKw, channelParams, changes1, feeConf)) .collectFirst { case Left(f) => Left(f) } .getOrElse { - Metrics.LocalFeeratePerByte.withTag(Tags.CommitmentFormat, params.commitmentFormat.toString).record(FeeratePerByte(cmd.feeratePerKw).feerate.toLong) + Metrics.LocalFeeratePerByte.withTag(Tags.CommitmentFormat, channelParams.commitmentFormat.toString).record(FeeratePerByte(cmd.feeratePerKw).feerate.toLong) Right(copy(changes = changes1), fee) } } } def receiveFee(fee: UpdateFee, feerates: FeeratesPerKw, feeConf: OnChainFeeConf)(implicit log: LoggingAdapter): Either[ChannelException, Commitments] = { - if (params.localParams.paysCommitTxFees) { + if (channelParams.localParams.paysCommitTxFees) { Left(NonInitiatorCannotSendUpdateFee(channelId)) } else if (fee.feeratePerKw < FeeratePerKw.MinimumFeeratePerKw) { Left(FeerateTooSmall(channelId, remoteFeeratePerKw = fee.feeratePerKw)) } else { - val localFeeratePerKw = feeConf.getCommitmentFeerate(feerates, params.remoteNodeId, params.commitmentFormat, active.head.capacity) + val localFeeratePerKw = feeConf.getCommitmentFeerate(feerates, remoteNodeId, channelParams.commitmentFormat, active.head.capacity) log.info("remote feeratePerKw={}, local feeratePerKw={}, ratio={}", fee.feeratePerKw, localFeeratePerKw, fee.feeratePerKw.toLong.toDouble / localFeeratePerKw.toLong) // update_fee replace each other, so we can remove previous ones val changes1 = changes.copy(remoteChanges = changes.remoteChanges.copy(proposed = changes.remoteChanges.proposed.filterNot(_.isInstanceOf[UpdateFee]) :+ fee)) - active.map(_.canReceiveFee(fee.feeratePerKw, params, changes1, feerates, feeConf)) + active.map(_.canReceiveFee(fee.feeratePerKw, channelParams, changes1, feerates, feeConf)) .collectFirst { case Left(f) => Left(f) } .getOrElse { - Metrics.RemoteFeeratePerByte.withTag(Tags.CommitmentFormat, params.commitmentFormat.toString).record(FeeratePerByte(fee.feeratePerKw).feerate.toLong) + Metrics.RemoteFeeratePerByte.withTag(Tags.CommitmentFormat, channelParams.commitmentFormat.toString).record(FeeratePerByte(fee.feeratePerKw).feerate.toLong) Right(copy(changes = changes1)) } } @@ -1033,8 +1043,8 @@ case class Commitments(params: ChannelParams, remoteNextCommitInfo match { case Right(_) if !changes.localHasChanges => Left(CannotSignWithoutChanges(channelId)) case Right(remoteNextPerCommitmentPoint) => - val commitKeys = RemoteCommitmentKeys(params, channelKeys, remoteNextPerCommitmentPoint) - val (active1, sigs) = active.map(_.sendCommit(params, channelKeys, commitKeys, changes, remoteNextPerCommitmentPoint, active.size)).unzip + val commitKeys = RemoteCommitmentKeys(channelParams, channelKeys, remoteNextPerCommitmentPoint) + val (active1, sigs) = active.map(_.sendCommit(channelParams, channelKeys, commitKeys, changes, remoteNextPerCommitmentPoint, active.size)).unzip val commitments1 = copy( changes = changes.copy( localChanges = changes.localChanges.copy(proposed = Nil, signed = changes.localChanges.proposed), @@ -1058,10 +1068,10 @@ case class Commitments(params: ChannelParams, case _: CommitSig if active.size > 1 => return Left(CommitSigCountMismatch(channelId, active.size, 1)) case commitSig: CommitSig => Seq(commitSig) } - val commitKeys = LocalCommitmentKeys(params, channelKeys, localCommitIndex + 1) + val commitKeys = LocalCommitmentKeys(channelParams, channelKeys, localCommitIndex + 1) // Signatures are sent in order (most recent first), calling `zip` will drop trailing sigs that are for deactivated/pruned commitments. val active1 = active.zip(sigs).map { case (commitment, commit) => - commitment.receiveCommit(params, channelKeys, commitKeys, changes, commit) match { + commitment.receiveCommit(channelParams, channelKeys, commitKeys, changes, commit) match { case Left(f) => return Left(f) case Right(commitment1) => commitment1 } @@ -1125,21 +1135,21 @@ case class Commitments(params: ChannelParams, case _ => true }) val localReduced = DustExposure.reduceForDustExposure(localSpecWithoutNewHtlcs, changes.localChanges.all, changes.remoteChanges.acked) - val localCommitDustExposure = DustExposure.computeExposure(localReduced, params.localParams.dustLimit, params.commitmentFormat) + val localCommitDustExposure = DustExposure.computeExposure(localReduced, channelParams.localCommitParams.dustLimit, channelParams.commitmentFormat) val remoteReduced = DustExposure.reduceForDustExposure(remoteSpecWithoutNewHtlcs, changes.remoteChanges.acked, changes.localChanges.all) - val remoteCommitDustExposure = DustExposure.computeExposure(remoteReduced, params.remoteParams.dustLimit, params.commitmentFormat) + val remoteCommitDustExposure = DustExposure.computeExposure(remoteReduced, channelParams.remoteCommitParams.dustLimit, channelParams.commitmentFormat) // we sort incoming htlcs by decreasing amount: we want to prioritize higher amounts. val sortedReceivedHtlcs = receivedHtlcs.sortBy(_.amountMsat).reverse DustExposure.filterBeforeForward( maxDustExposure, localReduced, - params.localParams.dustLimit, + channelParams.localCommitParams.dustLimit, localCommitDustExposure, remoteReduced, - params.remoteParams.dustLimit, + channelParams.remoteCommitParams.dustLimit, remoteCommitDustExposure, sortedReceivedHtlcs, - params.commitmentFormat) + channelParams.commitmentFormat) } val actions = acceptedHtlcs.map(add => PostRevocationAction.RelayHtlc(add)) ++ rejectedHtlcs.map(add => PostRevocationAction.RejectHtlc(add)) ++ @@ -1180,7 +1190,7 @@ case class Commitments(params: ChannelParams, active.forall { commitment => val localFundingKey = channelKeys.fundingKey(commitment.fundingTxIndex).publicKey val remoteFundingKey = commitment.remoteFundingPubKey - val redeemInfo = Helpers.Funding.makeFundingScript(localFundingKey, remoteFundingKey, params.commitmentFormat) + val redeemInfo = Helpers.Funding.makeFundingScript(localFundingKey, remoteFundingKey, channelParams.commitmentFormat) commitment.commitInput.txOut.publicKeyScript == redeemInfo.pubkeyScript } } @@ -1191,7 +1201,7 @@ case class Commitments(params: ChannelParams, case ChannelSpendSignature.IndividualSignature(latestRemoteSig) => latestRemoteSig == commitSig.signature case ChannelSpendSignature.PartialSignatureWithNonce(_, _) => ??? } - params.channelFeatures.hasFeature(Features.DualFunding) && isLatestSig + channelParams.channelFeatures.hasFeature(Features.DualFunding) && isLatestSig } def localFundingSigs(fundingTxId: TxId): Option[TxSignatures] = { @@ -1294,7 +1304,7 @@ case class Commitments(params: ChannelParams, case Some(lastConfirmed) => // NB: we cannot prune active commitments, even if we know that they have been double-spent, because our peer // may not yet be aware of it, and will expect us to send commit_sig. - val pruned = if (params.announceChannel) { + val pruned = if (channelParams.announceChannel) { // If the most recently confirmed commitment isn't announced yet, we cannot prune the last commitment we // announced, because our channel updates are based on its announcement (and its short_channel_id). // If we never announced the channel, we don't need to announce old commitments, we will directly announce the last one. diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala index 7712879ad5..b5305f3b48 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala @@ -352,14 +352,17 @@ object Helpers { def maxHtlcAmount(nodeParams: NodeParams, commitments: Commitments): MilliSatoshi = { if (!commitments.announceChannel) { // The channel is private, let's not change the channel update needlessly. - return commitments.params.maxHtlcAmount + return commitments.channelParams.maxHtlcAmount } for (balanceThreshold <- nodeParams.channelConf.balanceThresholds) { if (commitments.availableBalanceForSend <= balanceThreshold.available) { - return balanceThreshold.maxHtlcAmount.toMilliSatoshi.max(commitments.params.remoteParams.htlcMinimum.max(commitments.params.localParams.htlcMinimum)).min(commitments.params.maxHtlcAmount) + // Our maximum HTLC amount must always be greater than htlc_minimum_msat. + val allowedHtlcAmount = Seq(balanceThreshold.maxHtlcAmount.toMilliSatoshi, commitments.channelParams.localCommitParams.htlcMinimum, commitments.channelParams.remoteCommitParams.htlcMinimum).max + // But it cannot exceed the channel's max_htlc_value_in_flight_msat. + return allowedHtlcAmount.min(commitments.channelParams.maxHtlcAmount) } } - commitments.params.maxHtlcAmount + commitments.channelParams.maxHtlcAmount } def getRelayFees(nodeParams: NodeParams, remoteNodeId: PublicKey, announceChannel: Boolean): RelayFees = { @@ -431,7 +434,7 @@ object Helpers { // Note that the reserve may not always be met: we could be using dual funding with a large funding amount on // our side and a small funding amount on their side. But we shouldn't care as long as they can pay the fees for // the commitment transaction. - val fees = commitTxTotalCost(params.remoteParams.dustLimit, remoteSpec, params.commitmentFormat) + val fees = commitTxTotalCost(params.remoteCommitParams.dustLimit, remoteSpec, params.commitmentFormat) val missing = fees - toRemote.truncateToSatoshi if (missing > 0.sat) { return Left(CannotAffordFirstCommitFees(params.channelId, missing = missing, fees = fees)) @@ -439,8 +442,8 @@ object Helpers { } val commitmentInput = makeFundingInputInfo(fundingTxId, fundingTxOutputIndex, fundingAmount, localFundingKey.publicKey, remoteFundingPubKey, params.commitmentFormat) - val (localCommitTx, _) = Commitment.makeLocalTxs(params, localCommitKeys, localCommitmentIndex, localFundingKey, remoteFundingPubKey, commitmentInput, localSpec) - val (remoteCommitTx, htlcTxs) = Commitment.makeRemoteTxs(params, remoteCommitKeys, remoteCommitmentIndex, localFundingKey, remoteFundingPubKey, commitmentInput, remoteSpec) + val (localCommitTx, _) = Commitment.makeLocalTxs(params, params.localCommitParams, localCommitKeys, localCommitmentIndex, localFundingKey, remoteFundingPubKey, commitmentInput, localSpec) + val (remoteCommitTx, htlcTxs) = Commitment.makeRemoteTxs(params, params.remoteCommitParams, remoteCommitKeys, remoteCommitmentIndex, localFundingKey, remoteFundingPubKey, commitmentInput, remoteSpec) val sortedHtlcTxs = htlcTxs.sortBy(_.input.outPoint.index) Right(localSpec, localCommitTx, remoteSpec, remoteCommitTx, sortedHtlcTxs) } @@ -662,7 +665,7 @@ object Helpers { def firstClosingFee(commitment: FullCommitment, localScriptPubkey: ByteVector, remoteScriptPubkey: ByteVector, feerates: ClosingFeerates)(implicit log: LoggingAdapter): ClosingFees = { // this is just to estimate the weight, it depends on size of the pubkey scripts - val dummyClosingTx = ClosingTx.createUnsignedTx(commitment.commitInput, localScriptPubkey, remoteScriptPubkey, commitment.localParams.paysClosingFees, Satoshi(0), Satoshi(0), commitment.localCommit.spec) + val dummyClosingTx = ClosingTx.createUnsignedTx(commitment.commitInput, localScriptPubkey, remoteScriptPubkey, commitment.localChannelParams.paysClosingFees, 0 sat, 0 sat, commitment.localCommit.spec) val dummyPubkey = commitment.remoteFundingPubKey val dummySig = ChannelSpendSignature.IndividualSignature(Transactions.PlaceHolderSig) val closingWeight = dummyClosingTx.aggregateSigs(dummyPubkey, dummyPubkey, dummySig, dummySig).weight() @@ -672,7 +675,7 @@ object Helpers { def firstClosingFee(commitment: FullCommitment, localScriptPubkey: ByteVector, remoteScriptPubkey: ByteVector, feerates: FeeratesPerKw, onChainFeeConf: OnChainFeeConf)(implicit log: LoggingAdapter): ClosingFees = { val requestedFeerate = onChainFeeConf.getClosingFeerate(feerates) - val preferredFeerate = commitment.params.commitmentFormat match { + val preferredFeerate = commitment.commitmentFormat match { case DefaultCommitmentFormat => // we "MUST set fee_satoshis less than or equal to the base fee of the final commitment transaction" requestedFeerate.min(commitment.localCommit.spec.commitTxFeerate) @@ -696,8 +699,8 @@ object Helpers { def makeClosingTx(channelKeys: ChannelKeys, commitment: FullCommitment, localScriptPubkey: ByteVector, remoteScriptPubkey: ByteVector, closingFees: ClosingFees)(implicit log: LoggingAdapter): (ClosingTx, ClosingSigned) = { log.debug("making closing tx with closing fee={} and commitments:\n{}", closingFees.preferred, commitment.specs2String) - val dustLimit = commitment.localParams.dustLimit.max(commitment.remoteParams.dustLimit) - val closingTx = ClosingTx.createUnsignedTx(commitment.commitInput, localScriptPubkey, remoteScriptPubkey, commitment.localParams.paysClosingFees, dustLimit, closingFees.preferred, commitment.localCommit.spec) + val dustLimit = commitment.localCommitParams.dustLimit.max(commitment.remoteCommitParams.dustLimit) + val closingTx = ClosingTx.createUnsignedTx(commitment.commitInput, localScriptPubkey, remoteScriptPubkey, commitment.localChannelParams.paysClosingFees, dustLimit, closingFees.preferred, commitment.localCommit.spec) val localClosingSig = closingTx.sign(channelKeys.fundingKey(commitment.fundingTxIndex), commitment.remoteFundingPubKey).sig val closingSigned = ClosingSigned(commitment.channelId, closingFees.preferred, localClosingSig, TlvStream(ClosingSignedTlv.FeeRange(closingFees.min, closingFees.max))) log.debug(s"signed closing txid=${closingTx.tx.txid} with closing fee=${closingSigned.feeSatoshis}") @@ -892,15 +895,15 @@ object Helpers { val commitmentKeys = commitment.localKeys(channelKeys) val feerateDelayed = onChainFeeConf.getClosingFeerate(feerates) val mainDelayedTx_opt = withTxGenerationLog("local-main-delayed") { - ClaimLocalDelayedOutputTx.createUnsignedTx(commitmentKeys, commitTx, commitment.localParams.dustLimit, commitment.remoteParams.toSelfDelay, finalScriptPubKey, feerateDelayed, commitment.params.commitmentFormat) + ClaimLocalDelayedOutputTx.createUnsignedTx(commitmentKeys, commitTx, commitment.localCommitParams.dustLimit, commitment.localCommitParams.toSelfDelay, finalScriptPubKey, feerateDelayed, commitment.commitmentFormat) } val unsignedHtlcTxs = commitment.htlcTxs(fundingKey, commitmentKeys) - val (incomingHtlcs, htlcSuccessTxs) = claimIncomingHtlcOutputs(commitmentKeys, commitment, unsignedHtlcTxs) - val (outgoingHtlcs, htlcTimeoutTxs) = claimOutgoingHtlcOutputs(commitmentKeys, commitment, unsignedHtlcTxs) - val anchorOutput_opt = ClaimLocalAnchorTx.findInput(commitTx, fundingKey, commitmentKeys, commitment.params.commitmentFormat).toOption + val (incomingHtlcs, htlcSuccessTxs) = claimIncomingHtlcOutputs(commitmentKeys, commitment.changes, unsignedHtlcTxs) + val (outgoingHtlcs, htlcTimeoutTxs) = claimOutgoingHtlcOutputs(commitmentKeys, unsignedHtlcTxs) + val anchorOutput_opt = ClaimLocalAnchorTx.findInput(commitTx, fundingKey, commitmentKeys, commitment.commitmentFormat).toOption val spendAnchor = incomingHtlcs.nonEmpty || outgoingHtlcs.nonEmpty || onChainFeeConf.spendAnchorWithoutHtlcs val anchorTx_opt = if (spendAnchor) { - claimAnchor(fundingKey, commitmentKeys, commitTx, commitment.params.commitmentFormat) + claimAnchor(fundingKey, commitmentKeys, commitTx, commitment.commitmentFormat) } else { None } @@ -926,26 +929,26 @@ object Helpers { /** Create outputs of the local commitment transaction, allowing us for example to identify HTLC outputs. */ def makeLocalCommitTxOutputs(channelKeys: ChannelKeys, commitKeys: LocalCommitmentKeys, commitment: FullCommitment): Seq[CommitmentOutput] = { val fundingKey = channelKeys.fundingKey(commitment.fundingTxIndex) - makeCommitTxOutputs(fundingKey.publicKey, commitment.remoteFundingPubKey, commitKeys.publicKeys, commitment.localParams.paysCommitTxFees, commitment.localParams.dustLimit, commitment.remoteParams.toSelfDelay, commitment.localCommit.spec, commitment.params.commitmentFormat) + makeCommitTxOutputs(fundingKey.publicKey, commitment.remoteFundingPubKey, commitKeys.publicKeys, commitment.localChannelParams.paysCommitTxFees, commitment.localCommitParams.dustLimit, commitment.localCommitParams.toSelfDelay, commitment.localCommit.spec, commitment.commitmentFormat) } /** * Claim the outputs of a local commit tx corresponding to incoming HTLCs. If we don't have the preimage for an * incoming HTLC, we still include an entry in the map because we may receive that preimage later. */ - private def claimIncomingHtlcOutputs(commitKeys: LocalCommitmentKeys, commitment: FullCommitment, unsignedHtlcTxs: Seq[(UnsignedHtlcTx, ByteVector64)])(implicit log: LoggingAdapter): (Map[OutPoint, Long], Seq[HtlcSuccessTx]) = { + private def claimIncomingHtlcOutputs(commitKeys: LocalCommitmentKeys, changes: CommitmentChanges, unsignedHtlcTxs: Seq[(UnsignedHtlcTx, ByteVector64)])(implicit log: LoggingAdapter): (Map[OutPoint, Long], Seq[HtlcSuccessTx]) = { // We collect all the preimages available. - val preimages = (commitment.changes.localChanges.all ++ commitment.changes.remoteChanges.all).collect { + val preimages = (changes.localChanges.all ++ changes.remoteChanges.all).collect { case u: UpdateFulfillHtlc => Crypto.sha256(u.paymentPreimage) -> u.paymentPreimage }.toMap // We collect incoming HTLCs that we started failing but didn't cross-sign. - val failedIncomingHtlcs: Set[Long] = commitment.changes.localChanges.all.collect { + val failedIncomingHtlcs: Set[Long] = changes.localChanges.all.collect { case u: UpdateFailHtlc => u.id case u: UpdateFailMalformedHtlc => u.id }.toSet // We collect incoming HTLCs that we haven't relayed: they may have been signed by our peer, but we haven't // received their revocation yet. - val nonRelayedIncomingHtlcs: Set[Long] = commitment.changes.remoteChanges.all.collect { case add: UpdateAddHtlc => add.id }.toSet + val nonRelayedIncomingHtlcs: Set[Long] = changes.remoteChanges.all.collect { case add: UpdateAddHtlc => add.id }.toSet val incomingHtlcs = unsignedHtlcTxs.collect { case (txInfo: UnsignedHtlcSuccessTx, remoteSig) => if (preimages.contains(txInfo.paymentHash)) { @@ -977,7 +980,7 @@ object Helpers { /** * Claim the outputs of a local commit tx corresponding to outgoing HTLCs, after their timeout. */ - private def claimOutgoingHtlcOutputs(commitKeys: LocalCommitmentKeys, commitment: FullCommitment, unsignedHtlcTxs: Seq[(UnsignedHtlcTx, ByteVector64)])(implicit log: LoggingAdapter): (Map[OutPoint, Long], Seq[HtlcTimeoutTx]) = { + private def claimOutgoingHtlcOutputs(commitKeys: LocalCommitmentKeys, unsignedHtlcTxs: Seq[(UnsignedHtlcTx, ByteVector64)])(implicit log: LoggingAdapter): (Map[OutPoint, Long], Seq[HtlcTimeoutTx]) = { val outgoingHtlcs = unsignedHtlcTxs.collect { case (txInfo: UnsignedHtlcTimeoutTx, remoteSig) => // We track all outputs that belong to outgoing htlcs. Our peer may or may not have the preimage: if they @@ -1037,7 +1040,7 @@ object Helpers { // Note that this will return None if the transaction wasn't one of our HTLC transactions, which may happen // if our peer was able to claim the HTLC output before us (race condition between success and timeout). val htlcDelayedTx_opt = withTxGenerationLog("htlc-delayed") { - HtlcDelayedTx.createUnsignedTx(commitKeys, tx, commitment.localParams.dustLimit, commitment.remoteParams.toSelfDelay, finalScriptPubKey, feerateDelayed, commitment.params.commitmentFormat) + HtlcDelayedTx.createUnsignedTx(commitKeys, tx, commitment.localCommitParams.dustLimit, commitment.localCommitParams.toSelfDelay, finalScriptPubKey, feerateDelayed, commitment.commitmentFormat) } val localCommitPublished1 = localCommitPublished.copy(htlcDelayedOutputs = localCommitPublished.htlcDelayedOutputs ++ htlcDelayedTx_opt.map(_.input.outPoint).toSeq) (localCommitPublished1, ThirdStageTransactions(htlcDelayedTx_opt.toSeq)) @@ -1068,13 +1071,13 @@ object Helpers { val fundingKey = channelKeys.fundingKey(commitment.fundingTxIndex) val commitKeys = commitment.remoteKeys(channelKeys, remoteCommit.remotePerCommitmentPoint) val outputs = makeRemoteCommitTxOutputs(channelKeys, commitKeys, commitment, remoteCommit) - val mainTx_opt = claimMainOutput(commitment.params, commitKeys, commitTx, feerates, onChainFeeConf, finalScriptPubKey) + val mainTx_opt = claimMainOutput(commitment.channelParams, commitKeys, commitTx, feerates, onChainFeeConf, finalScriptPubKey) val (incomingHtlcs, htlcSuccessTxs) = claimIncomingHtlcOutputs(commitKeys, commitTx, outputs, commitment, remoteCommit, finalScriptPubKey) val (outgoingHtlcs, htlcTimeoutTxs) = claimOutgoingHtlcOutputs(commitKeys, commitTx, outputs, commitment, remoteCommit, finalScriptPubKey) - val anchorOutput_opt = ClaimRemoteAnchorTx.findInput(commitTx, fundingKey, commitKeys, commitment.params.commitmentFormat).toOption + val anchorOutput_opt = ClaimRemoteAnchorTx.findInput(commitTx, fundingKey, commitKeys, commitment.commitmentFormat).toOption val spendAnchor = incomingHtlcs.nonEmpty || outgoingHtlcs.nonEmpty || onChainFeeConf.spendAnchorWithoutHtlcs val anchorTx_opt = if (spendAnchor) { - claimAnchor(fundingKey, commitKeys, commitTx, commitment.params.commitmentFormat) + claimAnchor(fundingKey, commitKeys, commitTx, commitment.commitmentFormat) } else { None } @@ -1101,10 +1104,10 @@ object Helpers { val feerate = onChainFeeConf.getClosingFeerate(feerates) params.commitmentFormat match { case DefaultCommitmentFormat => withTxGenerationLog("remote-main") { - ClaimP2WPKHOutputTx.createUnsignedTx(commitKeys, commitTx, params.localParams.dustLimit, finalScriptPubKey, feerate, params.commitmentFormat) + ClaimP2WPKHOutputTx.createUnsignedTx(commitKeys, commitTx, params.localCommitParams.dustLimit, finalScriptPubKey, feerate, params.commitmentFormat) } case _: AnchorOutputsCommitmentFormat | _: SimpleTaprootChannelCommitmentFormat => withTxGenerationLog("remote-main-delayed") { - ClaimRemoteDelayedOutputTx.createUnsignedTx(commitKeys, commitTx, params.localParams.dustLimit, finalScriptPubKey, feerate, params.commitmentFormat) + ClaimRemoteDelayedOutputTx.createUnsignedTx(commitKeys, commitTx, params.localCommitParams.dustLimit, finalScriptPubKey, feerate, params.commitmentFormat) } } } @@ -1112,7 +1115,7 @@ object Helpers { /** Create outputs of the remote commitment transaction, allowing us for example to identify HTLC outputs. */ def makeRemoteCommitTxOutputs(channelKeys: ChannelKeys, commitKeys: RemoteCommitmentKeys, commitment: FullCommitment, remoteCommit: RemoteCommit): Seq[CommitmentOutput] = { val fundingKey = channelKeys.fundingKey(commitment.fundingTxIndex) - makeCommitTxOutputs(commitment.remoteFundingPubKey, fundingKey.publicKey, commitKeys.publicKeys, !commitment.localParams.paysCommitTxFees, commitment.remoteParams.dustLimit, commitment.localParams.toSelfDelay, remoteCommit.spec, commitment.params.commitmentFormat) + makeCommitTxOutputs(commitment.remoteFundingPubKey, fundingKey.publicKey, commitKeys.publicKeys, !commitment.localChannelParams.paysCommitTxFees, commitment.remoteCommitParams.dustLimit, commitment.remoteCommitParams.toSelfDelay, remoteCommit.spec, commitment.commitmentFormat) } /** @@ -1141,7 +1144,7 @@ object Helpers { // We immediately spend incoming htlcs for which we have the preimage. val preimage = preimages(add.paymentHash) withTxGenerationLog("claim-htlc-success") { - ClaimHtlcSuccessTx.createUnsignedTx(commitKeys, commitTx, commitment.localParams.dustLimit, outputs, finalScriptPubKey, add, preimage, feerate, commitment.params.commitmentFormat) + ClaimHtlcSuccessTx.createUnsignedTx(commitKeys, commitTx, commitment.localCommitParams.dustLimit, outputs, finalScriptPubKey, add, preimage, feerate, commitment.commitmentFormat) }.map(claimHtlcTx => (claimHtlcTx.input.outPoint, add.id, Some(claimHtlcTx))) } else if (failedIncomingHtlcs.contains(add.id)) { // We can ignore incoming htlcs that we started failing: our peer will claim them after the timeout. @@ -1175,7 +1178,7 @@ object Helpers { // claim the output, we will learn the preimage from their transaction, otherwise we will get our funds // back after the timeout. withTxGenerationLog("claim-htlc-timeout") { - ClaimHtlcTimeoutTx.createUnsignedTx(commitKeys, commitTx, commitment.localParams.dustLimit, outputs, finalScriptPubKey, add, feerate, commitment.params.commitmentFormat) + ClaimHtlcTimeoutTx.createUnsignedTx(commitKeys, commitTx, commitment.localCommitParams.dustLimit, outputs, finalScriptPubKey, add, feerate, commitment.commitmentFormat) }.map(claimHtlcTx => (claimHtlcTx.input.outPoint, add.id, Some(claimHtlcTx))) }.flatten.toSeq val htlcOutputs = outgoingHtlcs.collect { case (outpoint, htlcId, _) => outpoint -> htlcId }.toMap @@ -1192,7 +1195,7 @@ object Helpers { // Remember we are looking at the remote commitment so IN for them is really OUT for us and vice versa. case OutgoingHtlc(add: UpdateAddHtlc) if add.paymentHash == Crypto.sha256(preimage) => withTxGenerationLog("claim-htlc-success") { - ClaimHtlcSuccessTx.createUnsignedTx(commitKeys, remoteCommitPublished.commitTx, commitment.localParams.dustLimit, outputs, finalScriptPubKey, add, preimage, feerate, commitment.params.commitmentFormat) + ClaimHtlcSuccessTx.createUnsignedTx(commitKeys, remoteCommitPublished.commitTx, commitment.localCommitParams.dustLimit, outputs, finalScriptPubKey, add, preimage, feerate, commitment.commitmentFormat) } }.flatten.toSeq } @@ -1240,13 +1243,12 @@ object Helpers { * This function returns the per-commitment secret in the first case, and None in the other cases. */ def getRemotePerCommitmentSecret(params: ChannelParams, channelKeys: ChannelKeys, remotePerCommitmentSecrets: ShaChain, commitTx: Transaction): Option[(Long, PrivateKey)] = { - import params._ // a valid tx will always have at least one input, but this ensures we don't throw in tests val sequence = commitTx.txIn.headOption.map(_.sequence).getOrElse(0L) val obscuredTxNumber = Transactions.decodeTxNumber(sequence, commitTx.lockTime) - val localPaymentPoint = localParams.walletStaticPaymentBasepoint.getOrElse(channelKeys.paymentBasePoint) + val localPaymentPoint = params.localParams.walletStaticPaymentBasepoint.getOrElse(channelKeys.paymentBasePoint) // this tx has been published by remote, so we need to invert local/remote params - val txNumber = Transactions.obscuredCommitTxNumber(obscuredTxNumber, !localParams.isChannelOpener, remoteParams.paymentBasepoint, localPaymentPoint) + val txNumber = Transactions.obscuredCommitTxNumber(obscuredTxNumber, !params.localParams.isChannelOpener, params.remoteParams.paymentBasepoint, localPaymentPoint) if (txNumber > 0xffffffffffffL) { // txNumber must be lesser than 48 bits long None @@ -1274,23 +1276,23 @@ object Helpers { // First we will claim our main output right away. val mainTx_opt = commitmentFormat match { case DefaultCommitmentFormat => withTxGenerationLog("remote-main") { - ClaimP2WPKHOutputTx.createUnsignedTx(commitKeys, commitTx, localParams.dustLimit, finalScriptPubKey, feerateMain, commitmentFormat) + ClaimP2WPKHOutputTx.createUnsignedTx(commitKeys, commitTx, localCommitParams.dustLimit, finalScriptPubKey, feerateMain, commitmentFormat) } case _: AnchorOutputsCommitmentFormat | _: SimpleTaprootChannelCommitmentFormat => withTxGenerationLog("remote-main-delayed") { - ClaimRemoteDelayedOutputTx.createUnsignedTx(commitKeys, commitTx, localParams.dustLimit, finalScriptPubKey, feerateMain, commitmentFormat) + ClaimRemoteDelayedOutputTx.createUnsignedTx(commitKeys, commitTx, localCommitParams.dustLimit, finalScriptPubKey, feerateMain, commitmentFormat) } } // Then we punish them by stealing their main output. val mainPenaltyTx_opt = withTxGenerationLog("main-penalty") { - MainPenaltyTx.createUnsignedTx(commitKeys, revocationKey, commitTx, localParams.dustLimit, finalScriptPubKey, localParams.toSelfDelay, feeratePenalty, commitmentFormat) + MainPenaltyTx.createUnsignedTx(commitKeys, revocationKey, commitTx, localCommitParams.dustLimit, finalScriptPubKey, remoteCommitParams.toSelfDelay, feeratePenalty, commitmentFormat) } // We retrieve the historical information needed to rebuild htlc scripts. val htlcInfos = db.listHtlcInfos(channelId, commitmentNumber) log.info("got {} htlcs for commitmentNumber={}", htlcInfos.size, commitmentNumber) // And finally we steal the htlc outputs. - val htlcPenaltyTxs = HtlcPenaltyTx.createUnsignedTxs(commitKeys, revocationKey, commitTx, htlcInfos, localParams.dustLimit, finalScriptPubKey, feeratePenalty, commitmentFormat) + val htlcPenaltyTxs = HtlcPenaltyTx.createUnsignedTxs(commitKeys, revocationKey, commitTx, htlcInfos, localCommitParams.dustLimit, finalScriptPubKey, feeratePenalty, commitmentFormat) .flatMap(htlcPenaltyTx => withTxGenerationLog("htlc-penalty")(htlcPenaltyTx)) val rvk = RevokedCommitPublished( @@ -1342,8 +1344,8 @@ object Helpers { private def claimHtlcTxOutputs(params: ChannelParams, commitmentKeys: RemoteCommitmentKeys, revocationKey: PrivateKey, htlcTx: Transaction, feerates: FeeratesPerKw, finalScriptPubKey: ByteVector)(implicit log: LoggingAdapter): Seq[ClaimHtlcDelayedOutputPenaltyTx] = { // We need to use a high fee when spending HTLC txs because after a delay they can also be spent by the counterparty. val feeratePenalty = feerates.fastest - val dustLimit = params.localParams.dustLimit - val toSelfDelay = params.localParams.toSelfDelay + val dustLimit = params.localCommitParams.dustLimit + val toSelfDelay = params.remoteCommitParams.toSelfDelay ClaimHtlcDelayedOutputPenaltyTx.createUnsignedTxs(commitmentKeys, revocationKey, htlcTx, dustLimit, toSelfDelay, finalScriptPubKey, feeratePenalty, params.commitmentFormat).flatMap(penaltyTx => { withTxGenerationLog("htlc-delayed-penalty")(penaltyTx) }) @@ -1407,7 +1409,7 @@ object Helpers { def trimmedOrTimedOutHtlcs(channelKeys: ChannelKeys, commitment: FullCommitment, localCommit: LocalCommit, confirmedTx: Transaction)(implicit log: LoggingAdapter): Set[UpdateAddHtlc] = { if (confirmedTx.txid == localCommit.txId) { // The commitment tx is confirmed: we can immediately fail all dust htlcs (they don't have an output in the tx). - val untrimmedHtlcs = Transactions.trimOfferedHtlcs(commitment.localParams.dustLimit, localCommit.spec, commitment.params.commitmentFormat).map(_.add) + val untrimmedHtlcs = Transactions.trimOfferedHtlcs(commitment.localCommitParams.dustLimit, localCommit.spec, commitment.commitmentFormat).map(_.add) localCommit.spec.htlcs.collect(outgoing) -- untrimmedHtlcs } else if (confirmedTx.txIn.exists(_.outPoint.txid == localCommit.txId)) { // The transaction spends the commitment tx: maybe it is a timeout tx, in which case we can resolve and fail the @@ -1436,7 +1438,7 @@ object Helpers { def trimmedOrTimedOutHtlcs(channelKeys: ChannelKeys, commitment: FullCommitment, remoteCommit: RemoteCommit, confirmedTx: Transaction)(implicit log: LoggingAdapter): Set[UpdateAddHtlc] = { if (confirmedTx.txid == remoteCommit.txId) { // The commitment tx is confirmed: we can immediately fail all dust htlcs (they don't have an output in the tx). - val untrimmedHtlcs = Transactions.trimReceivedHtlcs(commitment.remoteParams.dustLimit, remoteCommit.spec, commitment.params.commitmentFormat).map(_.add) + val untrimmedHtlcs = Transactions.trimReceivedHtlcs(commitment.remoteCommitParams.dustLimit, remoteCommit.spec, commitment.commitmentFormat).map(_.add) remoteCommit.spec.htlcs.collect(incoming) -- untrimmedHtlcs } else if (confirmedTx.txIn.exists(_.outPoint.txid == remoteCommit.txId)) { // The transaction spends the commitment tx: maybe it is a timeout tx, in which case we can resolve and fail the diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/Channel.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/Channel.scala index 472a7a1f34..262fc08763 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/Channel.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/Channel.scala @@ -124,6 +124,14 @@ object Channel { UInt64(maxHtlcValueInFlightMsat.min(fundingAmount * maxHtlcValueInFlightPercent / 100).toLong) } } + + def commitParams(fundingAmount: Satoshi, unlimitedMaxHtlcValueInFlight: Boolean): ProposedCommitParams = ProposedCommitParams( + localDustLimit = dustLimit, + localHtlcMinimum = htlcMinimum, + localMaxHtlcValueInFlight = maxHtlcValueInFlight(fundingAmount, unlimitedMaxHtlcValueInFlight), + localMaxAcceptedHtlcs = maxAcceptedHtlcs, + toRemoteDelay = toRemoteDelay, + ) } trait TxPublisherFactory { @@ -286,7 +294,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall goto(WAIT_FOR_INIT_SINGLE_FUNDED_CHANNEL) } - case Event(input: INPUT_INIT_CHANNEL_NON_INITIATOR, Nothing) if !input.localParams.isChannelOpener => + case Event(input: INPUT_INIT_CHANNEL_NON_INITIATOR, Nothing) if !input.localChannelParams.isChannelOpener => activeConnection = input.remote txPublisher ! SetChannelId(remoteNodeId, input.temporaryChannelId) if (input.dualFunded) { @@ -327,7 +335,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall watchFundingConfirmed(commitment.fundingTxId, Some(nodeParams.channelConf.minDepth), herdDelay_opt) case fundingTx: LocalFundingStatus.DualFundedUnconfirmedFundingTx => publishFundingTx(fundingTx) - val minDepth_opt = data.commitments.params.minDepth(nodeParams.channelConf.minDepth) + val minDepth_opt = data.commitments.channelParams.minDepth(nodeParams.channelConf.minDepth) watchFundingConfirmed(fundingTx.sharedTx.txId, minDepth_opt, herdDelay_opt) case fundingTx: LocalFundingStatus.ZeroconfPublishedFundingTx => watchFundingConfirmed(fundingTx.tx.txid, Some(nodeParams.channelConf.minDepth), herdDelay_opt) @@ -361,7 +369,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall context.system.eventStream.publish(ChannelAborted(self, remoteNodeId, closing.channelId)) goto(CLOSED) using closing case closing: DATA_CLOSING => - val localPaysClosingFees = closing.commitments.params.localParams.paysClosingFees + val localPaysClosingFees = closing.commitments.localChannelParams.paysClosingFees val closingType_opt = Closing.isClosingTypeAlreadyKnown(closing) log.info(s"channel is closing (closingType=${closingType_opt.map(c => EventType.Closed(c).label).getOrElse("UnknownYet")})") // If the closing type is known: @@ -385,11 +393,11 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall // and must wait for it to confirm. doPublish(c.remoteCommitPublished, Closing.RemoteClose.SecondStageTransactions(None, None, Nil), commitment) case Some(c: Closing.RevokedClose) => - Closing.RevokedClose.getRemotePerCommitmentSecret(closing.commitments.params, channelKeys, closing.commitments.remotePerCommitmentSecrets, c.revokedCommitPublished.commitTx).foreach { + Closing.RevokedClose.getRemotePerCommitmentSecret(closing.commitments.channelParams, channelKeys, closing.commitments.remotePerCommitmentSecrets, c.revokedCommitPublished.commitTx).foreach { case (commitmentNumber, remotePerCommitmentSecret) => - val (_, secondStageTransactions) = Closing.RevokedClose.claimCommitTxOutputs(closing.commitments.params, channelKeys, c.revokedCommitPublished.commitTx, commitmentNumber, remotePerCommitmentSecret, nodeParams.db.channels, nodeParams.currentBitcoinCoreFeerates, nodeParams.onChainFeeConf, closing.finalScriptPubKey) + val (_, secondStageTransactions) = Closing.RevokedClose.claimCommitTxOutputs(closing.commitments.channelParams, channelKeys, c.revokedCommitPublished.commitTx, commitmentNumber, remotePerCommitmentSecret, nodeParams.db.channels, nodeParams.currentBitcoinCoreFeerates, nodeParams.onChainFeeConf, closing.finalScriptPubKey) doPublish(c.revokedCommitPublished, secondStageTransactions) - val thirdStageTransactions = Closing.RevokedClose.claimHtlcTxsOutputs(closing.commitments.params, channelKeys, remotePerCommitmentSecret, c.revokedCommitPublished, nodeParams.currentBitcoinCoreFeerates, closing.finalScriptPubKey) + val thirdStageTransactions = Closing.RevokedClose.claimHtlcTxsOutputs(closing.commitments.channelParams, channelKeys, remotePerCommitmentSecret, c.revokedCommitPublished, nodeParams.currentBitcoinCoreFeerates, closing.finalScriptPubKey) doPublish(c.revokedCommitPublished, thirdStageTransactions) } case None => @@ -412,9 +420,9 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall doPublish(rcp, secondStageTransactions, commitment) }) closing.revokedCommitPublished.foreach(rvk => { - Closing.RevokedClose.getRemotePerCommitmentSecret(closing.commitments.params, channelKeys, closing.commitments.remotePerCommitmentSecrets, rvk.commitTx).foreach { + Closing.RevokedClose.getRemotePerCommitmentSecret(closing.commitments.channelParams, channelKeys, closing.commitments.remotePerCommitmentSecrets, rvk.commitTx).foreach { case (commitmentNumber, remotePerCommitmentSecret) => - val (_, secondStageTransactions) = Closing.RevokedClose.claimCommitTxOutputs(closing.commitments.params, channelKeys, rvk.commitTx, commitmentNumber, remotePerCommitmentSecret, nodeParams.db.channels, nodeParams.currentBitcoinCoreFeerates, nodeParams.onChainFeeConf, closing.finalScriptPubKey) + val (_, secondStageTransactions) = Closing.RevokedClose.claimCommitTxOutputs(closing.commitments.channelParams, channelKeys, rvk.commitTx, commitmentNumber, remotePerCommitmentSecret, nodeParams.db.channels, nodeParams.currentBitcoinCoreFeerates, nodeParams.onChainFeeConf, closing.finalScriptPubKey) doPublish(rvk, secondStageTransactions) } }) @@ -604,8 +612,8 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall val nextCommitNumber = nextRemoteCommit.index // we persist htlc data in order to be able to claim htlc outputs in case a revoked tx is published by our // counterparty, so only htlcs above remote's dust_limit matter - val trimmedHtlcs = Transactions.trimOfferedHtlcs(d.commitments.params.remoteParams.dustLimit, nextRemoteCommit.spec, commitments1.params.commitmentFormat) ++ - Transactions.trimReceivedHtlcs(commitments1.params.remoteParams.dustLimit, nextRemoteCommit.spec, commitments1.params.commitmentFormat) + val trimmedHtlcs = Transactions.trimOfferedHtlcs(d.commitments.channelParams.remoteCommitParams.dustLimit, nextRemoteCommit.spec, commitments1.channelParams.commitmentFormat) ++ + Transactions.trimReceivedHtlcs(commitments1.channelParams.remoteCommitParams.dustLimit, nextRemoteCommit.spec, commitments1.channelParams.commitmentFormat) trimmedHtlcs.map(_.add).foreach { htlc => log.debug(s"adding paymentHash=${htlc.paymentHash} cltvExpiry=${htlc.cltvExpiry} to htlcs db for commitNumber=$nextCommitNumber") nodeParams.db.channels.addHtlcInfo(d.channelId, nextCommitNumber, htlc.paymentHash, htlc.cltvExpiry) @@ -631,7 +639,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall log.warning("received commit_sig after sending tx_abort, they probably sent it before receiving our tx_abort, ignoring...") stay() case (SpliceStatus.SpliceWaitingForSigs(signingSession), sig: CommitSig) => - signingSession.receiveCommitSig(d.commitments.params, channelKeys, sig, nodeParams.currentBlockHeight) match { + signingSession.receiveCommitSig(d.commitments.channelParams, channelKeys, sig, nodeParams.currentBlockHeight) match { case Left(f) => rollbackFundingAttempt(signingSession.fundingTx.tx, Nil) stay() using d.copy(spliceStatus = SpliceStatus.SpliceAborted) sending TxAbort(d.channelId, f.getMessage) @@ -645,7 +653,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall // We don't have their tx_sigs, but they have ours, and could publish the funding tx without telling us. // That's why we move on immediately to the next step, and will update our unsigned funding tx when we // receive their tx_sigs. - val minDepth_opt = d.commitments.params.minDepth(nodeParams.channelConf.minDepth) + val minDepth_opt = d.commitments.channelParams.minDepth(nodeParams.channelConf.minDepth) watchFundingConfirmed(signingSession.fundingTx.txId, minDepth_opt, delay_opt = None) val commitments1 = d.commitments.add(signingSession1.commitment) val d1 = d.copy(commitments = commitments1, spliceStatus = SpliceStatus.NoSplice) @@ -742,7 +750,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall handleCommandError(CannotCloseWithUnsignedOutgoingUpdateFee(d.channelId), c) } else { val localScriptPubKey = c.scriptPubKey.getOrElse(getOrGenerateFinalScriptPubKey(d)) - d.commitments.params.validateLocalShutdownScript(localScriptPubKey) match { + d.commitments.channelParams.validateLocalShutdownScript(localScriptPubKey) match { case Left(e) => handleCommandError(e, c) case Right(localShutdownScript) => val shutdown = Shutdown(d.channelId, localShutdownScript) @@ -751,7 +759,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall } case Event(remoteShutdown@Shutdown(_, remoteScriptPubKey, _), d: DATA_NORMAL) => - d.commitments.params.validateRemoteShutdownScript(remoteScriptPubKey) match { + d.commitments.channelParams.validateRemoteShutdownScript(remoteScriptPubKey) match { case Left(e) => log.warning(s"they sent an invalid closing script: ${e.getMessage}") context.system.scheduler.scheduleOnce(2 second, peer, Peer.Disconnect(remoteNodeId)) @@ -807,10 +815,10 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall // are there pending signed changes on either side? we need to have received their last revocation! if (d.commitments.hasNoPendingHtlcsOrFeeUpdate) { // there are no pending signed changes, let's directly negotiate a closing transaction - if (Features.canUseFeature(d.commitments.params.localParams.initFeatures, d.commitments.params.remoteParams.initFeatures, Features.SimpleClose)) { + if (Features.canUseFeature(d.commitments.localChannelParams.initFeatures, d.commitments.remoteChannelParams.initFeatures, Features.SimpleClose)) { val (d1, closingComplete_opt) = startSimpleClose(d.commitments, localShutdown, remoteShutdown, closeStatus) goto(NEGOTIATING_SIMPLE) using d1 storing() sending sendList ++ closingComplete_opt.toSeq - } else if (d.commitments.params.localParams.paysClosingFees) { + } else if (d.commitments.localChannelParams.paysClosingFees) { // we pay the closing fees, so we initiate the negotiation by sending the first closing_signed val (closingTx, closingSigned) = MutualClose.makeFirstClosingTx(channelKeys, d.commitments.latest, localShutdown.scriptPubKey, remoteShutdownScript, nodeParams.currentFeeratesForFundingClosing, nodeParams.onChainFeeConf, closeStatus.feerates_opt) goto(NEGOTIATING) using DATA_NEGOTIATING(d.commitments, localShutdown, remoteShutdown, List(List(ClosingTxProposed(closingTx, closingSigned))), bestUnpublishedClosingTx_opt = None) storing() sending sendList :+ closingSigned @@ -848,7 +856,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall case Some(c) if d.lastAnnouncement_opt.exists(_.shortChannelId == remoteAnnSigs.shortChannelId) => if (!announcementSigsSent.contains(remoteAnnSigs.shortChannelId)) { log.info("re-sending announcement_signatures for scid={}", remoteAnnSigs.shortChannelId) - val localAnnSigs_opt = c.signAnnouncement(nodeParams, d.commitments.params, channelKeys.fundingKey(c.fundingTxIndex)) + val localAnnSigs_opt = c.signAnnouncement(nodeParams, d.commitments.channelParams, channelKeys.fundingKey(c.fundingTxIndex)) localAnnSigs_opt.foreach(annSigs => announcementSigsSent += annSigs.shortChannelId) stay() sending localAnnSigs_opt.toSeq } else { @@ -856,7 +864,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall stay() } case Some(c) => - c.signAnnouncement(nodeParams, d.commitments.params, channelKeys.fundingKey(c.fundingTxIndex)) match { + c.signAnnouncement(nodeParams, d.commitments.channelParams, channelKeys.fundingKey(c.fundingTxIndex)) match { case Some(localAnnSigs) => val fundingPubKey = channelKeys.fundingKey(c.fundingTxIndex).publicKey val channelAnn = Announcements.makeChannelAnnouncement(nodeParams.chainHash, localAnnSigs.shortChannelId, nodeParams.nodeId, remoteNodeId, fundingPubKey, c.remoteFundingPubKey, localAnnSigs.nodeSignature, remoteAnnSigs.nodeSignature, localAnnSigs.bitcoinSignature, remoteAnnSigs.bitcoinSignature) @@ -866,7 +874,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall log.info("announcing channelId={} on the network with shortChannelId={} for fundingTxIndex={}", d.channelId, localAnnSigs.shortChannelId, c.fundingTxIndex) // We generate a new channel_update because we can now use the scid of the announced funding transaction. val scidForChannelUpdate = Helpers.scidForChannelUpdate(Some(channelAnn), d.aliases.localAlias) - val channelUpdate = Announcements.makeChannelUpdate(nodeParams, remoteNodeId, scidForChannelUpdate, d.commitments.params, d.channelUpdate.relayFees, Helpers.maxHtlcAmount(nodeParams, d.commitments), enable = true) + val channelUpdate = Announcements.makeChannelUpdate(nodeParams, remoteNodeId, scidForChannelUpdate, d.commitments.channelParams, d.channelUpdate.relayFees, Helpers.maxHtlcAmount(nodeParams, d.commitments), enable = true) context.system.eventStream.publish(ShortChannelIdAssigned(self, d.channelId, Some(channelAnn), d.aliases, remoteNodeId)) // We use goto() instead of stay() because we want to fire transitions. goto(NORMAL) using d.copy(lastAnnouncement_opt = Some(channelAnn), channelUpdate = channelUpdate) storing() @@ -888,7 +896,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall } case Event(c: CMD_UPDATE_RELAY_FEE, d: DATA_NORMAL) => - val channelUpdate1 = Announcements.makeChannelUpdate(nodeParams, remoteNodeId, scidForChannelUpdate(d), d.commitments.params, Relayer.RelayFees(c.feeBase, c.feeProportionalMillionths), Helpers.maxHtlcAmount(nodeParams, d.commitments), enable = true) + val channelUpdate1 = Announcements.makeChannelUpdate(nodeParams, remoteNodeId, scidForChannelUpdate(d), d.commitments.channelParams, Relayer.RelayFees(c.feeBase, c.feeProportionalMillionths), Helpers.maxHtlcAmount(nodeParams, d.commitments), enable = true) log.debug(s"updating relay fees: prev={} next={}", d.channelUpdate.toStringShort, channelUpdate1.toStringShort) val replyTo = if (c.replyTo == ActorRef.noSender) sender() else c.replyTo replyTo ! RES_SUCCESS(c, d.channelId) @@ -897,7 +905,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall case Event(BroadcastChannelUpdate(reason), d: DATA_NORMAL) => val age = TimestampSecond.now() - d.channelUpdate.timestamp - val channelUpdate1 = Announcements.makeChannelUpdate(nodeParams, remoteNodeId, scidForChannelUpdate(d), d.commitments.params, d.channelUpdate.relayFees, Helpers.maxHtlcAmount(nodeParams, d.commitments), enable = true) + val channelUpdate1 = Announcements.makeChannelUpdate(nodeParams, remoteNodeId, scidForChannelUpdate(d), d.commitments.channelParams, d.channelUpdate.relayFees, Helpers.maxHtlcAmount(nodeParams, d.commitments), enable = true) reason match { case Reconnected if d.commitments.announceChannel && Announcements.areSame(channelUpdate1, d.channelUpdate) && age < REFRESH_CHANNEL_UPDATE_INTERVAL => // we already sent an identical channel_update not long ago (flapping protection in case we keep being disconnected/reconnected) @@ -919,7 +927,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall } case Event(cmd: CMD_SPLICE, d: DATA_NORMAL) => - if (!d.commitments.params.remoteParams.initFeatures.hasFeature(Features.SplicePrototype)) { + if (!d.commitments.remoteChannelParams.initFeatures.hasFeature(Features.SplicePrototype)) { log.warning("cannot initiate splice, peer doesn't support splicing") cmd.replyTo ! RES_FAILURE(cmd, CommandUnavailableInThisState(d.channelId, "splice", NORMAL)) stay() @@ -1008,7 +1016,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall stay() using d.copy(spliceStatus = SpliceStatus.NegotiatingQuiescence(None, QuiescenceNegotiation.NonInitiator.ReceivedStfu(msg))) case SpliceStatus.NegotiatingQuiescence(Some(cmd), QuiescenceNegotiation.Initiator.SentStfu(_)) => // If both sides send stfu at the same time, the quiescence initiator is the channel opener. - if (!msg.initiator || d.commitments.params.localParams.isChannelOpener) { + if (!msg.initiator || d.commitments.localChannelParams.isChannelOpener) { cmd match { case cmd: CMD_SPLICE => initiateSplice(cmd, d) match { case Left(f) => @@ -1064,7 +1072,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall } else { val parentCommitment = d.commitments.latest.commitment val localFundingPubKey = channelKeys.fundingKey(parentCommitment.fundingTxIndex + 1).publicKey - val fundingScript = Funding.makeFundingScript(localFundingPubKey, msg.fundingPubKey, d.commitments.params.commitmentFormat).pubkeyScript + val fundingScript = Funding.makeFundingScript(localFundingPubKey, msg.fundingPubKey, d.commitments.channelParams.commitmentFormat).pubkeyScript LiquidityAds.validateRequest(nodeParams.privateKey, d.channelId, fundingScript, msg.feerate, isChannelCreation = false, msg.requestFunding_opt, nodeParams.liquidityAdsConfig.rates_opt, msg.useFeeCredit_opt) match { case Left(t) => log.warning("rejecting splice request with invalid liquidity ads: {}", t.getMessage) @@ -1088,7 +1096,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall remoteFundingPubKey = msg.fundingPubKey, localOutputs = Nil, lockTime = msg.lockTime, - dustLimit = d.commitments.params.localParams.dustLimit.max(d.commitments.params.remoteParams.dustLimit), + dustLimit = d.commitments.channelParams.localCommitParams.dustLimit.max(d.commitments.channelParams.remoteCommitParams.dustLimit), targetFeerate = msg.feerate, requireConfirmedInputs = RequireConfirmedInputs(forLocal = msg.requireConfirmedInputs, forRemote = spliceAck.requireConfirmedInputs) ) @@ -1096,7 +1104,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall val txBuilder = context.spawnAnonymous(InteractiveTxBuilder( sessionId, nodeParams, fundingParams, - channelParams = d.commitments.params, + channelParams = d.commitments.channelParams, channelKeys = channelKeys, purpose = InteractiveTxBuilder.SpliceTx(parentCommitment, d.commitments.changes), localPushAmount = spliceAck.pushAmount, remotePushAmount = msg.pushAmount, @@ -1132,11 +1140,11 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall remoteFundingPubKey = msg.fundingPubKey, localOutputs = cmd.spliceOutputs, lockTime = spliceInit.lockTime, - dustLimit = d.commitments.params.localParams.dustLimit.max(d.commitments.params.remoteParams.dustLimit), + dustLimit = d.commitments.channelParams.localCommitParams.dustLimit.max(d.commitments.channelParams.remoteCommitParams.dustLimit), targetFeerate = spliceInit.feerate, requireConfirmedInputs = RequireConfirmedInputs(forLocal = msg.requireConfirmedInputs, forRemote = spliceInit.requireConfirmedInputs) ) - val fundingScript = Funding.makeFundingScript(spliceInit.fundingPubKey, msg.fundingPubKey, d.commitments.params.commitmentFormat).pubkeyScript + val fundingScript = Funding.makeFundingScript(spliceInit.fundingPubKey, msg.fundingPubKey, d.commitments.channelParams.commitmentFormat).pubkeyScript LiquidityAds.validateRemoteFunding(spliceInit.requestFunding_opt, remoteNodeId, d.channelId, fundingScript, msg.fundingContribution, spliceInit.feerate, isChannelCreation = false, msg.willFund_opt) match { case Left(t) => log.info("rejecting splice attempt: invalid liquidity ads response ({})", t.getMessage) @@ -1147,7 +1155,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall val txBuilder = context.spawnAnonymous(InteractiveTxBuilder( sessionId, nodeParams, fundingParams, - channelParams = d.commitments.params, + channelParams = d.commitments.channelParams, channelKeys = channelKeys, purpose = InteractiveTxBuilder.SpliceTx(parentCommitment, d.commitments.changes), localPushAmount = cmd.pushAmount, remotePushAmount = msg.pushAmount, @@ -1216,7 +1224,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall val txBuilder = context.spawnAnonymous(InteractiveTxBuilder( sessionId, nodeParams, fundingParams, - channelParams = d.commitments.params, + channelParams = d.commitments.channelParams, channelKeys = channelKeys, purpose = rbf, localPushAmount = 0 msat, remotePushAmount = 0 msat, @@ -1270,7 +1278,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall val txBuilder = context.spawnAnonymous(InteractiveTxBuilder( sessionId, nodeParams, fundingParams, - channelParams = d.commitments.params, + channelParams = d.commitments.channelParams, channelKeys = channelKeys, purpose = rbf, localPushAmount = 0 msat, remotePushAmount = 0 msat, @@ -1341,7 +1349,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall cmd_opt.foreach(cmd => cmd.replyTo ! RES_SPLICE(fundingTxIndex = signingSession.fundingTxIndex, signingSession.fundingTx.txId, signingSession.fundingParams.fundingAmount, signingSession.localCommit.fold(_.spec, _.spec).toLocal)) remoteCommitSig_opt.foreach(self ! _) liquidityPurchase_opt.collect { - case purchase if !signingSession.fundingParams.isInitiator => peer ! LiquidityPurchaseSigned(d.channelId, signingSession.fundingTx.txId, signingSession.fundingTxIndex, d.commitments.params.remoteParams.htlcMinimum, purchase) + case purchase if !signingSession.fundingParams.isInitiator => peer ! LiquidityPurchaseSigned(d.channelId, signingSession.fundingTx.txId, signingSession.fundingTxIndex, d.commitments.channelParams.remoteCommitParams.htlcMinimum, purchase) } val d1 = d.copy(spliceStatus = SpliceStatus.SpliceWaitingForSigs(signingSession)) stay() using d1 storing() sending commitSig @@ -1386,7 +1394,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall rollbackFundingAttempt(signingSession.fundingTx.tx, previousTxs = Seq.empty) // no splice rbf yet stay() using d.copy(spliceStatus = SpliceStatus.SpliceAborted) sending TxAbort(d.channelId, f.getMessage) case Right(signingSession1) => - val minDepth_opt = d.commitments.params.minDepth(nodeParams.channelConf.minDepth) + val minDepth_opt = d.commitments.channelParams.minDepth(nodeParams.channelConf.minDepth) watchFundingConfirmed(signingSession.fundingTx.txId, minDepth_opt, delay_opt = None) val commitments1 = d.commitments.add(signingSession1.commitment) val d1 = d.copy(commitments = commitments1, spliceStatus = SpliceStatus.NoSplice) @@ -1428,7 +1436,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall // If the channel is public and we've received the remote splice_locked, we send our announcement_signatures // in order to generate the channel_announcement. val remoteLocked = commitment.fundingTxIndex == 0 || d.commitments.all.exists(c => c.fundingTxId == commitment.fundingTxId && c.remoteFundingStatus == RemoteFundingStatus.Locked) - val localAnnSigs_opt = if (d.commitments.announceChannel && remoteLocked) commitment.signAnnouncement(nodeParams, commitments1.params, channelKeys.fundingKey(commitment.fundingTxIndex)) else None + val localAnnSigs_opt = if (d.commitments.announceChannel && remoteLocked) commitment.signAnnouncement(nodeParams, commitments1.channelParams, channelKeys.fundingKey(commitment.fundingTxIndex)) else None localAnnSigs_opt match { case Some(localAnnSigs) => announcementSigsSent += localAnnSigs.shortChannelId @@ -1463,7 +1471,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall None } // If the commitment is confirmed, we were waiting to receive the remote splice_locked before sending our announcement_signatures. - val localAnnSigs_opt = commitment.signAnnouncement(nodeParams, commitments1.params, channelKeys.fundingKey(commitment.fundingTxIndex)) match { + val localAnnSigs_opt = commitment.signAnnouncement(nodeParams, commitments1.channelParams, channelKeys.fundingKey(commitment.fundingTxIndex)) match { case Some(localAnnSigs) if !announcementSigsSent.contains(localAnnSigs.shortChannelId) => announcementSigsSent += localAnnSigs.shortChannelId // If we've already received the remote announcement_signatures, we're now ready to process them. @@ -1491,7 +1499,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall // if we have pending unsigned htlcs, then we cancel them and generate an update with the disabled flag set, that will be returned to the sender in a temporary channel failure if (d.commitments.changes.localChanges.proposed.collectFirst { case add: UpdateAddHtlc => add }.isDefined) { log.debug("updating channel_update announcement (reason=disabled)") - val channelUpdate1 = Announcements.makeChannelUpdate(nodeParams, remoteNodeId, scidForChannelUpdate(d), d.commitments.params, d.channelUpdate.relayFees, Helpers.maxHtlcAmount(nodeParams, d.commitments), enable = false) + val channelUpdate1 = Announcements.makeChannelUpdate(nodeParams, remoteNodeId, scidForChannelUpdate(d), d.commitments.channelParams, d.channelUpdate.relayFees, Helpers.maxHtlcAmount(nodeParams, d.commitments), enable = false) // NB: the htlcs stay in the commitments.localChange, they will be cleaned up after reconnection d.commitments.changes.localChanges.proposed.collect { case add: UpdateAddHtlc => relayer ! RES_ADD_SETTLED(d.commitments.originChannels(add.id), add, HtlcResult.DisconnectedBeforeSigned(channelUpdate1)) @@ -1596,8 +1604,8 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall val nextCommitNumber = nextRemoteCommit.index // we persist htlc data in order to be able to claim htlc outputs in case a revoked tx is published by our // counterparty, so only htlcs above remote's dust_limit matter - val trimmedHtlcs = Transactions.trimOfferedHtlcs(d.commitments.params.remoteParams.dustLimit, nextRemoteCommit.spec, d.commitments.params.commitmentFormat) ++ - Transactions.trimReceivedHtlcs(d.commitments.params.remoteParams.dustLimit, nextRemoteCommit.spec, d.commitments.params.commitmentFormat) + val trimmedHtlcs = Transactions.trimOfferedHtlcs(d.commitments.channelParams.remoteCommitParams.dustLimit, nextRemoteCommit.spec, d.commitments.channelParams.commitmentFormat) ++ + Transactions.trimReceivedHtlcs(d.commitments.channelParams.remoteCommitParams.dustLimit, nextRemoteCommit.spec, d.commitments.channelParams.commitmentFormat) trimmedHtlcs.map(_.add).foreach { htlc => log.debug(s"adding paymentHash=${htlc.paymentHash} cltvExpiry=${htlc.cltvExpiry} to htlcs db for commitNumber=$nextCommitNumber") nodeParams.db.channels.addHtlcInfo(d.channelId, nextCommitNumber, htlc.paymentHash, htlc.cltvExpiry) @@ -1620,10 +1628,10 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall log.debug("received a new sig:\n{}", commitments1.latest.specs2String) context.system.eventStream.publish(ChannelSignatureReceived(self, commitments1)) if (commitments1.hasNoPendingHtlcsOrFeeUpdate) { - if (Features.canUseFeature(d.commitments.params.localParams.initFeatures, d.commitments.params.remoteParams.initFeatures, Features.SimpleClose)) { + if (Features.canUseFeature(d.commitments.localChannelParams.initFeatures, d.commitments.remoteChannelParams.initFeatures, Features.SimpleClose)) { val (d1, closingComplete_opt) = startSimpleClose(d.commitments, localShutdown, remoteShutdown, closeStatus) goto(NEGOTIATING_SIMPLE) using d1 storing() sending revocation +: closingComplete_opt.toSeq - } else if (d.commitments.params.localParams.paysClosingFees) { + } else if (d.commitments.localChannelParams.paysClosingFees) { // we pay the closing fees, so we initiate the negotiation by sending the first closing_signed val (closingTx, closingSigned) = MutualClose.makeFirstClosingTx(channelKeys, commitments1.latest, localShutdown.scriptPubKey, remoteShutdown.scriptPubKey, nodeParams.currentFeeratesForFundingClosing, nodeParams.onChainFeeConf, d.closeStatus.feerates_opt) goto(NEGOTIATING) using DATA_NEGOTIATING(commitments1, localShutdown, remoteShutdown, List(List(ClosingTxProposed(closingTx, closingSigned))), bestUnpublishedClosingTx_opt = None) storing() sending revocation :: closingSigned :: Nil @@ -1663,10 +1671,10 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall } if (commitments1.hasNoPendingHtlcsOrFeeUpdate) { log.debug("switching to NEGOTIATING spec:\n{}", commitments1.latest.specs2String) - if (Features.canUseFeature(d.commitments.params.localParams.initFeatures, d.commitments.params.remoteParams.initFeatures, Features.SimpleClose)) { + if (Features.canUseFeature(d.commitments.localChannelParams.initFeatures, d.commitments.remoteChannelParams.initFeatures, Features.SimpleClose)) { val (d1, closingComplete_opt) = startSimpleClose(d.commitments, localShutdown, remoteShutdown, closeStatus) goto(NEGOTIATING_SIMPLE) using d1 storing() sending closingComplete_opt.toSeq - } else if (d.commitments.params.localParams.paysClosingFees) { + } else if (d.commitments.localChannelParams.paysClosingFees) { // we pay the closing fees, so we initiate the negotiation by sending the first closing_signed val (closingTx, closingSigned) = MutualClose.makeFirstClosingTx(channelKeys, commitments1.latest, localShutdown.scriptPubKey, remoteShutdown.scriptPubKey, nodeParams.currentFeeratesForFundingClosing, nodeParams.onChainFeeConf, d.closeStatus.feerates_opt) goto(NEGOTIATING) using DATA_NEGOTIATING(commitments1, localShutdown, remoteShutdown, List(List(ClosingTxProposed(closingTx, closingSigned))), bestUnpublishedClosingTx_opt = None) storing() sending closingSigned @@ -1696,7 +1704,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall case Event(c: CurrentFeerates.BitcoinCore, d: DATA_SHUTDOWN) => handleCurrentFeerate(c, d) case Event(c: CMD_CLOSE, d: DATA_SHUTDOWN) => - val useSimpleClose = Features.canUseFeature(d.commitments.params.localParams.initFeatures, d.commitments.params.remoteParams.initFeatures, Features.SimpleClose) + val useSimpleClose = Features.canUseFeature(d.commitments.localChannelParams.initFeatures, d.commitments.remoteChannelParams.initFeatures, Features.SimpleClose) val localShutdown_opt = c.scriptPubKey match { case Some(scriptPubKey) if scriptPubKey != d.localShutdown.scriptPubKey && useSimpleClose => Some(Shutdown(d.channelId, scriptPubKey)) case _ => None @@ -1750,7 +1758,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall handleMutualClose(signedClosingTx, Left(d.copy(bestUnpublishedClosingTx_opt = Some(signedClosingTx)))) sending closingSignedRemoteFees } else { c.feeRange_opt match { - case Some(ClosingSignedTlv.FeeRange(minFee, maxFee)) if !d.commitments.params.localParams.paysClosingFees => + case Some(ClosingSignedTlv.FeeRange(minFee, maxFee)) if !d.commitments.localChannelParams.paysClosingFees => // if we are not paying the closing fees and they proposed a fee range, we pick a value in that range and they should accept it without further negotiation // we don't care much about the closing fee since they're paying it (not us) and we can use CPFP if we want to speed up confirmation val localClosingFees = MutualClose.firstClosingFee(d.commitments.latest, d.localShutdown.scriptPubKey, d.remoteShutdown.scriptPubKey, nodeParams.currentFeeratesForFundingClosing, nodeParams.onChainFeeConf) @@ -1908,7 +1916,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall // We are already watching the corresponding outputs: no need to set additional watches. d.localCommitPublished.foreach(lcp => { val commitKeys = commitment.localKeys(channelKeys) - Closing.LocalClose.claimHtlcsWithPreimage(channelKeys, commitKeys, commitment, c.r).foreach(htlcTx => commitment.params.commitmentFormat match { + Closing.LocalClose.claimHtlcsWithPreimage(channelKeys, commitKeys, commitment, c.r).foreach(htlcTx => commitment.commitmentFormat match { case Transactions.DefaultCommitmentFormat => txPublisher ! TxPublisher.PublishFinalTx(htlcTx, Some(lcp.commitTx.txid)) case _: Transactions.AnchorOutputsCommitmentFormat | _: Transactions.SimpleTaprootChannelCommitmentFormat => @@ -2127,14 +2135,14 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall revokedCommitPublished = d.revokedCommitPublished.map(rvk => { // If the tx is one of our peer's HTLC txs, they were able to claim the output before us. // In that case, we immediately publish a penalty transaction spending their HTLC tx to steal their funds. - val (rvk1, penaltyTxs) = Closing.RevokedClose.claimHtlcTxOutputs(d.commitments.params, channelKeys, d.commitments.remotePerCommitmentSecrets, rvk, tx, nodeParams.currentBitcoinCoreFeerates, d.finalScriptPubKey) + val (rvk1, penaltyTxs) = Closing.RevokedClose.claimHtlcTxOutputs(d.commitments.channelParams, channelKeys, d.commitments.remotePerCommitmentSecrets, rvk, tx, nodeParams.currentBitcoinCoreFeerates, d.finalScriptPubKey) doPublish(rvk1, penaltyTxs) Closing.updateIrrevocablySpent(rvk1, tx) }) ) // if the local commitment tx just got confirmed, let's send an event telling when we will get the main output refund if (d1.localCommitPublished.exists(_.commitTx.txid == tx.txid)) { - context.system.eventStream.publish(LocalCommitConfirmed(self, remoteNodeId, d.channelId, blockHeight + d.commitments.params.remoteParams.toSelfDelay.toInt)) + context.system.eventStream.publish(LocalCommitConfirmed(self, remoteNodeId, d.channelId, blockHeight + d.commitments.channelParams.localCommitParams.toSelfDelay.toInt)) } // if the local or remote commitment tx just got confirmed, we abandon anchor transactions that were created based // on the other commitment: they will never confirm so we must free their wallet inputs. @@ -2218,7 +2226,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall case Event(c: CMD_CLOSE, d: DATA_CLOSING) => handleCommandError(ClosingAlreadyInProgress(d.channelId), c) case Event(c: CMD_BUMP_FORCE_CLOSE_FEE, d: DATA_CLOSING) => - d.commitments.params.commitmentFormat match { + d.commitments.channelParams.commitmentFormat match { case commitmentFormat: Transactions.AnchorOutputsCommitmentFormat => val commitment = d.commitments.latest val fundingKey = channelKeys.fundingKey(commitment.fundingTxIndex) @@ -2371,7 +2379,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall } case _ => Set.empty } - val lastFundingLockedTlvs: Set[ChannelReestablishTlv] = if (d.commitments.params.remoteParams.initFeatures.hasFeature(Features.SplicePrototype)) { + val lastFundingLockedTlvs: Set[ChannelReestablishTlv] = if (d.commitments.remoteChannelParams.initFeatures.hasFeature(Features.SplicePrototype)) { d.commitments.lastLocalLocked_opt.map(c => ChannelReestablishTlv.MyCurrentFundingLockedTlv(c.fundingTxId)).toSet ++ d.commitments.lastRemoteLocked_opt.map(c => ChannelReestablishTlv.YourLastFundingLockedTlv(c.fundingTxId)).toSet } else Set.empty @@ -2435,7 +2443,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall if (channelReestablish.nextLocalCommitmentNumber == 0) { // They haven't received our commit_sig: we retransmit it. // We're also waiting for signatures from them, and will send our tx_signatures once we receive them. - val commitSig = signingSession.remoteCommit.sign(d.commitments.params, channelKeys, signingSession.fundingTxIndex, signingSession.fundingParams.remoteFundingPubKey, signingSession.commitInput) + val commitSig = signingSession.remoteCommit.sign(d.commitments.channelParams, channelKeys, signingSession.fundingTxIndex, signingSession.fundingParams.remoteFundingPubKey, signingSession.commitInput) goto(WAIT_FOR_DUAL_FUNDING_CONFIRMED) sending commitSig } else { // They have already received our commit_sig, but we were waiting for them to send either commit_sig or @@ -2446,7 +2454,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall // We've already received their commit_sig and sent our tx_signatures. We retransmit our tx_signatures // and our commit_sig if they haven't received it already. if (channelReestablish.nextLocalCommitmentNumber == 0) { - val commitSig = d.commitments.latest.remoteCommit.sign(d.commitments.params, channelKeys, d.commitments.latest.fundingTxIndex, d.commitments.latest.remoteFundingPubKey, d.commitments.latest.commitInput) + val commitSig = d.commitments.latest.remoteCommit.sign(d.commitments.channelParams, channelKeys, d.commitments.latest.fundingTxIndex, d.commitments.latest.remoteFundingPubKey, d.commitments.latest.commitInput) goto(WAIT_FOR_DUAL_FUNDING_CONFIRMED) sending Seq(commitSig, d.latestFundingTx.sharedTx.localSigs) } else { goto(WAIT_FOR_DUAL_FUNDING_CONFIRMED) sending d.latestFundingTx.sharedTx.localSigs @@ -2461,12 +2469,12 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall case Event(_: ChannelReestablish, d: DATA_WAIT_FOR_CHANNEL_READY) => log.debug("re-sending channel_ready") - val channelReady = createChannelReady(d.aliases, d.commitments.params) + val channelReady = createChannelReady(d.aliases, d.commitments.channelParams) goto(WAIT_FOR_CHANNEL_READY) sending channelReady case Event(channelReestablish: ChannelReestablish, d: DATA_WAIT_FOR_DUAL_FUNDING_READY) => log.debug("re-sending channel_ready") - val channelReady = createChannelReady(d.aliases, d.commitments.params) + val channelReady = createChannelReady(d.aliases, d.commitments.channelParams) // We've already received their commit_sig and sent our tx_signatures. We retransmit our tx_signatures // and our commit_sig if they haven't received it already. channelReestablish.nextFundingTxId_opt match { @@ -2474,7 +2482,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall d.commitments.latest.localFundingStatus.localSigs_opt match { case Some(txSigs) if channelReestablish.nextLocalCommitmentNumber == 0 => log.info("re-sending commit_sig and tx_signatures for fundingTxIndex={} fundingTxId={}", d.commitments.latest.fundingTxIndex, d.commitments.latest.fundingTxId) - val commitSig = d.commitments.latest.remoteCommit.sign(d.commitments.params, channelKeys, d.commitments.latest.fundingTxIndex, d.commitments.latest.remoteFundingPubKey, d.commitments.latest.commitInput) + val commitSig = d.commitments.latest.remoteCommit.sign(d.commitments.channelParams, channelKeys, d.commitments.latest.fundingTxIndex, d.commitments.latest.remoteFundingPubKey, d.commitments.latest.commitInput) goto(WAIT_FOR_DUAL_FUNDING_READY) sending Seq(commitSig, txSigs, channelReady) case Some(txSigs) => log.info("re-sending tx_signatures for fundingTxIndex={} fundingTxId={}", d.commitments.latest.fundingTxIndex, d.commitments.latest.fundingTxId) @@ -2500,7 +2508,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall // We only send channel_ready for initial funding transactions. case Some(c) if c.fundingTxIndex != 0 => () case Some(c) => - val remoteSpliceSupport = d.commitments.params.remoteParams.initFeatures.hasFeature(Features.SplicePrototype) + val remoteSpliceSupport = d.commitments.remoteChannelParams.initFeatures.hasFeature(Features.SplicePrototype) // If our peer has not received our channel_ready, we retransmit it. val notReceivedByRemote = remoteSpliceSupport && channelReestablish.yourLastFundingLocked_opt.isEmpty // If next_local_commitment_number is 1 in both the channel_reestablish it sent and received, then the node @@ -2518,7 +2526,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall // The funding transaction is confirmed, so we've already sent our announcement_signatures. // We haven't announced the channel yet, which means we haven't received our peer's announcement_signatures. // We retransmit our announcement_signatures to let our peer know that we're ready to announce the channel. - val localAnnSigs = c.signAnnouncement(nodeParams, d.commitments.params, channelKeys.fundingKey(c.fundingTxIndex)) + val localAnnSigs = c.signAnnouncement(nodeParams, d.commitments.channelParams, channelKeys.fundingKey(c.fundingTxIndex)) localAnnSigs.foreach(annSigs => { announcementSigsSent += annSigs.shortChannelId sendQueue = sendQueue :+ annSigs @@ -2535,7 +2543,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall // They haven't received our commit_sig: we retransmit it. // We're also waiting for signatures from them, and will send our tx_signatures once we receive them. log.info("re-sending commit_sig for splice attempt with fundingTxIndex={} fundingTxId={}", signingSession.fundingTxIndex, signingSession.fundingTx.txId) - val commitSig = signingSession.remoteCommit.sign(d.commitments.params, channelKeys, signingSession.fundingTxIndex, signingSession.fundingParams.remoteFundingPubKey, signingSession.commitInput) + val commitSig = signingSession.remoteCommit.sign(d.commitments.channelParams, channelKeys, signingSession.fundingTxIndex, signingSession.fundingParams.remoteFundingPubKey, signingSession.commitInput) sendQueue = sendQueue :+ commitSig } d.spliceStatus @@ -2546,7 +2554,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall // tx_signatures and our commit_sig if they haven't received it already. if (channelReestablish.nextLocalCommitmentNumber == d.commitments.remoteCommitIndex) { log.info("re-sending commit_sig and tx_signatures for fundingTxIndex={} fundingTxId={}", d.commitments.latest.fundingTxIndex, d.commitments.latest.fundingTxId) - val commitSig = d.commitments.latest.remoteCommit.sign(d.commitments.params, channelKeys, d.commitments.latest.fundingTxIndex, d.commitments.latest.remoteFundingPubKey, d.commitments.latest.commitInput) + val commitSig = d.commitments.latest.remoteCommit.sign(d.commitments.channelParams, channelKeys, d.commitments.latest.fundingTxIndex, d.commitments.latest.remoteFundingPubKey, d.commitments.latest.commitInput) sendQueue = sendQueue :+ commitSig :+ dfu.sharedTx.localSigs } else { log.info("re-sending tx_signatures for fundingTxIndex={} fundingTxId={}", d.commitments.latest.fundingTxIndex, d.commitments.latest.fundingTxId) @@ -2633,9 +2641,9 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall // only briefly connects and then disconnects, we may never have the opportunity to send our `update_fee`, so // we send it (if needed) when reconnected. val shutdownInProgress = d.localShutdown.nonEmpty || d.remoteShutdown.nonEmpty - if (d.commitments.params.localParams.paysCommitTxFees && !shutdownInProgress) { + if (d.commitments.localChannelParams.paysCommitTxFees && !shutdownInProgress) { val currentFeeratePerKw = d.commitments.latest.localCommit.spec.commitTxFeerate - val networkFeeratePerKw = nodeParams.onChainFeeConf.getCommitmentFeerate(nodeParams.currentBitcoinCoreFeerates, remoteNodeId, d.commitments.params.commitmentFormat, d.commitments.latest.capacity) + val networkFeeratePerKw = nodeParams.onChainFeeConf.getCommitmentFeerate(nodeParams.currentBitcoinCoreFeerates, remoteNodeId, d.commitments.channelParams.commitmentFormat, d.commitments.latest.capacity) if (nodeParams.onChainFeeConf.shouldUpdateFee(currentFeeratePerKw, networkFeeratePerKw)) { self ! CMD_UPDATE_FEE(networkFeeratePerKw, commit = true) } @@ -2677,7 +2685,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall // BOLT 2: A node if it has sent a previous shutdown MUST retransmit shutdown. // negotiation restarts from the beginning, and is initialized by the channel initiator // note: in any case we still need to keep all previously sent closing_signed, because they may publish one of them - if (d.commitments.params.localParams.paysClosingFees) { + if (d.commitments.localChannelParams.paysClosingFees) { // we could use the last closing_signed we sent, but network fees may have changed while we were offline so it is better to restart from scratch val (closingTx, closingSigned) = Closing.MutualClose.makeFirstClosingTx(channelKeys, d.commitments.latest, d.localShutdown.scriptPubKey, d.remoteShutdown.scriptPubKey, nodeParams.currentFeeratesForFundingClosing, nodeParams.onChainFeeConf, None) val closingTxProposed1 = d.closingTxProposed :+ List(ClosingTxProposed(closingTx, closingSigned)) @@ -3012,7 +3020,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall log.debug("emitting channel down event") if (d.lastAnnouncement_opt.nonEmpty) { // We tell the rest of the network that this channel shouldn't be used anymore. - val disabledUpdate = Announcements.makeChannelUpdate(nodeParams, remoteNodeId, Helpers.scidForChannelUpdate(d), d.commitments.params, d.channelUpdate.relayFees, Helpers.maxHtlcAmount(nodeParams, d.commitments), enable = false) + val disabledUpdate = Announcements.makeChannelUpdate(nodeParams, remoteNodeId, Helpers.scidForChannelUpdate(d), d.commitments.channelParams, d.channelUpdate.relayFees, Helpers.maxHtlcAmount(nodeParams, d.commitments), enable = false) context.system.eventStream.publish(LocalChannelUpdate(self, d.channelId, d.aliases, remoteNodeId, d.lastAnnouncedCommitment_opt, disabledUpdate, d.commitments)) } val lcd = LocalChannelDown(self, d.channelId, d.commitments.all.flatMap(_.shortChannelId_opt), d.aliases, remoteNodeId) @@ -3101,11 +3109,11 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall private def handleCurrentFeerate(c: CurrentFeerates, d: ChannelDataWithCommitments) = { val commitments = d.commitments.latest - val networkFeeratePerKw = nodeParams.onChainFeeConf.getCommitmentFeerate(nodeParams.currentBitcoinCoreFeerates, remoteNodeId, d.commitments.params.commitmentFormat, commitments.capacity) + val networkFeeratePerKw = nodeParams.onChainFeeConf.getCommitmentFeerate(nodeParams.currentBitcoinCoreFeerates, remoteNodeId, d.commitments.channelParams.commitmentFormat, commitments.capacity) val currentFeeratePerKw = commitments.localCommit.spec.commitTxFeerate - val shouldUpdateFee = d.commitments.params.localParams.paysCommitTxFees && nodeParams.onChainFeeConf.shouldUpdateFee(currentFeeratePerKw, networkFeeratePerKw) - val shouldClose = !d.commitments.params.localParams.paysCommitTxFees && - nodeParams.onChainFeeConf.feerateToleranceFor(d.commitments.remoteNodeId).isProposedFeerateTooLow(d.commitments.params.commitmentFormat, networkFeeratePerKw, currentFeeratePerKw) && + val shouldUpdateFee = d.commitments.localChannelParams.paysCommitTxFees && nodeParams.onChainFeeConf.shouldUpdateFee(currentFeeratePerKw, networkFeeratePerKw) + val shouldClose = !d.commitments.localChannelParams.paysCommitTxFees && + nodeParams.onChainFeeConf.feerateToleranceFor(d.commitments.remoteNodeId).isProposedFeerateTooLow(d.commitments.channelParams.commitmentFormat, networkFeeratePerKw, currentFeeratePerKw) && d.commitments.hasPendingOrProposedHtlcs // we close only if we have HTLCs potentially at risk if (shouldUpdateFee) { self ! CMD_UPDATE_FEE(networkFeeratePerKw, commit = true) @@ -3126,11 +3134,11 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall */ private def handleCurrentFeerateDisconnected(c: CurrentFeerates, d: ChannelDataWithCommitments) = { val commitments = d.commitments.latest - val networkFeeratePerKw = nodeParams.onChainFeeConf.getCommitmentFeerate(nodeParams.currentBitcoinCoreFeerates, remoteNodeId, d.commitments.params.commitmentFormat, commitments.capacity) + val networkFeeratePerKw = nodeParams.onChainFeeConf.getCommitmentFeerate(nodeParams.currentBitcoinCoreFeerates, remoteNodeId, d.commitments.channelParams.commitmentFormat, commitments.capacity) val currentFeeratePerKw = commitments.localCommit.spec.commitTxFeerate // if the network fees are too high we risk to not be able to confirm our current commitment val shouldClose = networkFeeratePerKw > currentFeeratePerKw && - nodeParams.onChainFeeConf.feerateToleranceFor(d.commitments.remoteNodeId).isProposedFeerateTooLow(d.commitments.params.commitmentFormat, networkFeeratePerKw, currentFeeratePerKw) && + nodeParams.onChainFeeConf.feerateToleranceFor(d.commitments.remoteNodeId).isProposedFeerateTooLow(d.commitments.channelParams.commitmentFormat, networkFeeratePerKw, currentFeeratePerKw) && d.commitments.hasPendingOrProposedHtlcs // we close only if we have HTLCs potentially at risk if (shouldClose) { if (nodeParams.onChainFeeConf.closeOnOfflineMismatch) { @@ -3192,7 +3200,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall if (d.channelUpdate.channelFlags.isEnabled) { // if the channel isn't disabled we generate a new channel_update log.debug("updating channel_update announcement (reason=disabled)") - val channelUpdate1 = Announcements.makeChannelUpdate(nodeParams, remoteNodeId, scidForChannelUpdate(d), d.commitments.params, d.channelUpdate.relayFees, Helpers.maxHtlcAmount(nodeParams, d.commitments), enable = false) + val channelUpdate1 = Announcements.makeChannelUpdate(nodeParams, remoteNodeId, scidForChannelUpdate(d), d.commitments.channelParams, d.channelUpdate.relayFees, Helpers.maxHtlcAmount(nodeParams, d.commitments), enable = false) // then we update the state and replay the request self forward c // we use goto() to fire transitions @@ -3205,7 +3213,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall } private def handleUpdateRelayFeeDisconnected(c: CMD_UPDATE_RELAY_FEE, d: DATA_NORMAL) = { - val channelUpdate1 = Announcements.makeChannelUpdate(nodeParams, remoteNodeId, scidForChannelUpdate(d), d.commitments.params, Relayer.RelayFees(c.feeBase, c.feeProportionalMillionths), Helpers.maxHtlcAmount(nodeParams, d.commitments), enable = false) + val channelUpdate1 = Announcements.makeChannelUpdate(nodeParams, remoteNodeId, scidForChannelUpdate(d), d.commitments.channelParams, Relayer.RelayFees(c.feeBase, c.feeProportionalMillionths), Helpers.maxHtlcAmount(nodeParams, d.commitments), enable = false) log.debug(s"updating relay fees: prev={} next={}", d.channelUpdate.toStringShort, channelUpdate1.toStringShort) val replyTo = if (c.replyTo == ActorRef.noSender) sender() else c.replyTo replyTo ! RES_SUCCESS(c, d.channelId) @@ -3323,13 +3331,13 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall spliceInAmount = cmd.additionalLocalFunding, spliceOut = cmd.spliceOutputs, targetFeerate = targetFeerate) - val commitTxFees = if (d.commitments.params.localParams.paysCommitTxFees) { - Transactions.commitTxTotalCost(d.commitments.params.remoteParams.dustLimit, parentCommitment.remoteCommit.spec, d.commitments.params.commitmentFormat) + val commitTxFees = if (d.commitments.localChannelParams.paysCommitTxFees) { + Transactions.commitTxTotalCost(d.commitments.channelParams.remoteCommitParams.dustLimit, parentCommitment.remoteCommit.spec, d.commitments.channelParams.commitmentFormat) } else { 0.sat } - if (fundingContribution < 0.sat && parentCommitment.localCommit.spec.toLocal + fundingContribution < parentCommitment.localChannelReserve(d.commitments.params).max(commitTxFees)) { - log.warning(s"cannot do splice: insufficient funds (commitTxFees=$commitTxFees reserve=${parentCommitment.localChannelReserve(d.commitments.params)})") + if (fundingContribution < 0.sat && parentCommitment.localCommit.spec.toLocal + fundingContribution < parentCommitment.localChannelReserve(d.commitments.channelParams).max(commitTxFees)) { + log.warning(s"cannot do splice: insufficient funds (commitTxFees=$commitTxFees reserve=${parentCommitment.localChannelReserve(d.commitments.channelParams)})") Left(InvalidSpliceRequest(d.channelId)) } else if (cmd.spliceOut_opt.map(_.scriptPubKey).exists(!MutualClose.isValidFinalScriptPubkey(_, allowAnySegwit = true, allowOpReturn = false))) { log.warning("cannot do splice: invalid splice-out script") @@ -3353,13 +3361,13 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall getSpliceRbfContext(Some(cmd), d).flatMap(rbf => { // We use the same contribution as the previous splice attempt. val fundingContribution = rbf.latestFundingTx.fundingParams.localContribution - val commitTxFees = if (d.commitments.params.localParams.paysCommitTxFees) { - Transactions.commitTxTotalCost(d.commitments.params.remoteParams.dustLimit, rbf.parentCommitment.remoteCommit.spec, d.commitments.params.commitmentFormat) + val commitTxFees = if (d.commitments.localChannelParams.paysCommitTxFees) { + Transactions.commitTxTotalCost(d.commitments.channelParams.remoteCommitParams.dustLimit, rbf.parentCommitment.remoteCommit.spec, d.commitments.channelParams.commitmentFormat) } else { 0.sat } - if (fundingContribution < 0.sat && rbf.parentCommitment.localCommit.spec.toLocal + fundingContribution < rbf.parentCommitment.localChannelReserve(d.commitments.params).max(commitTxFees)) { - log.warning(s"cannot do rbf: insufficient funds (commitTxFees=$commitTxFees reserve=${rbf.parentCommitment.localChannelReserve(d.commitments.params)})") + if (fundingContribution < 0.sat && rbf.parentCommitment.localCommit.spec.toLocal + fundingContribution < rbf.parentCommitment.localChannelReserve(d.commitments.channelParams).max(commitTxFees)) { + log.warning(s"cannot do rbf: insufficient funds (commitTxFees=$commitTxFees reserve=${rbf.parentCommitment.localChannelReserve(d.commitments.channelParams)})") Left(InvalidSpliceRequest(d.channelId)) } else { val txInitRbf = TxInitRbf(d.channelId, cmd.lockTime, cmd.targetFeerate, fundingContribution, rbf.latestFundingTx.fundingParams.requireConfirmedInputs.forRemote, cmd.requestFunding_opt) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/ChannelOpenDualFunded.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/ChannelOpenDualFunded.scala index 28f900924e..e89ae08750 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/ChannelOpenDualFunded.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/ChannelOpenDualFunded.scala @@ -105,7 +105,7 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers { when(WAIT_FOR_INIT_DUAL_FUNDED_CHANNEL)(handleExceptions { case Event(input: INPUT_INIT_CHANNEL_INITIATOR, _) => val fundingPubKey = channelKeys.fundingKey(fundingTxIndex = 0).publicKey - val upfrontShutdownScript_opt = input.localParams.upfrontShutdownScript_opt.map(scriptPubKey => ChannelTlv.UpfrontShutdownScriptTlv(scriptPubKey)) + val upfrontShutdownScript_opt = input.localChannelParams.upfrontShutdownScript_opt.map(scriptPubKey => ChannelTlv.UpfrontShutdownScriptTlv(scriptPubKey)) val tlvs: Set[OpenDualFundedChannelTlv] = Set( upfrontShutdownScript_opt, Some(ChannelTlv.ChannelTypeTlv(input.channelType)), @@ -119,15 +119,15 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers { fundingFeerate = input.fundingTxFeerate, commitmentFeerate = input.commitTxFeerate, fundingAmount = input.fundingAmount, - dustLimit = input.localParams.dustLimit, - maxHtlcValueInFlightMsat = input.localParams.maxHtlcValueInFlightMsat, - htlcMinimum = input.localParams.htlcMinimum, - toSelfDelay = input.localParams.toSelfDelay, - maxAcceptedHtlcs = input.localParams.maxAcceptedHtlcs, + dustLimit = input.proposedCommitParams.localDustLimit, + maxHtlcValueInFlightMsat = input.proposedCommitParams.localMaxHtlcValueInFlight, + htlcMinimum = input.proposedCommitParams.localHtlcMinimum, + toSelfDelay = input.proposedCommitParams.toRemoteDelay, + maxAcceptedHtlcs = input.proposedCommitParams.localMaxAcceptedHtlcs, lockTime = nodeParams.currentBlockHeight.toLong, fundingPubkey = fundingPubKey, revocationBasepoint = channelKeys.revocationBasePoint, - paymentBasepoint = input.localParams.walletStaticPaymentBasepoint.getOrElse(channelKeys.paymentBasePoint), + paymentBasepoint = input.localChannelParams.walletStaticPaymentBasepoint.getOrElse(channelKeys.paymentBasePoint), delayedPaymentBasepoint = channelKeys.delayedPaymentBasePoint, htlcBasepoint = channelKeys.htlcBasePoint, firstPerCommitmentPoint = channelKeys.commitmentPoint(0), @@ -139,36 +139,32 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers { when(WAIT_FOR_OPEN_DUAL_FUNDED_CHANNEL)(handleExceptions { case Event(open: OpenDualFundedChannel, d: DATA_WAIT_FOR_OPEN_DUAL_FUNDED_CHANNEL) => - import d.init.{localParams, remoteInit} val localFundingPubkey = channelKeys.fundingKey(fundingTxIndex = 0).publicKey val fundingScript = Funding.makeFundingScript(localFundingPubkey, open.fundingPubkey, d.init.channelType.commitmentFormat).pubkeyScript - Helpers.validateParamsDualFundedNonInitiator(nodeParams, d.init.channelType, open, fundingScript, remoteNodeId, localParams.initFeatures, remoteInit.features, d.init.fundingContribution_opt) match { + Helpers.validateParamsDualFundedNonInitiator(nodeParams, d.init.channelType, open, fundingScript, remoteNodeId, d.init.localChannelParams.initFeatures, d.init.remoteInit.features, d.init.fundingContribution_opt) match { case Left(t) => handleLocalError(t, d, Some(open)) case Right((channelFeatures, remoteShutdownScript, willFund_opt)) => context.system.eventStream.publish(ChannelCreated(self, peer, remoteNodeId, isOpener = false, open.temporaryChannelId, open.commitmentFeerate, Some(open.fundingFeerate))) - val remoteParams = RemoteParams( + val remoteChannelParams = RemoteChannelParams( nodeId = remoteNodeId, dustLimit = open.dustLimit, maxHtlcValueInFlightMsat = open.maxHtlcValueInFlightMsat, initialRequestedChannelReserve_opt = None, // channel reserve will be computed based on channel capacity htlcMinimum = open.htlcMinimum, - toSelfDelay = open.toSelfDelay, + toRemoteDelay = open.toSelfDelay, maxAcceptedHtlcs = open.maxAcceptedHtlcs, revocationBasepoint = open.revocationBasepoint, paymentBasepoint = open.paymentBasepoint, delayedPaymentBasepoint = open.delayedPaymentBasepoint, htlcBasepoint = open.htlcBasepoint, - initFeatures = remoteInit.features, + initFeatures = d.init.remoteInit.features, upfrontShutdownScript_opt = remoteShutdownScript) - log.debug("remote params: {}", remoteParams) // We've exchanged open_channel2 and accept_channel2, we now know the final channelId. val channelId = Helpers.computeChannelId(open.revocationBasepoint, channelKeys.revocationBasePoint) - val channelParams = ChannelParams(channelId, d.init.channelConfig, channelFeatures, localParams, remoteParams, open.channelFlags) + val channelParams = ChannelParams(channelId, d.init.channelConfig, channelFeatures, d.init.localChannelParams, remoteChannelParams, open.channelFlags) val localAmount = d.init.fundingContribution_opt.map(_.fundingAmount).getOrElse(0 sat) - val minDepth_opt = channelParams.minDepth(nodeParams.channelConf.minDepth) - val upfrontShutdownScript_opt = localParams.upfrontShutdownScript_opt.map(scriptPubKey => ChannelTlv.UpfrontShutdownScriptTlv(scriptPubKey)) val tlvs: Set[AcceptDualFundedChannelTlv] = Set( - upfrontShutdownScript_opt, + d.init.localChannelParams.upfrontShutdownScript_opt.map(scriptPubKey => ChannelTlv.UpfrontShutdownScriptTlv(scriptPubKey)), Some(ChannelTlv.ChannelTypeTlv(d.init.channelType)), if (d.init.requireConfirmedInputs) Some(ChannelTlv.RequireConfirmedInputsTlv()) else None, willFund_opt.map(l => ChannelTlv.ProvideFundingTlv(l.willFund)), @@ -178,15 +174,15 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers { val accept = AcceptDualFundedChannel( temporaryChannelId = open.temporaryChannelId, fundingAmount = localAmount, - dustLimit = localParams.dustLimit, - maxHtlcValueInFlightMsat = localParams.maxHtlcValueInFlightMsat, - htlcMinimum = localParams.htlcMinimum, - minimumDepth = minDepth_opt.getOrElse(0).toLong, - toSelfDelay = localParams.toSelfDelay, - maxAcceptedHtlcs = localParams.maxAcceptedHtlcs, + dustLimit = d.init.proposedCommitParams.localDustLimit, + maxHtlcValueInFlightMsat = d.init.proposedCommitParams.localMaxHtlcValueInFlight, + htlcMinimum = d.init.proposedCommitParams.localHtlcMinimum, + minimumDepth = channelParams.minDepth(nodeParams.channelConf.minDepth).getOrElse(0).toLong, + toSelfDelay = d.init.proposedCommitParams.toRemoteDelay, + maxAcceptedHtlcs = d.init.proposedCommitParams.localMaxAcceptedHtlcs, fundingPubkey = localFundingPubkey, revocationBasepoint = channelKeys.revocationBasePoint, - paymentBasepoint = localParams.walletStaticPaymentBasepoint.getOrElse(channelKeys.paymentBasePoint), + paymentBasepoint = d.init.localChannelParams.walletStaticPaymentBasepoint.getOrElse(channelKeys.paymentBasePoint), delayedPaymentBasepoint = channelKeys.delayedPaymentBasePoint, htlcBasepoint = channelKeys.htlcBasePoint, firstPerCommitmentPoint = channelKeys.commitmentPoint(0), @@ -198,7 +194,7 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers { // We start the interactive-tx funding protocol. val fundingParams = InteractiveTxParams( channelId = channelId, - isInitiator = localParams.isChannelOpener, + isInitiator = d.init.localChannelParams.isChannelOpener, localContribution = accept.fundingAmount, remoteContribution = open.fundingAmount, sharedInput_opt = None, @@ -230,8 +226,7 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers { when(WAIT_FOR_ACCEPT_DUAL_FUNDED_CHANNEL)(handleExceptions { case Event(accept: AcceptDualFundedChannel, d: DATA_WAIT_FOR_ACCEPT_DUAL_FUNDED_CHANNEL) => - import d.init.{localParams, remoteInit} - Helpers.validateParamsDualFundedInitiator(nodeParams, remoteNodeId, d.init.channelType, localParams.initFeatures, remoteInit.features, d.lastSent, accept) match { + Helpers.validateParamsDualFundedInitiator(nodeParams, remoteNodeId, d.init.channelType, d.init.localChannelParams.initFeatures, d.init.remoteInit.features, d.lastSent, accept) match { case Left(t) => d.init.replyTo ! OpenChannelResponse.Rejected(t.getMessage) handleLocalError(t, d, Some(accept)) @@ -241,28 +236,27 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers { peer ! ChannelIdAssigned(self, remoteNodeId, accept.temporaryChannelId, channelId) // we notify the peer asap so it knows how to route messages txPublisher ! SetChannelId(remoteNodeId, channelId) context.system.eventStream.publish(ChannelIdAssigned(self, remoteNodeId, accept.temporaryChannelId, channelId)) - val remoteParams = RemoteParams( + val remoteChannelParams = RemoteChannelParams( nodeId = remoteNodeId, dustLimit = accept.dustLimit, maxHtlcValueInFlightMsat = accept.maxHtlcValueInFlightMsat, initialRequestedChannelReserve_opt = None, // channel reserve will be computed based on channel capacity htlcMinimum = accept.htlcMinimum, - toSelfDelay = accept.toSelfDelay, + toRemoteDelay = accept.toSelfDelay, maxAcceptedHtlcs = accept.maxAcceptedHtlcs, revocationBasepoint = accept.revocationBasepoint, paymentBasepoint = accept.paymentBasepoint, delayedPaymentBasepoint = accept.delayedPaymentBasepoint, htlcBasepoint = accept.htlcBasepoint, - initFeatures = remoteInit.features, + initFeatures = d.init.remoteInit.features, upfrontShutdownScript_opt = remoteShutdownScript) - log.debug("remote params: {}", remoteParams) // We start the interactive-tx funding protocol. - val channelParams = ChannelParams(channelId, d.init.channelConfig, channelFeatures, localParams, remoteParams, d.lastSent.channelFlags) + val channelParams = ChannelParams(channelId, d.init.channelConfig, channelFeatures, d.init.localChannelParams, remoteChannelParams, d.lastSent.channelFlags) val localAmount = d.lastSent.fundingAmount val remoteAmount = accept.fundingAmount val fundingParams = InteractiveTxParams( channelId = channelId, - isInitiator = localParams.isChannelOpener, + isInitiator = d.init.localChannelParams.isChannelOpener, localContribution = localAmount, remoteContribution = remoteAmount, sharedInput_opt = None, @@ -336,7 +330,7 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers { d.deferred.foreach(self ! _) d.replyTo_opt.foreach(_ ! OpenChannelResponse.Created(d.channelId, status.fundingTx.txId, status.fundingTx.tx.localFees.truncateToSatoshi)) liquidityPurchase_opt.collect { - case purchase if !status.fundingParams.isInitiator => peer ! LiquidityPurchaseSigned(d.channelId, status.fundingTx.txId, status.fundingTxIndex, d.channelParams.remoteParams.htlcMinimum, purchase) + case purchase if !status.fundingParams.isInitiator => peer ! LiquidityPurchaseSigned(d.channelId, status.fundingTx.txId, status.fundingTxIndex, d.channelParams.remoteCommitParams.htlcMinimum, purchase) } val d1 = DATA_WAIT_FOR_DUAL_FUNDING_SIGNED(d.channelParams, d.secondRemotePerCommitmentPoint, d.localPushAmount, d.remotePushAmount, status, None) goto(WAIT_FOR_DUAL_FUNDING_SIGNED) using d1 storing() sending commitSig @@ -385,7 +379,7 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers { val minDepth_opt = d.channelParams.minDepth(nodeParams.channelConf.minDepth) watchFundingConfirmed(d.signingSession.fundingTx.txId, minDepth_opt, delay_opt = None) val commitments = Commitments( - params = d.channelParams, + channelParams = d.channelParams, changes = CommitmentChanges.init(), active = List(signingSession1.commitment), remoteNextCommitInfo = Right(d.secondRemotePerCommitmentPoint), @@ -408,7 +402,7 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers { val minDepth_opt = d.channelParams.minDepth(nodeParams.channelConf.minDepth) watchFundingConfirmed(d.signingSession.fundingTx.txId, minDepth_opt, delay_opt = None) val commitments = Commitments( - params = d.channelParams, + channelParams = d.channelParams, changes = CommitmentChanges.init(), active = List(signingSession.commitment), remoteNextCommitInfo = Right(d.secondRemotePerCommitmentPoint), @@ -473,7 +467,7 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers { rollbackRbfAttempt(signingSession, d) stay() using d.copy(status = DualFundingStatus.RbfAborted) sending TxAbort(d.channelId, f.getMessage) case Right(signingSession1) => - val minDepth_opt = d.commitments.params.minDepth(nodeParams.channelConf.minDepth) + val minDepth_opt = d.commitments.channelParams.minDepth(nodeParams.channelConf.minDepth) watchFundingConfirmed(signingSession.fundingTx.txId, minDepth_opt, delay_opt = None) val commitments1 = d.commitments.add(signingSession1.commitment) val d1 = DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED(commitments1, d.localPushAmount, d.remotePushAmount, d.waitingSince, d.lastChecked, DualFundingStatus.WaitingForConfirmations, d.deferred) @@ -493,7 +487,7 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers { if (!d.latestFundingTx.fundingParams.isInitiator) { cmd.replyTo ! RES_FAILURE(cmd, InvalidRbfNonInitiator(d.channelId)) stay() - } else if (d.commitments.params.zeroConf) { + } else if (d.commitments.channelParams.zeroConf) { cmd.replyTo ! RES_FAILURE(cmd, InvalidRbfZeroConf(d.channelId)) stay() } else if (cmd.requestFunding_opt.isEmpty && d.latestFundingTx.liquidityPurchase_opt.nonEmpty) { @@ -522,7 +516,7 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers { // Only the initiator is allowed to initiate RBF. log.info("rejecting tx_init_rbf, we're the initiator, not them!") stay() sending Error(d.channelId, InvalidRbfNonInitiator(d.channelId).getMessage) - } else if (d.commitments.params.zeroConf) { + } else if (d.commitments.channelParams.zeroConf) { log.info("rejecting tx_init_rbf, we're using zero-conf") stay() using d.copy(status = DualFundingStatus.RbfAborted) sending TxAbort(d.channelId, InvalidRbfZeroConf(d.channelId).getMessage) } else { @@ -569,7 +563,7 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers { val txBuilder = context.spawnAnonymous(InteractiveTxBuilder( randomBytes32(), nodeParams, fundingParams, - channelParams = d.commitments.params, + channelParams = d.commitments.channelParams, channelKeys = channelKeys, purpose = InteractiveTxBuilder.FundingTxRbf(d.commitments.active.head, previousTransactions = d.allFundingTxs.map(_.sharedTx), feeBudget_opt = None), localPushAmount = d.localPushAmount, remotePushAmount = d.remotePushAmount, @@ -617,7 +611,7 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers { val txBuilder = context.spawnAnonymous(InteractiveTxBuilder( randomBytes32(), nodeParams, fundingParams, - channelParams = d.commitments.params, + channelParams = d.commitments.channelParams, channelKeys = channelKeys, purpose = InteractiveTxBuilder.FundingTxRbf(d.commitments.active.head, previousTransactions = d.allFundingTxs.map(_.sharedTx), feeBudget_opt = Some(cmd.fundingFeeBudget)), localPushAmount = d.localPushAmount, remotePushAmount = d.remotePushAmount, @@ -647,7 +641,7 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers { log.debug("received their commit_sig, deferring message") stay() using d.copy(status = s.copy(remoteCommitSig = Some(commitSig))) case DualFundingStatus.RbfWaitingForSigs(signingSession) => - signingSession.receiveCommitSig(d.commitments.params, channelKeys, commitSig, nodeParams.currentBlockHeight) match { + signingSession.receiveCommitSig(d.commitments.channelParams, channelKeys, commitSig, nodeParams.currentBlockHeight) match { case Left(f) => rollbackRbfAttempt(signingSession, d) stay() using d.copy(status = DualFundingStatus.RbfAborted) sending TxAbort(d.channelId, f.getMessage) @@ -656,7 +650,7 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers { // No need to store their commit_sig, they will re-send it if we disconnect. stay() using d.copy(status = DualFundingStatus.RbfWaitingForSigs(signingSession1)) case signingSession1: InteractiveTxSigningSession.SendingSigs => - val minDepth_opt = d.commitments.params.minDepth(nodeParams.channelConf.minDepth) + val minDepth_opt = d.commitments.channelParams.minDepth(nodeParams.channelConf.minDepth) watchFundingConfirmed(signingSession.fundingTx.txId, minDepth_opt, delay_opt = None) val commitments1 = d.commitments.add(signingSession1.commitment) val d1 = DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED(commitments1, d.localPushAmount, d.remotePushAmount, d.waitingSince, d.lastChecked, DualFundingStatus.WaitingForConfirmations, d.deferred) @@ -701,7 +695,7 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers { cmd_opt.foreach(cmd => cmd.replyTo ! RES_BUMP_FUNDING_FEE(rbfIndex = d.previousFundingTxs.length, signingSession.fundingTx.txId, signingSession.fundingTx.tx.localFees.truncateToSatoshi)) remoteCommitSig_opt.foreach(self ! _) liquidityPurchase_opt.collect { - case purchase if !signingSession.fundingParams.isInitiator => peer ! LiquidityPurchaseSigned(d.channelId, signingSession.fundingTx.txId, signingSession.fundingTxIndex, d.commitments.params.remoteParams.htlcMinimum, purchase) + case purchase if !signingSession.fundingParams.isInitiator => peer ! LiquidityPurchaseSigned(d.channelId, signingSession.fundingTx.txId, signingSession.fundingTxIndex, d.commitments.channelParams.remoteCommitParams.htlcMinimum, purchase) } val d1 = d.copy(status = DualFundingStatus.RbfWaitingForSigs(signingSession)) stay() using d1 storing() sending commitSig @@ -724,7 +718,7 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers { // We still watch the funding tx for confirmation even if we can use the zero-conf channel right away. watchFundingConfirmed(w.tx.txid, Some(nodeParams.channelConf.minDepth), delay_opt = None) val shortIds = createShortIdAliases(d.channelId) - val channelReady = createChannelReady(shortIds, d.commitments.params) + val channelReady = createChannelReady(shortIds, d.commitments.channelParams) d.deferred.foreach(self ! _) goto(WAIT_FOR_DUAL_FUNDING_READY) using DATA_WAIT_FOR_DUAL_FUNDING_READY(commitments1, shortIds) storing() sending channelReady case Left(_) => stay() @@ -734,7 +728,7 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers { acceptFundingTxConfirmed(w, d) match { case Right((commitments1, _)) => val shortIds = createShortIdAliases(d.channelId) - val channelReady = createChannelReady(shortIds, d.commitments.params) + val channelReady = createChannelReady(shortIds, d.commitments.channelParams) reportRbfFailure(d.status, InvalidRbfTxConfirmed(d.channelId)) val toSend = d.status match { case DualFundingStatus.WaitingForConfirmations | DualFundingStatus.RbfAborted => Seq(channelReady) @@ -780,7 +774,7 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers { when(WAIT_FOR_DUAL_FUNDING_READY)(handleExceptions { case Event(channelReady: ChannelReady, d: DATA_WAIT_FOR_DUAL_FUNDING_READY) => val d1 = receiveChannelReady(d.aliases, channelReady, d.commitments) - val annSigs_opt = d1.commitments.all.find(_.fundingTxIndex == 0).flatMap(_.signAnnouncement(nodeParams, d1.commitments.params, channelKeys.fundingKey(fundingTxIndex = 0))) + val annSigs_opt = d1.commitments.all.find(_.fundingTxIndex == 0).flatMap(_.signAnnouncement(nodeParams, d1.commitments.channelParams, channelKeys.fundingKey(fundingTxIndex = 0))) annSigs_opt.foreach(annSigs => announcementSigsSent += annSigs.shortChannelId) goto(NORMAL) using d1 storing() sending annSigs_opt.toSeq diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/ChannelOpenSingleFunded.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/ChannelOpenSingleFunded.scala index c8289030b5..4332b503d4 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/ChannelOpenSingleFunded.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/ChannelOpenSingleFunded.scala @@ -75,22 +75,22 @@ trait ChannelOpenSingleFunded extends SingleFundingHandlers with ErrorHandlers { val fundingPubKey = channelKeys.fundingKey(fundingTxIndex = 0).publicKey // In order to allow TLV extensions and keep backwards-compatibility, we include an empty upfront_shutdown_script if this feature is not used // See https://github.com/lightningnetwork/lightning-rfc/pull/714. - val localShutdownScript = input.localParams.upfrontShutdownScript_opt.getOrElse(ByteVector.empty) + val localShutdownScript = input.localChannelParams.upfrontShutdownScript_opt.getOrElse(ByteVector.empty) val open = OpenChannel( chainHash = nodeParams.chainHash, temporaryChannelId = input.temporaryChannelId, fundingSatoshis = input.fundingAmount, pushMsat = input.pushAmount_opt.getOrElse(0 msat), - dustLimitSatoshis = input.localParams.dustLimit, - maxHtlcValueInFlightMsat = input.localParams.maxHtlcValueInFlightMsat, - channelReserveSatoshis = input.localParams.initialRequestedChannelReserve_opt.get, - htlcMinimumMsat = input.localParams.htlcMinimum, + dustLimitSatoshis = input.proposedCommitParams.localDustLimit, + maxHtlcValueInFlightMsat = input.proposedCommitParams.localMaxHtlcValueInFlight, + channelReserveSatoshis = input.localChannelParams.initialRequestedChannelReserve_opt.get, + htlcMinimumMsat = input.proposedCommitParams.localHtlcMinimum, feeratePerKw = input.commitTxFeerate, - toSelfDelay = input.localParams.toSelfDelay, - maxAcceptedHtlcs = input.localParams.maxAcceptedHtlcs, + toSelfDelay = input.proposedCommitParams.toRemoteDelay, + maxAcceptedHtlcs = input.proposedCommitParams.localMaxAcceptedHtlcs, fundingPubkey = fundingPubKey, revocationBasepoint = channelKeys.revocationBasePoint, - paymentBasepoint = input.localParams.walletStaticPaymentBasepoint.getOrElse(channelKeys.paymentBasePoint), + paymentBasepoint = input.localChannelParams.walletStaticPaymentBasepoint.getOrElse(channelKeys.paymentBasePoint), delayedPaymentBasepoint = channelKeys.delayedPaymentBasePoint, htlcBasepoint = channelKeys.htlcBasePoint, firstPerCommitmentPoint = channelKeys.commitmentPoint(0), @@ -104,17 +104,17 @@ trait ChannelOpenSingleFunded extends SingleFundingHandlers with ErrorHandlers { when(WAIT_FOR_OPEN_CHANNEL)(handleExceptions { case Event(open: OpenChannel, d: DATA_WAIT_FOR_OPEN_CHANNEL) => - Helpers.validateParamsSingleFundedFundee(nodeParams, d.initFundee.channelType, d.initFundee.localParams.initFeatures, open, remoteNodeId, d.initFundee.remoteInit.features) match { + Helpers.validateParamsSingleFundedFundee(nodeParams, d.initFundee.channelType, d.initFundee.localChannelParams.initFeatures, open, remoteNodeId, d.initFundee.remoteInit.features) match { case Left(t) => handleLocalError(t, d, Some(open)) case Right((channelFeatures, remoteShutdownScript)) => context.system.eventStream.publish(ChannelCreated(self, peer, remoteNodeId, isOpener = false, open.temporaryChannelId, open.feeratePerKw, None)) - val remoteParams = RemoteParams( + val remoteChannelParams = RemoteChannelParams( nodeId = remoteNodeId, dustLimit = open.dustLimitSatoshis, maxHtlcValueInFlightMsat = open.maxHtlcValueInFlightMsat, initialRequestedChannelReserve_opt = Some(open.channelReserveSatoshis), // our peer requires us to always have at least that much satoshis in our balance htlcMinimum = open.htlcMinimumMsat, - toSelfDelay = open.toSelfDelay, + toRemoteDelay = open.toSelfDelay, maxAcceptedHtlcs = open.maxAcceptedHtlcs, revocationBasepoint = open.revocationBasepoint, paymentBasepoint = open.paymentBasepoint, @@ -122,25 +122,22 @@ trait ChannelOpenSingleFunded extends SingleFundingHandlers with ErrorHandlers { htlcBasepoint = open.htlcBasepoint, initFeatures = d.initFundee.remoteInit.features, upfrontShutdownScript_opt = remoteShutdownScript) - log.debug("remote params: {}", remoteParams) val fundingPubkey = channelKeys.fundingKey(fundingTxIndex = 0).publicKey - val params = ChannelParams(d.initFundee.temporaryChannelId, d.initFundee.channelConfig, channelFeatures, d.initFundee.localParams, remoteParams, open.channelFlags) - val minimumDepth = params.minDepth(nodeParams.channelConf.minDepth) - log.info("will use fundingMinDepth={}", minimumDepth) + val channelParams = ChannelParams(d.initFundee.temporaryChannelId, d.initFundee.channelConfig, channelFeatures, d.initFundee.localChannelParams, remoteChannelParams, open.channelFlags) // In order to allow TLV extensions and keep backwards-compatibility, we include an empty upfront_shutdown_script if this feature is not used. // See https://github.com/lightningnetwork/lightning-rfc/pull/714. - val localShutdownScript = d.initFundee.localParams.upfrontShutdownScript_opt.getOrElse(ByteVector.empty) + val localShutdownScript = d.initFundee.localChannelParams.upfrontShutdownScript_opt.getOrElse(ByteVector.empty) val accept = AcceptChannel(temporaryChannelId = open.temporaryChannelId, - dustLimitSatoshis = d.initFundee.localParams.dustLimit, - maxHtlcValueInFlightMsat = d.initFundee.localParams.maxHtlcValueInFlightMsat, - channelReserveSatoshis = d.initFundee.localParams.initialRequestedChannelReserve_opt.get, - minimumDepth = minimumDepth.getOrElse(0).toLong, - htlcMinimumMsat = d.initFundee.localParams.htlcMinimum, - toSelfDelay = d.initFundee.localParams.toSelfDelay, - maxAcceptedHtlcs = d.initFundee.localParams.maxAcceptedHtlcs, + dustLimitSatoshis = d.initFundee.proposedCommitParams.localDustLimit, + maxHtlcValueInFlightMsat = d.initFundee.proposedCommitParams.localMaxHtlcValueInFlight, + channelReserveSatoshis = d.initFundee.localChannelParams.initialRequestedChannelReserve_opt.get, + minimumDepth = channelParams.minDepth(nodeParams.channelConf.minDepth).getOrElse(0).toLong, + htlcMinimumMsat = d.initFundee.proposedCommitParams.localHtlcMinimum, + toSelfDelay = d.initFundee.proposedCommitParams.toRemoteDelay, + maxAcceptedHtlcs = d.initFundee.proposedCommitParams.localMaxAcceptedHtlcs, fundingPubkey = fundingPubkey, revocationBasepoint = channelKeys.revocationBasePoint, - paymentBasepoint = d.initFundee.localParams.walletStaticPaymentBasepoint.getOrElse(channelKeys.paymentBasePoint), + paymentBasepoint = d.initFundee.localChannelParams.walletStaticPaymentBasepoint.getOrElse(channelKeys.paymentBasePoint), delayedPaymentBasepoint = channelKeys.delayedPaymentBasePoint, htlcBasepoint = channelKeys.htlcBasePoint, firstPerCommitmentPoint = channelKeys.commitmentPoint(0), @@ -148,7 +145,7 @@ trait ChannelOpenSingleFunded extends SingleFundingHandlers with ErrorHandlers { ChannelTlv.UpfrontShutdownScriptTlv(localShutdownScript), ChannelTlv.ChannelTypeTlv(d.initFundee.channelType) )) - goto(WAIT_FOR_FUNDING_CREATED) using DATA_WAIT_FOR_FUNDING_CREATED(params, open.fundingSatoshis, open.pushMsat, open.feeratePerKw, open.fundingPubkey, open.firstPerCommitmentPoint) sending accept + goto(WAIT_FOR_FUNDING_CREATED) using DATA_WAIT_FOR_FUNDING_CREATED(channelParams, open.fundingSatoshis, open.pushMsat, open.feeratePerKw, open.fundingPubkey, open.firstPerCommitmentPoint) sending accept } case Event(c: CloseCommand, d) => handleFastClose(c, d.channelId) @@ -160,18 +157,18 @@ trait ChannelOpenSingleFunded extends SingleFundingHandlers with ErrorHandlers { when(WAIT_FOR_ACCEPT_CHANNEL)(handleExceptions { case Event(accept: AcceptChannel, d@DATA_WAIT_FOR_ACCEPT_CHANNEL(init, open)) => - Helpers.validateParamsSingleFundedFunder(nodeParams, init.channelType, init.localParams.initFeatures, init.remoteInit.features, open, accept) match { + Helpers.validateParamsSingleFundedFunder(nodeParams, init.channelType, init.localChannelParams.initFeatures, init.remoteInit.features, open, accept) match { case Left(t) => d.initFunder.replyTo ! OpenChannelResponse.Rejected(t.getMessage) handleLocalError(t, d, Some(accept)) case Right((channelFeatures, remoteShutdownScript)) => - val remoteParams = RemoteParams( + val remoteChannelParams = RemoteChannelParams( nodeId = remoteNodeId, dustLimit = accept.dustLimitSatoshis, maxHtlcValueInFlightMsat = accept.maxHtlcValueInFlightMsat, initialRequestedChannelReserve_opt = Some(accept.channelReserveSatoshis), // our peer requires us to always have at least that much satoshis in our balance htlcMinimum = accept.htlcMinimumMsat, - toSelfDelay = accept.toSelfDelay, + toRemoteDelay = accept.toSelfDelay, maxAcceptedHtlcs = accept.maxAcceptedHtlcs, revocationBasepoint = accept.revocationBasepoint, paymentBasepoint = accept.paymentBasepoint, @@ -179,13 +176,12 @@ trait ChannelOpenSingleFunded extends SingleFundingHandlers with ErrorHandlers { htlcBasepoint = accept.htlcBasepoint, initFeatures = init.remoteInit.features, upfrontShutdownScript_opt = remoteShutdownScript) - log.debug("remote params: {}", remoteParams) log.info("remote will use fundingMinDepth={}", accept.minimumDepth) val localFundingKey = channelKeys.fundingKey(fundingTxIndex = 0) val fundingPubkeyScript = Script.write(Script.pay2wsh(Scripts.multiSig2of2(localFundingKey.publicKey, accept.fundingPubkey))) wallet.makeFundingTx(fundingPubkeyScript, init.fundingAmount, init.fundingTxFeerate, init.fundingTxFeeBudget_opt).pipeTo(self) - val params = ChannelParams(init.temporaryChannelId, init.channelConfig, channelFeatures, init.localParams, remoteParams, open.channelFlags) - goto(WAIT_FOR_FUNDING_INTERNAL) using DATA_WAIT_FOR_FUNDING_INTERNAL(params, init.fundingAmount, init.pushAmount_opt.getOrElse(0 msat), init.commitTxFeerate, accept.fundingPubkey, accept.firstPerCommitmentPoint, d.initFunder.replyTo) + val channelParams = ChannelParams(init.temporaryChannelId, init.channelConfig, channelFeatures, init.localChannelParams, remoteChannelParams, open.channelFlags) + goto(WAIT_FOR_FUNDING_INTERNAL) using DATA_WAIT_FOR_FUNDING_INTERNAL(channelParams, init.fundingAmount, init.pushAmount_opt.getOrElse(0 msat), init.commitTxFeerate, accept.fundingPubkey, accept.firstPerCommitmentPoint, d.initFunder.replyTo) } case Event(c: CloseCommand, d: DATA_WAIT_FOR_ACCEPT_CHANNEL) => @@ -206,18 +202,18 @@ trait ChannelOpenSingleFunded extends SingleFundingHandlers with ErrorHandlers { }) when(WAIT_FOR_FUNDING_INTERNAL)(handleExceptions { - case Event(MakeFundingTxResponse(fundingTx, fundingTxOutputIndex, fundingTxFee), d@DATA_WAIT_FOR_FUNDING_INTERNAL(params, fundingAmount, pushMsat, commitTxFeerate, remoteFundingPubKey, remoteFirstPerCommitmentPoint, replyTo)) => - val temporaryChannelId = params.channelId + case Event(MakeFundingTxResponse(fundingTx, fundingTxOutputIndex, fundingTxFee), d: DATA_WAIT_FOR_FUNDING_INTERNAL) => + val temporaryChannelId = d.channelParams.channelId // let's create the first commitment tx that spends the yet uncommitted funding tx val fundingKey = channelKeys.fundingKey(fundingTxIndex = 0) - val localCommitmentKeys = LocalCommitmentKeys(params, channelKeys, localCommitIndex = 0) - val remoteCommitmentKeys = RemoteCommitmentKeys(params, channelKeys, remoteFirstPerCommitmentPoint) - Funding.makeFirstCommitTxs(params, localFundingAmount = fundingAmount, remoteFundingAmount = 0 sat, localPushAmount = pushMsat, remotePushAmount = 0 msat, commitTxFeerate, fundingTx.txid, fundingTxOutputIndex, fundingKey, remoteFundingPubKey, localCommitmentKeys, remoteCommitmentKeys) match { + val localCommitmentKeys = LocalCommitmentKeys(d.channelParams, channelKeys, localCommitIndex = 0) + val remoteCommitmentKeys = RemoteCommitmentKeys(d.channelParams, channelKeys, d.remoteFirstPerCommitmentPoint) + Funding.makeFirstCommitTxs(d.channelParams, localFundingAmount = d.fundingAmount, remoteFundingAmount = 0 sat, localPushAmount = d.pushAmount, remotePushAmount = 0 msat, d.commitTxFeerate, fundingTx.txid, fundingTxOutputIndex, fundingKey, d.remoteFundingPubKey, localCommitmentKeys, remoteCommitmentKeys) match { case Left(ex) => handleLocalError(ex, d, None) case Right((localSpec, localCommitTx, remoteSpec, remoteCommitTx)) => require(fundingTx.txOut(fundingTxOutputIndex).publicKeyScript == localCommitTx.input.txOut.publicKeyScript, s"pubkey script mismatch!") - val localSigOfRemoteTx = params.commitmentFormat match { - case _: SegwitV0CommitmentFormat => remoteCommitTx.sign(fundingKey, remoteFundingPubKey).sig + val localSigOfRemoteTx = d.channelParams.commitmentFormat match { + case _: SegwitV0CommitmentFormat => remoteCommitTx.sign(fundingKey, d.remoteFundingPubKey).sig case _: SimpleTaprootChannelCommitmentFormat => ??? } // signature of their initial commitment tx that pays remote pushMsat @@ -228,12 +224,12 @@ trait ChannelOpenSingleFunded extends SingleFundingHandlers with ErrorHandlers { signature = localSigOfRemoteTx ) val channelId = toLongId(fundingTx.txid, fundingTxOutputIndex) - val params1 = params.copy(channelId = channelId) + val channelParams1 = d.channelParams.copy(channelId = channelId) peer ! ChannelIdAssigned(self, remoteNodeId, temporaryChannelId, channelId) // we notify the peer asap so it knows how to route messages txPublisher ! SetChannelId(remoteNodeId, channelId) context.system.eventStream.publish(ChannelIdAssigned(self, remoteNodeId, temporaryChannelId, channelId)) // NB: we don't send a ChannelSignatureSent for the first commit - goto(WAIT_FOR_FUNDING_SIGNED) using DATA_WAIT_FOR_FUNDING_SIGNED(params1, remoteFundingPubKey, fundingTx, fundingTxFee, localSpec, localCommitTx, RemoteCommit(0, remoteSpec, remoteCommitTx.tx.txid, remoteFirstPerCommitmentPoint), fundingCreated, replyTo) sending fundingCreated + goto(WAIT_FOR_FUNDING_SIGNED) using DATA_WAIT_FOR_FUNDING_SIGNED(channelParams1, d.remoteFundingPubKey, fundingTx, fundingTxFee, localSpec, localCommitTx, RemoteCommit(0, remoteSpec, remoteCommitTx.tx.txid, d.remoteFirstPerCommitmentPoint), fundingCreated, d.replyTo) sending fundingCreated } case Event(Status.Failure(t), d: DATA_WAIT_FOR_FUNDING_INTERNAL) => @@ -259,21 +255,21 @@ trait ChannelOpenSingleFunded extends SingleFundingHandlers with ErrorHandlers { }) when(WAIT_FOR_FUNDING_CREATED)(handleExceptions { - case Event(FundingCreated(_, fundingTxId, fundingTxOutputIndex, remoteSig, _), d@DATA_WAIT_FOR_FUNDING_CREATED(params, fundingAmount, pushMsat, commitTxFeerate, remoteFundingPubKey, remoteFirstPerCommitmentPoint)) => - val temporaryChannelId = params.channelId + case Event(FundingCreated(_, fundingTxId, fundingTxOutputIndex, remoteSig, _), d: DATA_WAIT_FOR_FUNDING_CREATED) => + val temporaryChannelId = d.channelParams.channelId val fundingKey = channelKeys.fundingKey(fundingTxIndex = 0) - val localCommitmentKeys = LocalCommitmentKeys(params, channelKeys, localCommitIndex = 0) - val remoteCommitmentKeys = RemoteCommitmentKeys(params, channelKeys, remoteFirstPerCommitmentPoint) + val localCommitmentKeys = LocalCommitmentKeys(d.channelParams, channelKeys, localCommitIndex = 0) + val remoteCommitmentKeys = RemoteCommitmentKeys(d.channelParams, channelKeys, d.remoteFirstPerCommitmentPoint) // they fund the channel with their funding tx, so the money is theirs (but we are paid pushMsat) - Funding.makeFirstCommitTxs(params, localFundingAmount = 0 sat, remoteFundingAmount = fundingAmount, localPushAmount = 0 msat, remotePushAmount = pushMsat, commitTxFeerate, fundingTxId, fundingTxOutputIndex, fundingKey, remoteFundingPubKey, localCommitmentKeys, remoteCommitmentKeys) match { + Funding.makeFirstCommitTxs(d.channelParams, localFundingAmount = 0 sat, remoteFundingAmount = d.fundingAmount, localPushAmount = 0 msat, remotePushAmount = d.pushAmount, d.commitTxFeerate, fundingTxId, fundingTxOutputIndex, fundingKey, d.remoteFundingPubKey, localCommitmentKeys, remoteCommitmentKeys) match { case Left(ex) => handleLocalError(ex, d, None) case Right((localSpec, localCommitTx, remoteSpec, remoteCommitTx)) => // check remote signature validity - localCommitTx.checkRemoteSig(fundingKey.publicKey, remoteFundingPubKey, ChannelSpendSignature.IndividualSignature(remoteSig)) match { + localCommitTx.checkRemoteSig(fundingKey.publicKey, d.remoteFundingPubKey, ChannelSpendSignature.IndividualSignature(remoteSig)) match { case false => handleLocalError(InvalidCommitmentSignature(temporaryChannelId, fundingTxId, commitmentNumber = 0, localCommitTx.tx), d, None) case true => - val localSigOfRemoteTx = params.commitmentFormat match { - case _: SegwitV0CommitmentFormat => remoteCommitTx.sign(fundingKey, remoteFundingPubKey).sig + val localSigOfRemoteTx = d.channelParams.commitmentFormat match { + case _: SegwitV0CommitmentFormat => remoteCommitTx.sign(fundingKey, d.remoteFundingPubKey).sig case _: SimpleTaprootChannelCommitmentFormat => ??? } val channelId = toLongId(fundingTxId, fundingTxOutputIndex) @@ -284,14 +280,14 @@ trait ChannelOpenSingleFunded extends SingleFundingHandlers with ErrorHandlers { val commitment = Commitment( fundingTxIndex = 0, firstRemoteCommitIndex = 0, - remoteFundingPubKey = remoteFundingPubKey, + remoteFundingPubKey = d.remoteFundingPubKey, localFundingStatus = SingleFundedUnconfirmedFundingTx(None), remoteFundingStatus = RemoteFundingStatus.NotLocked, localCommit = LocalCommit(0, localSpec, localCommitTx.tx.txid, localCommitTx.input, ChannelSpendSignature.IndividualSignature(remoteSig), htlcRemoteSigs = Nil), - remoteCommit = RemoteCommit(0, remoteSpec, remoteCommitTx.tx.txid, remoteFirstPerCommitmentPoint), + remoteCommit = RemoteCommit(0, remoteSpec, remoteCommitTx.tx.txid, d.remoteFirstPerCommitmentPoint), nextRemoteCommit_opt = None) val commitments = Commitments( - params = params.copy(channelId = channelId), + channelParams = d.channelParams.copy(channelId = channelId), changes = CommitmentChanges.init(), active = List(commitment), remoteNextCommitInfo = Right(randomKey().publicKey), // we will receive their next per-commitment point in the next message, so we temporarily put a random byte array @@ -303,7 +299,7 @@ trait ChannelOpenSingleFunded extends SingleFundingHandlers with ErrorHandlers { context.system.eventStream.publish(ChannelSignatureReceived(self, commitments)) // NB: we don't send a ChannelSignatureSent for the first commit log.info("waiting for them to publish the funding tx for channelId={} fundingTxid={}", channelId, commitment.fundingTxId) - watchFundingConfirmed(commitment.fundingTxId, params.minDepth(nodeParams.channelConf.minDepth), delay_opt = None) + watchFundingConfirmed(commitment.fundingTxId, d.channelParams.minDepth(nodeParams.channelConf.minDepth), delay_opt = None) goto(WAIT_FOR_FUNDING_CONFIRMED) using DATA_WAIT_FOR_FUNDING_CONFIRMED(commitments, nodeParams.currentBlockHeight, None, Right(fundingSigned)) storing() sending fundingSigned } } @@ -316,28 +312,28 @@ trait ChannelOpenSingleFunded extends SingleFundingHandlers with ErrorHandlers { }) when(WAIT_FOR_FUNDING_SIGNED)(handleExceptions { - case Event(msg@FundingSigned(_, remoteSig, _), d@DATA_WAIT_FOR_FUNDING_SIGNED(params, remoteFundingPubKey, fundingTx, fundingTxFee, localSpec, localCommitTx, remoteCommit, fundingCreated, _)) => + case Event(msg@FundingSigned(_, remoteSig, _), d: DATA_WAIT_FOR_FUNDING_SIGNED) => // we make sure that their sig checks out and that our first commit tx is spendable val fundingPubkey = channelKeys.fundingKey(fundingTxIndex = 0).publicKey - localCommitTx.checkRemoteSig(fundingPubkey, remoteFundingPubKey, ChannelSpendSignature.IndividualSignature(remoteSig)) match { + d.localCommitTx.checkRemoteSig(fundingPubkey, d.remoteFundingPubKey, ChannelSpendSignature.IndividualSignature(remoteSig)) match { case false => // we rollback the funding tx, it will never be published - wallet.rollback(fundingTx) + wallet.rollback(d.fundingTx) d.replyTo ! OpenChannelResponse.Rejected("invalid commit signatures") - handleLocalError(InvalidCommitmentSignature(d.channelId, fundingTx.txid, commitmentNumber = 0, localCommitTx.tx), d, Some(msg)) + handleLocalError(InvalidCommitmentSignature(d.channelId, d.fundingTx.txid, commitmentNumber = 0, d.localCommitTx.tx), d, Some(msg)) case true => val commitment = Commitment( fundingTxIndex = 0, firstRemoteCommitIndex = 0, - remoteFundingPubKey = remoteFundingPubKey, - localFundingStatus = SingleFundedUnconfirmedFundingTx(Some(fundingTx)), + remoteFundingPubKey = d.remoteFundingPubKey, + localFundingStatus = SingleFundedUnconfirmedFundingTx(Some(d.fundingTx)), remoteFundingStatus = RemoteFundingStatus.NotLocked, - localCommit = LocalCommit(0, localSpec, localCommitTx.tx.txid, localCommitTx.input, ChannelSpendSignature.IndividualSignature(remoteSig), htlcRemoteSigs = Nil), - remoteCommit = remoteCommit, + localCommit = LocalCommit(0, d.localSpec, d.localCommitTx.tx.txid, d.localCommitTx.input, ChannelSpendSignature.IndividualSignature(remoteSig), htlcRemoteSigs = Nil), + remoteCommit = d.remoteCommit, nextRemoteCommit_opt = None ) val commitments = Commitments( - params = params, + channelParams = d.channelParams, changes = CommitmentChanges.init(), active = List(commitment), remoteNextCommitInfo = Right(randomKey().publicKey), // we will receive their next per-commitment point in the next message, so we temporarily put a random byte array @@ -345,11 +341,11 @@ trait ChannelOpenSingleFunded extends SingleFundingHandlers with ErrorHandlers { originChannels = Map.empty) val blockHeight = nodeParams.currentBlockHeight context.system.eventStream.publish(ChannelSignatureReceived(self, commitments)) - log.info(s"publishing funding tx fundingTxid=${commitment.fundingTxId}") - watchFundingConfirmed(commitment.fundingTxId, params.minDepth(nodeParams.channelConf.minDepth), delay_opt = None) + log.info("publishing funding tx fundingTxId={}", commitment.fundingTxId) + watchFundingConfirmed(commitment.fundingTxId, d.channelParams.minDepth(nodeParams.channelConf.minDepth), delay_opt = None) // we will publish the funding tx only after the channel state has been written to disk because we want to // make sure we first persist the commitment that returns back the funds to us in case of problem - goto(WAIT_FOR_FUNDING_CONFIRMED) using DATA_WAIT_FOR_FUNDING_CONFIRMED(commitments, blockHeight, None, Left(fundingCreated)) storing() calling publishFundingTx(d.channelId, fundingTx, fundingTxFee, d.replyTo) + goto(WAIT_FOR_FUNDING_CONFIRMED) using DATA_WAIT_FOR_FUNDING_CONFIRMED(commitments, blockHeight, None, Left(d.lastSent)) storing() calling publishFundingTx(d.channelId, d.fundingTx, d.fundingTxFee, d.replyTo) } case Event(c: CloseCommand, d: DATA_WAIT_FOR_FUNDING_SIGNED) => @@ -384,9 +380,9 @@ trait ChannelOpenSingleFunded extends SingleFundingHandlers with ErrorHandlers { // notification that the funding tx has been successfully published: in that case we don't put a duplicate watch // - we're not using zero-conf, but our peer decided to trust us anyway, in which case we can skip waiting for // confirmations if we're the initiator (no risk of double-spend) and they provided a channel alias - val switchToZeroConf = d.commitments.params.localParams.isChannelOpener && + val switchToZeroConf = d.commitments.localChannelParams.isChannelOpener && remoteChannelReady.alias_opt.isDefined && - !d.commitments.params.zeroConf + !d.commitments.channelParams.zeroConf if (switchToZeroConf) { log.info("this channel isn't zero-conf, but we are funder and they sent an early channel_ready with an alias: no need to wait for confirmations") blockchain ! WatchPublished(self, d.commitments.latest.fundingTxId) @@ -402,7 +398,7 @@ trait ChannelOpenSingleFunded extends SingleFundingHandlers with ErrorHandlers { // We still watch the funding tx for confirmation even if we can use the zero-conf channel right away. watchFundingConfirmed(w.tx.txid, Some(nodeParams.channelConf.minDepth), delay_opt = None) val shortIds = createShortIdAliases(d.channelId) - val channelReady = createChannelReady(shortIds, d.commitments.params) + val channelReady = createChannelReady(shortIds, d.commitments.channelParams) d.deferred.foreach(self ! _) goto(WAIT_FOR_CHANNEL_READY) using DATA_WAIT_FOR_CHANNEL_READY(commitments1, shortIds) storing() sending channelReady case Left(_) => stay() @@ -412,7 +408,7 @@ trait ChannelOpenSingleFunded extends SingleFundingHandlers with ErrorHandlers { acceptFundingTxConfirmed(w, d) match { case Right((commitments1, _)) => val shortIds = createShortIdAliases(d.channelId) - val channelReady = createChannelReady(shortIds, d.commitments.params) + val channelReady = createChannelReady(shortIds, d.commitments.channelParams) d.deferred.foreach(self ! _) goto(WAIT_FOR_CHANNEL_READY) using DATA_WAIT_FOR_CHANNEL_READY(commitments1, shortIds) storing() sending channelReady case Left(_) => stay() @@ -429,7 +425,7 @@ trait ChannelOpenSingleFunded extends SingleFundingHandlers with ErrorHandlers { case Event(ProcessCurrentBlockHeight(c), d: DATA_WAIT_FOR_FUNDING_CONFIRMED) => d.fundingTx_opt match { case Some(_) => stay() // we are funder, we're still waiting for the funding tx to be confirmed case None if c.blockHeight - d.waitingSince > FUNDING_TIMEOUT_FUNDEE => - log.warning(s"funding tx hasn't been published in ${c.blockHeight - d.waitingSince} blocks") + log.warning("funding tx hasn't been published in {} blocks", c.blockHeight - d.waitingSince) self ! BITCOIN_FUNDING_TIMEOUT stay() case None => stay() // let's wait longer @@ -443,7 +439,7 @@ trait ChannelOpenSingleFunded extends SingleFundingHandlers with ErrorHandlers { when(WAIT_FOR_CHANNEL_READY)(handleExceptions { case Event(channelReady: ChannelReady, d: DATA_WAIT_FOR_CHANNEL_READY) => val d1 = receiveChannelReady(d.aliases, channelReady, d.commitments) - val annSigs_opt = d1.commitments.all.find(_.fundingTxIndex == 0).flatMap(_.signAnnouncement(nodeParams, d1.commitments.params, channelKeys.fundingKey(fundingTxIndex = 0))) + val annSigs_opt = d1.commitments.all.find(_.fundingTxIndex == 0).flatMap(_.signAnnouncement(nodeParams, d1.commitments.channelParams, channelKeys.fundingKey(fundingTxIndex = 0))) annSigs_opt.foreach(annSigs => announcementSigsSent += annSigs.shortChannelId) goto(NORMAL) using d1 storing() sending annSigs_opt.toSeq diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/CommonFundingHandlers.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/CommonFundingHandlers.scala index ed96642c0c..513f7bb859 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/CommonFundingHandlers.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/CommonFundingHandlers.scala @@ -138,7 +138,7 @@ trait CommonFundingHandlers extends CommonHandlers { val scidForChannelUpdate = Helpers.scidForChannelUpdate(channelAnnouncement_opt = None, aliases1.localAlias) log.info("using shortChannelId={} for initial channel_update", scidForChannelUpdate) val relayFees = getRelayFees(nodeParams, remoteNodeId, commitments.announceChannel) - val initialChannelUpdate = Announcements.makeChannelUpdate(nodeParams, remoteNodeId, scidForChannelUpdate, commitments.params, relayFees, Helpers.maxHtlcAmount(nodeParams, commitments), enable = true) + val initialChannelUpdate = Announcements.makeChannelUpdate(nodeParams, remoteNodeId, scidForChannelUpdate, commitments.channelParams, relayFees, Helpers.maxHtlcAmount(nodeParams, commitments), enable = true) // We need to periodically re-send channel updates, otherwise channel will be considered stale and get pruned by network. context.system.scheduler.scheduleWithFixedDelay(initialDelay = REFRESH_CHANNEL_UPDATE_INTERVAL, delay = REFRESH_CHANNEL_UPDATE_INTERVAL, receiver = self, message = BroadcastChannelUpdate(PeriodicRefresh)) val commitments1 = commitments.copy( diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/CommonHandlers.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/CommonHandlers.scala index 182a807342..bc41016765 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/CommonHandlers.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/CommonHandlers.scala @@ -18,7 +18,7 @@ package fr.acinq.eclair.channel.fsm import akka.actor.FSM import fr.acinq.bitcoin.scalacompat.ByteVector32 -import fr.acinq.eclair.{Features, MilliSatoshiLong} +import fr.acinq.eclair.Features import fr.acinq.eclair.channel.Helpers.Closing.MutualClose import fr.acinq.eclair.channel._ import fr.acinq.eclair.db.PendingCommandsDb @@ -110,10 +110,10 @@ trait CommonHandlers { case d: DATA_NEGOTIATING_SIMPLE => d.localScriptPubKey case d: DATA_CLOSING => d.finalScriptPubKey case d => - val allowAnySegwit = Features.canUseFeature(data.commitments.params.localParams.initFeatures, data.commitments.params.remoteParams.initFeatures, Features.ShutdownAnySegwit) - d.commitments.params.localParams.upfrontShutdownScript_opt match { + val allowAnySegwit = Features.canUseFeature(data.commitments.localChannelParams.initFeatures, data.commitments.remoteChannelParams.initFeatures, Features.ShutdownAnySegwit) + d.commitments.localChannelParams.upfrontShutdownScript_opt match { case Some(upfrontShutdownScript) => - if (data.commitments.params.channelFeatures.hasFeature(Features.UpfrontShutdownScript)) { + if (data.commitments.channelParams.channelFeatures.hasFeature(Features.UpfrontShutdownScript)) { // we have a shutdown script, and the option_upfront_shutdown_script is enabled: we have to use it upfrontShutdownScript } else { diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/DualFundingHandlers.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/DualFundingHandlers.scala index 227fb75ef3..a839e865a5 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/DualFundingHandlers.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/DualFundingHandlers.scala @@ -58,7 +58,7 @@ trait DualFundingHandlers extends CommonFundingHandlers { /** Return true if we should stop waiting for confirmations when receiving our peer's channel_ready. */ def switchToZeroConf(remoteChannelReady: ChannelReady, d: DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED): Boolean = { - if (!d.commitments.params.zeroConf) { + if (!d.commitments.channelParams.zeroConf) { // We're not using zero-conf, but our peer decided to trust us anyway. We can skip waiting for confirmations if: // - they provided a channel alias // - there is a single version of the funding tx (otherwise we don't know which one to use) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/ErrorHandlers.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/ErrorHandlers.scala index 7535925879..cafade4e17 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/ErrorHandlers.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/ErrorHandlers.scala @@ -54,7 +54,7 @@ trait ErrorHandlers extends CommonHandlers { case Left(negotiating) => DATA_CLOSING(negotiating.commitments, waitingSince = nodeParams.currentBlockHeight, finalScriptPubKey = negotiating.localShutdown.scriptPubKey, mutualCloseProposed = negotiating.closingTxProposed.flatten.map(_.unsignedTx), mutualClosePublished = closingTx :: Nil) case Right(closing) => closing.copy(mutualClosePublished = closing.mutualClosePublished :+ closingTx) } - goto(CLOSING) using nextData storing() calling doPublish(closingTx, nextData.commitments.params.localParams.paysClosingFees) + goto(CLOSING) using nextData storing() calling doPublish(closingTx, nextData.commitments.localChannelParams.paysClosingFees) } def doPublish(closingTx: ClosingTx, localPaysClosingFees: Boolean): Unit = { @@ -224,15 +224,15 @@ trait ErrorHandlers extends CommonHandlers { /** Publish 2nd-stage transactions for our local commitment. */ def doPublish(lcp: LocalCommitPublished, txs: Closing.LocalClose.SecondStageTransactions, commitment: FullCommitment): Unit = { - val publishCommitTx = PublishFinalTx(lcp.commitTx, commitment.commitInput.outPoint, "commit-tx", Closing.commitTxFee(commitment.commitInput, lcp.commitTx, commitment.localParams.paysCommitTxFees), None) + val publishCommitTx = PublishFinalTx(lcp.commitTx, commitment.commitInput.outPoint, "commit-tx", Closing.commitTxFee(commitment.commitInput, lcp.commitTx, commitment.localChannelParams.paysCommitTxFees), None) val publishAnchorTx_opt = txs.anchorTx_opt match { case Some(anchorTx) if !lcp.isConfirmed => - val confirmationTarget = Closing.confirmationTarget(commitment.localCommit, commitment.localParams.dustLimit, commitment.params.commitmentFormat, nodeParams.onChainFeeConf) + val confirmationTarget = Closing.confirmationTarget(commitment.localCommit, commitment.localCommitParams.dustLimit, commitment.commitmentFormat, nodeParams.onChainFeeConf) Some(PublishReplaceableTx(anchorTx, lcp.commitTx, commitment, confirmationTarget)) case _ => None } val publishMainDelayedTx_opt = txs.mainDelayedTx_opt.map(tx => PublishFinalTx(tx, None)) - val publishHtlcTxs = txs.htlcTxs.map(htlcTx => commitment.params.commitmentFormat match { + val publishHtlcTxs = txs.htlcTxs.map(htlcTx => commitment.commitmentFormat match { case DefaultCommitmentFormat => PublishFinalTx(htlcTx, Some(lcp.commitTx.txid)) case _: AnchorOutputsCommitmentFormat | _: SimpleTaprootChannelCommitmentFormat => PublishReplaceableTx(htlcTx, lcp.commitTx, commitment, Closing.confirmationTarget(htlcTx)) }) @@ -265,7 +265,7 @@ trait ErrorHandlers extends CommonHandlers { log.warning(s"they published their current commit in txid=${commitTx.txid}") require(commitTx.txid == commitments.remoteCommit.txId, "txid mismatch") val finalScriptPubKey = getOrGenerateFinalScriptPubKey(d) - context.system.eventStream.publish(TransactionPublished(d.channelId, remoteNodeId, commitTx, Closing.commitTxFee(commitments.commitInput, commitTx, d.commitments.params.localParams.paysCommitTxFees), "remote-commit")) + context.system.eventStream.publish(TransactionPublished(d.channelId, remoteNodeId, commitTx, Closing.commitTxFee(commitments.commitInput, commitTx, d.commitments.localChannelParams.paysCommitTxFees), "remote-commit")) val (remoteCommitPublished, closingTxs) = Closing.RemoteClose.claimCommitTxOutputs(channelKeys, commitments, commitments.remoteCommit, commitTx, nodeParams.currentBitcoinCoreFeerates, nodeParams.onChainFeeConf, finalScriptPubKey) val nextData = d match { case closing: DATA_CLOSING => closing.copy(remoteCommitPublished = Some(remoteCommitPublished)) @@ -284,7 +284,7 @@ trait ErrorHandlers extends CommonHandlers { require(commitTx.txid == remoteCommit.txId, "txid mismatch") val finalScriptPubKey = getOrGenerateFinalScriptPubKey(d) - context.system.eventStream.publish(TransactionPublished(d.channelId, remoteNodeId, commitTx, Closing.commitTxFee(commitment.commitInput, commitTx, d.commitments.params.localParams.paysCommitTxFees), "next-remote-commit")) + context.system.eventStream.publish(TransactionPublished(d.channelId, remoteNodeId, commitTx, Closing.commitTxFee(commitment.commitInput, commitTx, d.commitments.localChannelParams.paysCommitTxFees), "next-remote-commit")) val (remoteCommitPublished, closingTxs) = Closing.RemoteClose.claimCommitTxOutputs(channelKeys, commitment, remoteCommit, commitTx, nodeParams.currentBitcoinCoreFeerates, nodeParams.onChainFeeConf, finalScriptPubKey) val nextData = d match { case closing: DATA_CLOSING => closing.copy(nextRemoteCommitPublished = Some(remoteCommitPublished)) @@ -304,7 +304,7 @@ trait ErrorHandlers extends CommonHandlers { } val publishAnchorTx_opt = txs.anchorTx_opt match { case Some(anchorTx) if !rcp.isConfirmed => - val confirmationTarget = Closing.confirmationTarget(remoteCommit, commitment.remoteParams.dustLimit, commitment.params.commitmentFormat, nodeParams.onChainFeeConf) + val confirmationTarget = Closing.confirmationTarget(remoteCommit, commitment.remoteCommitParams.dustLimit, commitment.commitmentFormat, nodeParams.onChainFeeConf) Some(PublishReplaceableTx(anchorTx, rcp.commitTx, commitment, confirmationTarget)) case _ => None } @@ -330,11 +330,11 @@ trait ErrorHandlers extends CommonHandlers { val commitment = d.commitments.latest log.warning("funding tx spent by txid={}", tx.txid) val finalScriptPubKey = getOrGenerateFinalScriptPubKey(d) - Closing.RevokedClose.getRemotePerCommitmentSecret(d.commitments.params, channelKeys, d.commitments.remotePerCommitmentSecrets, tx) match { + Closing.RevokedClose.getRemotePerCommitmentSecret(d.commitments.channelParams, channelKeys, d.commitments.remotePerCommitmentSecrets, tx) match { case Some((commitmentNumber, remotePerCommitmentSecret)) => - val (revokedCommitPublished, closingTxs) = Closing.RevokedClose.claimCommitTxOutputs(d.commitments.params, channelKeys, tx, commitmentNumber, remotePerCommitmentSecret, nodeParams.db.channels, nodeParams.currentBitcoinCoreFeerates, nodeParams.onChainFeeConf, finalScriptPubKey) + val (revokedCommitPublished, closingTxs) = Closing.RevokedClose.claimCommitTxOutputs(d.commitments.channelParams, channelKeys, tx, commitmentNumber, remotePerCommitmentSecret, nodeParams.db.channels, nodeParams.currentBitcoinCoreFeerates, nodeParams.onChainFeeConf, finalScriptPubKey) log.warning("txid={} was a revoked commitment, publishing the penalty tx", tx.txid) - context.system.eventStream.publish(TransactionPublished(d.channelId, remoteNodeId, tx, Closing.commitTxFee(commitment.commitInput, tx, d.commitments.params.localParams.paysCommitTxFees), "revoked-commit")) + context.system.eventStream.publish(TransactionPublished(d.channelId, remoteNodeId, tx, Closing.commitTxFee(commitment.commitInput, tx, d.commitments.localChannelParams.paysCommitTxFees), "revoked-commit")) val exc = FundingTxSpent(d.channelId, tx.txid) val error = Error(d.channelId, exc.getMessage) val nextData = d match { @@ -348,10 +348,10 @@ trait ErrorHandlers extends CommonHandlers { case None => d match { case d: DATA_WAIT_FOR_REMOTE_PUBLISH_FUTURE_COMMITMENT => log.warning("they published a future commit (because we asked them to) in txid={}", tx.txid) - context.system.eventStream.publish(TransactionPublished(d.channelId, remoteNodeId, tx, Closing.commitTxFee(d.commitments.latest.commitInput, tx, d.commitments.latest.localParams.paysCommitTxFees), "future-remote-commit")) + context.system.eventStream.publish(TransactionPublished(d.channelId, remoteNodeId, tx, Closing.commitTxFee(d.commitments.latest.commitInput, tx, d.commitments.latest.localChannelParams.paysCommitTxFees), "future-remote-commit")) val remotePerCommitmentPoint = d.remoteChannelReestablish.myCurrentPerCommitmentPoint val commitKeys = d.commitments.latest.remoteKeys(channelKeys, remotePerCommitmentPoint) - val mainTx_opt = Closing.RemoteClose.claimMainOutput(d.commitments.params, commitKeys, tx, nodeParams.currentBitcoinCoreFeerates, nodeParams.onChainFeeConf, finalScriptPubKey) + val mainTx_opt = Closing.RemoteClose.claimMainOutput(d.commitments.channelParams, commitKeys, tx, nodeParams.currentBitcoinCoreFeerates, nodeParams.onChainFeeConf, finalScriptPubKey) mainTx_opt.foreach(tx => log.warning("publishing our recovery transaction: tx={}", tx.toString)) val remoteCommitPublished = RemoteCommitPublished( commitTx = tx, diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/publish/ReplaceableTxFunder.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/publish/ReplaceableTxFunder.scala index 12a183625b..057113e38e 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/publish/ReplaceableTxFunder.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/publish/ReplaceableTxFunder.scala @@ -124,8 +124,8 @@ private class ReplaceableTxFunder(replyTo: ActorRef[ReplaceableTxFunder.FundingR import ReplaceableTxFunder._ - private val dustLimit = commitment.localParams.dustLimit - private val commitFee: Satoshi = commitment.commitInput.txOut.amount - commitTx.txOut.map(_.amount).sum + private val dustLimit = commitment.localCommitParams.dustLimit + private val commitFee: Satoshi = commitment.capacity - commitTx.txOut.map(_.amount).sum private val log = context.log diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/db/DbEventHandler.scala b/eclair-core/src/main/scala/fr/acinq/eclair/db/DbEventHandler.scala index 9356799054..a7da4fb02b 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/db/DbEventHandler.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/db/DbEventHandler.scala @@ -125,7 +125,7 @@ class DbEventHandler(nodeParams: NodeParams) extends Actor with DiagnosticActorL case ChannelStateChanged(_, channelId, _, remoteNodeId, WAIT_FOR_CHANNEL_READY | WAIT_FOR_DUAL_FUNDING_READY, NORMAL, Some(commitments)) => ChannelMetrics.ChannelLifecycleEvents.withTag(ChannelTags.Event, ChannelTags.Events.Created).increment() val event = ChannelEvent.EventType.Created - auditDb.add(ChannelEvent(channelId, remoteNodeId, commitments.latest.capacity, commitments.params.localParams.isChannelOpener, !commitments.announceChannel, event)) + auditDb.add(ChannelEvent(channelId, remoteNodeId, commitments.latest.capacity, commitments.localChannelParams.isChannelOpener, !commitments.announceChannel, event)) channelsDb.updateChannelMeta(channelId, event) case ChannelStateChanged(_, _, _, _, WAIT_FOR_INIT_INTERNAL, _, _) => case ChannelStateChanged(_, channelId, _, _, OFFLINE, SYNCING, _) => @@ -139,7 +139,7 @@ class DbEventHandler(nodeParams: NodeParams) extends Actor with DiagnosticActorL ChannelMetrics.ChannelLifecycleEvents.withTag(ChannelTags.Event, ChannelTags.Events.Closed).increment() val event = ChannelEvent.EventType.Closed(e.closingType) val capacity = e.commitments.latest.capacity - auditDb.add(ChannelEvent(e.channelId, e.commitments.params.remoteParams.nodeId, capacity, e.commitments.params.localParams.isChannelOpener, !e.commitments.announceChannel, event)) + auditDb.add(ChannelEvent(e.channelId, e.commitments.remoteNodeId, capacity, e.commitments.localChannelParams.isChannelOpener, !e.commitments.announceChannel, event)) channelsDb.updateChannelMeta(e.channelId, event) case u: ChannelUpdateParametersChanged => diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/io/OpenChannelInterceptor.scala b/eclair-core/src/main/scala/fr/acinq/eclair/io/OpenChannelInterceptor.scala index 6743cbba69..d670ce61df 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/io/OpenChannelInterceptor.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/io/OpenChannelInterceptor.scala @@ -77,15 +77,15 @@ object OpenChannelInterceptor { } } - def makeChannelParams(nodeParams: NodeParams, initFeatures: Features[InitFeature], upfrontShutdownScript_opt: Option[ByteVector], walletStaticPaymentBasepoint_opt: Option[PublicKey], isChannelOpener: Boolean, paysCommitTxFees: Boolean, dualFunded: Boolean, fundingAmount: Satoshi, unlimitedMaxHtlcValueInFlight: Boolean): LocalParams = { - LocalParams( + def makeChannelParams(nodeParams: NodeParams, initFeatures: Features[InitFeature], upfrontShutdownScript_opt: Option[ByteVector], walletStaticPaymentBasepoint_opt: Option[PublicKey], isChannelOpener: Boolean, paysCommitTxFees: Boolean, dualFunded: Boolean, fundingAmount: Satoshi, unlimitedMaxHtlcValueInFlight: Boolean): LocalChannelParams = { + LocalChannelParams( nodeParams.nodeId, nodeParams.channelKeyManager.newFundingKeyPath(isChannelOpener), dustLimit = nodeParams.channelConf.dustLimit, maxHtlcValueInFlightMsat = nodeParams.channelConf.maxHtlcValueInFlight(fundingAmount, unlimitedMaxHtlcValueInFlight), initialRequestedChannelReserve_opt = if (dualFunded) None else Some((fundingAmount * nodeParams.channelConf.reserveToFundingRatio).max(nodeParams.channelConf.dustLimit)), // BOLT #2: make sure that our reserve is above our dust limit htlcMinimum = nodeParams.channelConf.htlcMinimum, - toSelfDelay = nodeParams.channelConf.toRemoteDelay, // we choose their delay + toRemoteDelay = nodeParams.channelConf.toRemoteDelay, // we choose their delay maxAcceptedHtlcs = nodeParams.channelConf.maxAcceptedHtlcs, isChannelOpener = isChannelOpener, paysCommitTxFees = paysCommitTxFees, @@ -172,7 +172,7 @@ private class OpenChannelInterceptor(peer: ActorRef[Any], } } - private def checkRateLimits(request: OpenChannelNonInitiator, channelType: SupportedChannelType, localParams: LocalParams): Behavior[Command] = { + private def checkRateLimits(request: OpenChannelNonInitiator, channelType: SupportedChannelType, localParams: LocalChannelParams): Behavior[Command] = { val adapter = context.messageAdapter[PendingChannelsRateLimiter.Response](PendingChannelsRateLimiterResponse) pendingChannelsRateLimiter ! AddOrRejectChannel(adapter, request.remoteNodeId, request.temporaryChannelId) receiveCommandMessage[CheckRateLimitsCommands](context, "checkRateLimits") { @@ -189,7 +189,7 @@ private class OpenChannelInterceptor(peer: ActorRef[Any], * If an external plugin was configured, we forward the channel request for further analysis. Otherwise, we accept * the channel and honor the optional liquidity request only for on-the-fly funding where we enforce a single channel. */ - private def checkLiquidityAdsRequest(request: OpenChannelNonInitiator, channelType: SupportedChannelType, localParams: LocalParams): Behavior[Command] = { + private def checkLiquidityAdsRequest(request: OpenChannelNonInitiator, channelType: SupportedChannelType, localParams: LocalChannelParams): Behavior[Command] = { nodeParams.pluginOpenChannelInterceptor match { case Some(plugin) => queryPlugin(plugin, request, localParams, ChannelConfig.standard, channelType) case None => @@ -228,7 +228,7 @@ private class OpenChannelInterceptor(peer: ActorRef[Any], } } - private def queryPlugin(plugin: InterceptOpenChannelPlugin, request: OpenChannelInterceptor.OpenChannelNonInitiator, localParams: LocalParams, channelConfig: ChannelConfig, channelType: SupportedChannelType): Behavior[Command] = + private def queryPlugin(plugin: InterceptOpenChannelPlugin, request: OpenChannelInterceptor.OpenChannelNonInitiator, localParams: LocalChannelParams, channelConfig: ChannelConfig, channelType: SupportedChannelType): Behavior[Command] = Behaviors.withTimers { timers => timers.startSingleTimer(PluginTimeout, pluginTimeout) val pluginResponseAdapter = context.messageAdapter[InterceptOpenChannelResponse](PluginOpenChannelResponse) @@ -302,7 +302,7 @@ private class OpenChannelInterceptor(peer: ActorRef[Any], } } - private def createLocalParams(nodeParams: NodeParams, initFeatures: Features[InitFeature], upfrontShutdownScript: Boolean, channelType: SupportedChannelType, isChannelOpener: Boolean, paysCommitTxFees: Boolean, dualFunded: Boolean, fundingAmount: Satoshi, disableMaxHtlcValueInFlight: Boolean): LocalParams = { + private def createLocalParams(nodeParams: NodeParams, initFeatures: Features[InitFeature], upfrontShutdownScript: Boolean, channelType: SupportedChannelType, isChannelOpener: Boolean, paysCommitTxFees: Boolean, dualFunded: Boolean, fundingAmount: Satoshi, disableMaxHtlcValueInFlight: Boolean): LocalChannelParams = { makeChannelParams( nodeParams, initFeatures, // Note that if our bitcoin node is configured to use taproot, this will generate a taproot script. 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 ec6e3aaa84..2077d5ccee 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 @@ -218,10 +218,27 @@ class Peer(val nodeParams: NodeParams, } else { randomBytes32() } - val fundingTxFeerate = c.fundingTxFeerate_opt.getOrElse(nodeParams.onChainFeeConf.getFundingFeerate(nodeParams.currentFeeratesForFundingClosing)) - val commitTxFeerate = nodeParams.onChainFeeConf.getCommitmentFeerate(nodeParams.currentBitcoinCoreFeerates, remoteNodeId, channelType.commitmentFormat, c.fundingAmount) - log.info(s"requesting a new channel with type=$channelType fundingAmount=${c.fundingAmount} dualFunded=$dualFunded pushAmount=${c.pushAmount_opt} fundingFeerate=$fundingTxFeerate temporaryChannelId=$temporaryChannelId localParams=$localParams") - channel ! INPUT_INIT_CHANNEL_INITIATOR(temporaryChannelId, c.fundingAmount, dualFunded, commitTxFeerate, fundingTxFeerate, c.fundingTxFeeBudget_opt, c.pushAmount_opt, requireConfirmedInputs, c.requestFunding_opt, localParams, d.peerConnection, d.remoteInit, c.channelFlags_opt.getOrElse(nodeParams.channelConf.channelFlags), channelConfig, channelType, replyTo) + val init = INPUT_INIT_CHANNEL_INITIATOR( + temporaryChannelId = temporaryChannelId, + fundingAmount = c.fundingAmount, + dualFunded = dualFunded, + commitTxFeerate = nodeParams.onChainFeeConf.getCommitmentFeerate(nodeParams.currentBitcoinCoreFeerates, remoteNodeId, channelType.commitmentFormat, c.fundingAmount), + fundingTxFeerate = c.fundingTxFeerate_opt.getOrElse(nodeParams.onChainFeeConf.getFundingFeerate(nodeParams.currentFeeratesForFundingClosing)), + fundingTxFeeBudget_opt = c.fundingTxFeeBudget_opt, + pushAmount_opt = c.pushAmount_opt, + requireConfirmedInputs = requireConfirmedInputs, + requestFunding_opt = c.requestFunding_opt, + localChannelParams = localParams, + proposedCommitParams = nodeParams.channelConf.commitParams(c.fundingAmount, unlimitedMaxHtlcValueInFlight = false), + remote = d.peerConnection, + remoteInit = d.remoteInit, + channelFlags = c.channelFlags_opt.getOrElse(nodeParams.channelConf.channelFlags), + channelConfig = channelConfig, + channelType = channelType, + replyTo = replyTo + ) + log.info(s"requesting a new channel with type=$channelType fundingAmount=${c.fundingAmount} dualFunded=$dualFunded pushAmount=${c.pushAmount_opt} fundingFeerate=${init.fundingTxFeerate} temporaryChannelId=$temporaryChannelId") + channel ! init stay() using d.copy(channels = d.channels + (TemporaryChannelId(temporaryChannelId) -> channel)) case Event(open: protocol.OpenChannel, d: ConnectedData) => @@ -269,11 +286,34 @@ class Peer(val nodeParams: NodeParams, log.info(s"accepting a new channel with type=$channelType temporaryChannelId=$temporaryChannelId localParams=$localParams") open match { case Left(open) => - channel ! INPUT_INIT_CHANNEL_NON_INITIATOR(open.temporaryChannelId, None, dualFunded = false, None, requireConfirmedInputs = false, localParams, d.peerConnection, d.remoteInit, channelConfig, channelType) + val init = INPUT_INIT_CHANNEL_NON_INITIATOR( + temporaryChannelId = open.temporaryChannelId, + fundingContribution_opt = None, + dualFunded = false, + pushAmount_opt = None, + requireConfirmedInputs = false, + localChannelParams = localParams, + proposedCommitParams = nodeParams.channelConf.commitParams(open.fundingSatoshis, unlimitedMaxHtlcValueInFlight = false), + remote = d.peerConnection, + remoteInit = d.remoteInit, + channelConfig = channelConfig, + channelType = channelType) + channel ! init channel ! open case Right(open) => - val requireConfirmedInputs = nodeParams.channelConf.requireConfirmedInputsForDualFunding - channel ! INPUT_INIT_CHANNEL_NON_INITIATOR(open.temporaryChannelId, addFunding_opt, dualFunded = true, None, requireConfirmedInputs, localParams, d.peerConnection, d.remoteInit, channelConfig, channelType) + val init = INPUT_INIT_CHANNEL_NON_INITIATOR( + temporaryChannelId = open.temporaryChannelId, + fundingContribution_opt = addFunding_opt, + dualFunded = true, + pushAmount_opt = None, + requireConfirmedInputs = nodeParams.channelConf.requireConfirmedInputsForDualFunding, + localChannelParams = localParams, + proposedCommitParams = nodeParams.channelConf.commitParams(open.fundingAmount + addFunding_opt.map(_.fundingAmount).getOrElse(0 sat), unlimitedMaxHtlcValueInFlight = false), + remote = d.peerConnection, + remoteInit = d.remoteInit, + channelConfig = channelConfig, + channelType = channelType) + channel ! init accept.useFeeCredit_opt match { case Some(useFeeCredit) => channel ! open.copy(tlvStream = TlvStream(open.tlvStream.records + ChannelTlv.UseFeeCredit(useFeeCredit))) case None => channel ! open @@ -1078,8 +1118,8 @@ object Peer { case class RemoteError(ascii: String) extends OpenChannelResponse { override def toString = s"peer aborted the channel funding flow: '$ascii'" } } - case class SpawnChannelInitiator(replyTo: akka.actor.typed.ActorRef[OpenChannelResponse], cmd: Peer.OpenChannel, channelConfig: ChannelConfig, channelType: SupportedChannelType, localParams: LocalParams) - case class SpawnChannelNonInitiator(open: Either[protocol.OpenChannel, protocol.OpenDualFundedChannel], channelConfig: ChannelConfig, channelType: SupportedChannelType, addFunding_opt: Option[LiquidityAds.AddFunding], localParams: LocalParams, peerConnection: ActorRef) + case class SpawnChannelInitiator(replyTo: akka.actor.typed.ActorRef[OpenChannelResponse], cmd: Peer.OpenChannel, channelConfig: ChannelConfig, channelType: SupportedChannelType, localParams: LocalChannelParams) + case class SpawnChannelNonInitiator(open: Either[protocol.OpenChannel, protocol.OpenDualFundedChannel], channelConfig: ChannelConfig, channelType: SupportedChannelType, addFunding_opt: Option[LiquidityAds.AddFunding], localParams: LocalChannelParams, peerConnection: ActorRef) /** If [[Features.OnTheFlyFunding]] is supported and we're connected, relay a funding proposal to our peer. */ case class ProposeOnTheFlyFunding(replyTo: typed.ActorRef[ProposeOnTheFlyFundingResponse], amount: MilliSatoshi, paymentHash: ByteVector32, expiry: CltvExpiry, onion: OnionRoutingPacket, onionSharedSecrets: Seq[Sphinx.SharedSecret], nextPathKey_opt: Option[PublicKey], upstream: Upstream.Hot) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/io/PendingChannelsRateLimiter.scala b/eclair-core/src/main/scala/fr/acinq/eclair/io/PendingChannelsRateLimiter.scala index a480cec083..44ccb6f366 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/io/PendingChannelsRateLimiter.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/io/PendingChannelsRateLimiter.scala @@ -54,11 +54,11 @@ object PendingChannelsRateLimiter { private[io] def filterPendingChannels(nodeParams: NodeParams, channels: Seq[PersistentChannelData]): Map[PublicKey, Seq[PersistentChannelData]] = { channels.filter { case p: PersistentChannelData if nodeParams.channelConf.channelOpenerWhitelist.contains(p.remoteNodeId) => false - case d: DATA_WAIT_FOR_FUNDING_CONFIRMED if !d.commitments.params.localParams.isChannelOpener => true + case d: DATA_WAIT_FOR_FUNDING_CONFIRMED if !d.commitments.localChannelParams.isChannelOpener => true case d: DATA_WAIT_FOR_DUAL_FUNDING_SIGNED if !d.channelParams.localParams.isChannelOpener => true - case d: DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED if !d.commitments.params.localParams.isChannelOpener => true - case d: DATA_WAIT_FOR_CHANNEL_READY if !d.commitments.params.localParams.isChannelOpener => true - case d: DATA_WAIT_FOR_DUAL_FUNDING_READY if !d.commitments.params.localParams.isChannelOpener => true + case d: DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED if !d.commitments.localChannelParams.isChannelOpener => true + case d: DATA_WAIT_FOR_CHANNEL_READY if !d.commitments.localChannelParams.isChannelOpener => true + case d: DATA_WAIT_FOR_DUAL_FUNDING_READY if !d.commitments.localChannelParams.isChannelOpener => true case _ => false }.groupBy(_.remoteNodeId) } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/payment/relay/OnTheFlyFunding.scala b/eclair-core/src/main/scala/fr/acinq/eclair/payment/relay/OnTheFlyFunding.scala index 8b7c977052..a5bb395e85 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/payment/relay/OnTheFlyFunding.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/payment/relay/OnTheFlyFunding.scala @@ -293,7 +293,7 @@ object OnTheFlyFunding { private def relay(data: DATA_NORMAL): Behavior[Command] = { context.log.debug("relaying {} on-the-fly HTLCs that have been funded", cmd.proposed.size) - val htlcMinimum = data.commitments.params.remoteParams.htlcMinimum + val htlcMinimum = data.commitments.channelParams.remoteCommitParams.htlcMinimum val cmdAdapter = context.messageAdapter[CommandResponse[CMD_ADD_HTLC]](WrappedCommandResponse) val htlcSettledAdapter = context.messageAdapter[RES_ADD_SETTLED[Origin.Hot, HtlcResult]](WrappedHtlcSettled) cmd.proposed.foldLeft(cmd.status.remainingFees) { 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 10ad00cf05..b20a7b09d3 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 @@ -30,6 +30,7 @@ import fr.acinq.eclair.payment.{ChannelPaymentRelayed, IncomingPaymentPacket, Pa import fr.acinq.eclair.transactions.DirectedHtlc.outgoing import fr.acinq.eclair.wire.protocol._ import fr.acinq.eclair.{CustomCommitmentsPlugin, Feature, Features, Logs, MilliSatoshiLong, NodeParams, TimestampMilli} +import kamon.metric.{Gauge, Metric} import scala.concurrent.Promise import scala.util.Try @@ -306,7 +307,7 @@ class PostRestartHtlcCleaner(nodeParams: NodeParams, register: ActorRef, initial object PostRestartHtlcCleaner { - def props(nodeParams: NodeParams, register: ActorRef, initialized: Option[Promise[Done]] = None) = Props(new PostRestartHtlcCleaner(nodeParams, register, initialized)) + def props(nodeParams: NodeParams, register: ActorRef, initialized: Option[Promise[Done]] = None): Props = Props(new PostRestartHtlcCleaner(nodeParams, register, initialized)) case class Init(channels: Seq[PersistentChannelData]) @@ -320,10 +321,10 @@ object PostRestartHtlcCleaner { val Hint = "hint" private val pending = Kamon.gauge("payment.broken-htlcs.pending", "Broken HTLCs because of a node restart") - val PendingNotRelayed = pending.withTag(Relayed, value = false) - val PendingRelayedOut = pending.withTag(Relayed, value = true) - val Resolved = Kamon.gauge("payment.broken-htlcs.resolved", "Broken HTLCs resolved after a node restart") - val Unhandled = Kamon.gauge("payment.broken-htlcs.unhandled", "Broken HTLCs that we don't know how to handle") + val PendingNotRelayed: Gauge = pending.withTag(Relayed, value = false) + val PendingRelayedOut: Gauge = pending.withTag(Relayed, value = true) + val Resolved: Metric.Gauge = Kamon.gauge("payment.broken-htlcs.resolved", "Broken HTLCs resolved after a node restart") + val Unhandled: Metric.Gauge = Kamon.gauge("payment.broken-htlcs.unhandled", "Broken HTLCs that we don't know how to handle") } @@ -427,8 +428,7 @@ object PostRestartHtlcCleaner { case Some(_: Closing.MutualClose) => Set.empty case None => Set.empty } - val params = d.commitments.params - val channelKeys = nodeParams.channelKeyManager.channelKeys(params.channelConfig, params.localParams.fundingKeyPath) + 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)) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version0/ChannelCodecs0.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version0/ChannelCodecs0.scala index 874b16ed13..8c2a81a619 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version0/ChannelCodecs0.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version0/ChannelCodecs0.scala @@ -57,7 +57,7 @@ private[channel] object ChannelCodecs0 { // field and don't support additional features which is why all bits are set to 0. ) - def localParamsCodec(channelVersion: ChannelTypes0.ChannelVersion): Codec[LocalParams] = ( + def localParamsCodec(channelVersion: ChannelTypes0.ChannelVersion): Codec[LocalChannelParams] = ( ("nodeId" | publicKey) :: ("channelPath" | keyPathCodec) :: ("dustLimit" | satoshi) :: @@ -71,7 +71,7 @@ private[channel] object ChannelCodecs0 { ("walletStaticPaymentBasepoint" | optional(provide(channelVersion.paysDirectlyToWallet), publicKey)) :: ("features" | combinedFeaturesCodec)).map { case nodeId :: channelPath :: dustLimit :: maxHtlcValueInFlightMsat :: channelReserve :: htlcMinimum :: toSelfDelay :: maxAcceptedHtlcs :: isInitiator :: upfrontShutdownScript_opt :: walletStaticPaymentBasepoint :: features :: HNil => - LocalParams(nodeId, channelPath, dustLimit, maxHtlcValueInFlightMsat, channelReserve, htlcMinimum, toSelfDelay, maxAcceptedHtlcs, isInitiator, isInitiator, upfrontShutdownScript_opt, walletStaticPaymentBasepoint, features) + LocalChannelParams(nodeId, channelPath, dustLimit, maxHtlcValueInFlightMsat, channelReserve, htlcMinimum, toSelfDelay, maxAcceptedHtlcs, isInitiator, isInitiator, upfrontShutdownScript_opt, walletStaticPaymentBasepoint, features) }.decodeOnly val remoteParamsCodec: Codec[ChannelTypes0.RemoteParams] = ( @@ -464,7 +464,7 @@ private[channel] object ChannelCodecs0 { ("revokedCommitPublished" | listOfN(uint16, revokedCommitPublishedCodec))).map { case commitments :: fundingTx_opt :: waitingSince :: mutualCloseProposed :: mutualClosePublished :: localCommitPublished :: remoteCommitPublished :: nextRemoteCommitPublished :: futureRemoteCommitPublished :: revokedCommitPublished :: HNil => val commitments1 = ChannelTypes0.setFundingStatus(commitments, SingleFundedUnconfirmedFundingTx(fundingTx_opt)) - DATA_CLOSING(commitments1, waitingSince, commitments1.params.localParams.upfrontShutdownScript_opt.get, mutualCloseProposed, mutualClosePublished, localCommitPublished, remoteCommitPublished, nextRemoteCommitPublished, futureRemoteCommitPublished, revokedCommitPublished) + DATA_CLOSING(commitments1, waitingSince, commitments1.localChannelParams.upfrontShutdownScript_opt.get, mutualCloseProposed, mutualClosePublished, localCommitPublished, remoteCommitPublished, nextRemoteCommitPublished, futureRemoteCommitPublished, revokedCommitPublished) }.decodeOnly val DATA_CLOSING_09_Codec: Codec[DATA_CLOSING] = ( @@ -480,7 +480,7 @@ private[channel] object ChannelCodecs0 { ("revokedCommitPublished" | listOfN(uint16, revokedCommitPublishedCodec))).map { case commitments :: fundingTx_opt :: waitingSince :: mutualCloseProposed :: mutualClosePublished :: localCommitPublished :: remoteCommitPublished :: nextRemoteCommitPublished :: futureRemoteCommitPublished :: revokedCommitPublished :: HNil => val commitments1 = ChannelTypes0.setFundingStatus(commitments, SingleFundedUnconfirmedFundingTx(fundingTx_opt)) - DATA_CLOSING(commitments1, waitingSince, commitments1.params.localParams.upfrontShutdownScript_opt.get, mutualCloseProposed, mutualClosePublished, localCommitPublished, remoteCommitPublished, nextRemoteCommitPublished, futureRemoteCommitPublished, revokedCommitPublished) + DATA_CLOSING(commitments1, waitingSince, commitments1.localChannelParams.upfrontShutdownScript_opt.get, mutualCloseProposed, mutualClosePublished, localCommitPublished, remoteCommitPublished, nextRemoteCommitPublished, futureRemoteCommitPublished, revokedCommitPublished) }.decodeOnly val channelReestablishCodec: Codec[ChannelReestablish] = ( diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version0/ChannelTypes0.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version0/ChannelTypes0.scala index 3cd3cdeab0..1121805230 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version0/ChannelTypes0.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version0/ChannelTypes0.scala @@ -166,7 +166,7 @@ private[channel] object ChannelTypes0 { maxHtlcValueInFlightMsat: UInt64, // this is not MilliSatoshi because it can exceed the total amount of MilliSatoshi requestedChannelReserve_opt: Option[Satoshi], htlcMinimum: MilliSatoshi, - toSelfDelay: CltvExpiryDelta, + toRemoteDelay: CltvExpiryDelta, maxAcceptedHtlcs: Int, fundingPubKey: PublicKey, revocationBasepoint: PublicKey, @@ -175,13 +175,13 @@ private[channel] object ChannelTypes0 { htlcBasepoint: PublicKey, initFeatures: Features[InitFeature], upfrontShutdownScript_opt: Option[ByteVector]) { - def migrate(): channel.RemoteParams = channel.RemoteParams( + def migrate(): channel.RemoteChannelParams = channel.RemoteChannelParams( nodeId = nodeId, dustLimit = dustLimit, maxHtlcValueInFlightMsat = maxHtlcValueInFlightMsat, initialRequestedChannelReserve_opt = requestedChannelReserve_opt, htlcMinimum = htlcMinimum, - toSelfDelay = toSelfDelay, + toRemoteDelay = toRemoteDelay, maxAcceptedHtlcs = maxAcceptedHtlcs, revocationBasepoint = revocationBasepoint, paymentBasepoint = paymentBasepoint, @@ -195,7 +195,7 @@ private[channel] object ChannelTypes0 { case class WaitingForRevocation(nextRemoteCommit: RemoteCommit, sent: CommitSig, sentAfterLocalCommitIndex: Long) case class Commitments(channelVersion: ChannelVersion, - localParams: LocalParams, remoteParams: RemoteParams, + localParams: LocalChannelParams, remoteParams: RemoteParams, channelFlags: ChannelFlags, localCommit: LocalCommit, remoteCommit: RemoteCommit, localChanges: LocalChanges, remoteChanges: RemoteChanges, diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version1/ChannelCodecs1.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version1/ChannelCodecs1.scala index 276833bbfc..c25ef198ae 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version1/ChannelCodecs1.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version1/ChannelCodecs1.scala @@ -44,7 +44,7 @@ private[channel] object ChannelCodecs1 { val channelVersionCodec: Codec[ChannelTypes0.ChannelVersion] = bits(ChannelTypes0.ChannelVersion.LENGTH_BITS).as[ChannelTypes0.ChannelVersion] - def localParamsCodec(channelVersion: ChannelTypes0.ChannelVersion): Codec[LocalParams] = ( + def localParamsCodec(channelVersion: ChannelTypes0.ChannelVersion): Codec[LocalChannelParams] = ( ("nodeId" | publicKey) :: ("channelPath" | keyPathCodec) :: ("dustLimit" | satoshi) :: @@ -56,7 +56,7 @@ private[channel] object ChannelCodecs1 { ("isChannelOpener" | bool) :: ("paysCommitTxFees" | bool) :: ignore(6) :: ("upfrontShutdownScript_opt" | lengthDelimited(bytes).map(Option(_)).decodeOnly) :: ("walletStaticPaymentBasepoint" | optional(provide(channelVersion.paysDirectlyToWallet), publicKey)) :: - ("features" | combinedFeaturesCodec)).as[LocalParams].decodeOnly + ("features" | combinedFeaturesCodec)).as[LocalChannelParams].decodeOnly val remoteParamsCodec: Codec[ChannelTypes0.RemoteParams] = ( ("nodeId" | publicKey) :: @@ -306,7 +306,7 @@ private[channel] object ChannelCodecs1 { ("revokedCommitPublished" | listOfN(uint16, revokedCommitPublishedCodec))).map { case commitments :: fundingTx_opt :: waitingSince :: mutualCloseProposed :: mutualClosePublished :: localCommitPublished :: remoteCommitPublished :: nextRemoteCommitPublished :: futureRemoteCommitPublished :: revokedCommitPublished :: HNil => val commitments1 = ChannelTypes0.setFundingStatus(commitments, SingleFundedUnconfirmedFundingTx(fundingTx_opt)) - DATA_CLOSING(commitments1, waitingSince, commitments1.params.localParams.upfrontShutdownScript_opt.get, mutualCloseProposed, mutualClosePublished, localCommitPublished, remoteCommitPublished, nextRemoteCommitPublished, futureRemoteCommitPublished, revokedCommitPublished) + DATA_CLOSING(commitments1, waitingSince, commitments1.localChannelParams.upfrontShutdownScript_opt.get, mutualCloseProposed, mutualClosePublished, localCommitPublished, remoteCommitPublished, nextRemoteCommitPublished, futureRemoteCommitPublished, revokedCommitPublished) }.decodeOnly val DATA_WAIT_FOR_REMOTE_PUBLISH_FUTURE_COMMITMENT_26_Codec: Codec[DATA_WAIT_FOR_REMOTE_PUBLISH_FUTURE_COMMITMENT] = ( diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version2/ChannelCodecs2.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version2/ChannelCodecs2.scala index 7fb950f82c..77621252f8 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version2/ChannelCodecs2.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version2/ChannelCodecs2.scala @@ -53,7 +53,7 @@ private[channel] object ChannelCodecs2 { val channelVersionCodec: Codec[ChannelTypes0.ChannelVersion] = bits(ChannelTypes0.ChannelVersion.LENGTH_BITS).as[ChannelTypes0.ChannelVersion] - def localParamsCodec(channelVersion: ChannelTypes0.ChannelVersion): Codec[LocalParams] = ( + def localParamsCodec(channelVersion: ChannelTypes0.ChannelVersion): Codec[LocalChannelParams] = ( ("nodeId" | publicKey) :: ("channelPath" | keyPathCodec) :: ("dustLimit" | satoshi) :: @@ -65,7 +65,7 @@ private[channel] object ChannelCodecs2 { ("isChannelOpener" | bool) :: ("paysCommitTxFees" | bool) :: ignore(6) :: ("upfrontShutdownScript_opt" | lengthDelimited(bytes).map(Option(_)).decodeOnly) :: ("walletStaticPaymentBasepoint" | optional(provide(channelVersion.paysDirectlyToWallet), publicKey)) :: - ("features" | combinedFeaturesCodec)).as[LocalParams] + ("features" | combinedFeaturesCodec)).as[LocalChannelParams] val remoteParamsCodec: Codec[ChannelTypes0.RemoteParams] = ( ("nodeId" | publicKey) :: @@ -336,7 +336,7 @@ private[channel] object ChannelCodecs2 { ("revokedCommitPublished" | listOfN(uint16, revokedCommitPublishedCodec))).map { case commitments :: fundingTx_opt :: waitingSince :: mutualCloseProposed :: mutualClosePublished :: localCommitPublished :: remoteCommitPublished :: nextRemoteCommitPublished :: futureRemoteCommitPublished :: revokedCommitPublished :: HNil => val commitments1 = ChannelTypes0.setFundingStatus(commitments, SingleFundedUnconfirmedFundingTx(fundingTx_opt)) - DATA_CLOSING(commitments1, waitingSince, commitments1.params.localParams.upfrontShutdownScript_opt.get, mutualCloseProposed, mutualClosePublished, localCommitPublished, remoteCommitPublished, nextRemoteCommitPublished, futureRemoteCommitPublished, revokedCommitPublished) + DATA_CLOSING(commitments1, waitingSince, commitments1.localChannelParams.upfrontShutdownScript_opt.get, mutualCloseProposed, mutualClosePublished, localCommitPublished, remoteCommitPublished, nextRemoteCommitPublished, futureRemoteCommitPublished, revokedCommitPublished) }.decodeOnly val DATA_WAIT_FOR_REMOTE_PUBLISH_FUTURE_COMMITMENT_06_Codec: Codec[DATA_WAIT_FOR_REMOTE_PUBLISH_FUTURE_COMMITMENT] = ( diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version3/ChannelCodecs3.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version3/ChannelCodecs3.scala index f273fad604..e7138b4750 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version3/ChannelCodecs3.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version3/ChannelCodecs3.scala @@ -66,7 +66,7 @@ private[channel] object ChannelCodecs3 { (cf: ChannelFeatures) => Features(cf.features.map(f => f -> FeatureSupport.Mandatory).toMap).toByteVector // we encode features as mandatory, by convention ) - def localParamsCodec(channelFeatures: ChannelFeatures): Codec[LocalParams] = ( + def localParamsCodec(channelFeatures: ChannelFeatures): Codec[LocalChannelParams] = ( ("nodeId" | publicKey) :: ("channelPath" | keyPathCodec) :: ("dustLimit" | satoshi) :: @@ -78,7 +78,7 @@ private[channel] object ChannelCodecs3 { ("isChannelOpener" | bool) :: ("paysCommitTxFees" | bool) :: ignore(6) :: ("upfrontShutdownScript_opt" | lengthDelimited(bytes).map(Option(_)).decodeOnly) :: ("walletStaticPaymentBasepoint" | optional(provide(channelFeatures.paysDirectlyToWallet), publicKey)) :: - ("features" | combinedFeaturesCodec)).as[LocalParams] + ("features" | combinedFeaturesCodec)).as[LocalChannelParams] def remoteParamsCodec(channelFeatures: ChannelFeatures): Codec[ChannelTypes0.RemoteParams] = ( ("nodeId" | publicKey) :: @@ -435,7 +435,7 @@ private[channel] object ChannelCodecs3 { ("revokedCommitPublished" | listOfN(uint16, revokedCommitPublishedCodec))).map { case commitments :: fundingTx_opt :: waitingSince :: mutualCloseProposed :: mutualClosePublished :: localCommitPublished :: remoteCommitPublished :: nextRemoteCommitPublished :: futureRemoteCommitPublished :: revokedCommitPublished :: HNil => val commitments1 = ChannelTypes0.setFundingStatus(commitments, SingleFundedUnconfirmedFundingTx(fundingTx_opt)) - DATA_CLOSING(commitments1, waitingSince, commitments1.params.localParams.upfrontShutdownScript_opt.get, mutualCloseProposed, mutualClosePublished, localCommitPublished, remoteCommitPublished, nextRemoteCommitPublished, futureRemoteCommitPublished, revokedCommitPublished) + DATA_CLOSING(commitments1, waitingSince, commitments1.localChannelParams.upfrontShutdownScript_opt.get, mutualCloseProposed, mutualClosePublished, localCommitPublished, remoteCommitPublished, nextRemoteCommitPublished, futureRemoteCommitPublished, revokedCommitPublished) }.decodeOnly val unconfirmedFundingTxCodec: Codec[UnconfirmedFundingTx] = discriminated[UnconfirmedFundingTx].by(uint8) @@ -456,7 +456,7 @@ private[channel] object ChannelCodecs3 { ("revokedCommitPublished" | listOfN(uint16, revokedCommitPublishedCodec))).map { case commitments :: fundingTx_opt :: waitingSince :: _ :: mutualCloseProposed :: mutualClosePublished :: localCommitPublished :: remoteCommitPublished :: nextRemoteCommitPublished :: futureRemoteCommitPublished :: revokedCommitPublished :: HNil => val commitments1 = ChannelTypes0.setFundingStatus(commitments, SingleFundedUnconfirmedFundingTx(fundingTx_opt.flatMap(_.signedTx_opt))) - DATA_CLOSING(commitments1, waitingSince, commitments.params.localParams.upfrontShutdownScript_opt.get, mutualCloseProposed, mutualClosePublished, localCommitPublished, remoteCommitPublished, nextRemoteCommitPublished, futureRemoteCommitPublished, revokedCommitPublished) + DATA_CLOSING(commitments1, waitingSince, commitments.localChannelParams.upfrontShutdownScript_opt.get, mutualCloseProposed, mutualClosePublished, localCommitPublished, remoteCommitPublished, nextRemoteCommitPublished, futureRemoteCommitPublished, revokedCommitPublished) }.decodeOnly val DATA_WAIT_FOR_REMOTE_PUBLISH_FUTURE_COMMITMENT_06_Codec: Codec[DATA_WAIT_FOR_REMOTE_PUBLISH_FUTURE_COMMITMENT] = ( diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version3/ChannelTypes3.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version3/ChannelTypes3.scala index c363df2bb4..3170b33aca 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version3/ChannelTypes3.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version3/ChannelTypes3.scala @@ -49,7 +49,7 @@ private[channel] object ChannelTypes3 { case class Commitments(channelId: ByteVector32, channelConfig: ChannelConfig, channelFeatures: ChannelFeatures, - localParams: LocalParams, remoteParams: ChannelTypes0.RemoteParams, + localParams: LocalChannelParams, remoteParams: ChannelTypes0.RemoteParams, channelFlags: ChannelFlags, localCommit: ChannelTypes3.LocalCommit, remoteCommit: RemoteCommit, localChanges: LocalChanges, remoteChanges: RemoteChanges, diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version4/ChannelCodecs4.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version4/ChannelCodecs4.scala index 3a8125106f..d9ec9d267e 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version4/ChannelCodecs4.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/internal/channel/version4/ChannelCodecs4.scala @@ -53,7 +53,7 @@ private[channel] object ChannelCodecs4 { (cf: ChannelFeatures) => Features(cf.features.map(f => f -> FeatureSupport.Mandatory).toMap).toByteVector // we encode features as mandatory, by convention ) - def localParamsCodec(channelFeatures: ChannelFeatures): Codec[LocalParams] = ( + def localParamsCodec(channelFeatures: ChannelFeatures): Codec[LocalChannelParams] = ( ("nodeId" | publicKey) :: ("channelPath" | keyPathCodec) :: ("dustLimit" | satoshi) :: @@ -66,9 +66,9 @@ private[channel] object ChannelCodecs4 { ("isChannelOpener" | bool) :: ("paysCommitTxFees" | bool) :: ignore(6) :: ("upfrontShutdownScript_opt" | optional(bool8, lengthDelimited(bytes))) :: ("walletStaticPaymentBasepoint" | optional(provide(channelFeatures.paysDirectlyToWallet), publicKey)) :: - ("features" | combinedFeaturesCodec)).as[LocalParams] + ("features" | combinedFeaturesCodec)).as[LocalChannelParams] - def remoteParamsCodec(channelFeatures: ChannelFeatures): Codec[RemoteParams] = ( + def remoteParamsCodec(channelFeatures: ChannelFeatures): Codec[RemoteChannelParams] = ( ("nodeId" | publicKey) :: ("dustLimit" | satoshi) :: ("maxHtlcValueInFlightMsat" | uint64) :: @@ -81,7 +81,7 @@ private[channel] object ChannelCodecs4 { ("delayedPaymentBasepoint" | publicKey) :: ("htlcBasepoint" | publicKey) :: ("features" | combinedFeaturesCodec) :: - ("shutdownScript" | optional(bool8, lengthDelimited(bytes)))).as[RemoteParams] + ("shutdownScript" | optional(bool8, lengthDelimited(bytes)))).as[RemoteChannelParams] def setCodec[T](codec: Codec[T]): Codec[Set[T]] = listOfN(uint16, codec).xmap(_.toSet, _.toList) @@ -549,7 +549,7 @@ private[channel] object ChannelCodecs4 { * The resulting htlc set size is thus between 1,4 MB and 64 MB, which can be pretty large. * To avoid writing that htlc set multiple times to disk, we encode it separately. */ - case class EncodedCommitments(params: ChannelParams, + case class EncodedCommitments(channelParams: ChannelParams, changes: CommitmentChanges, // The direction we use is from our local point of view. htlcs: Set[DirectedHtlc], @@ -561,7 +561,7 @@ private[channel] object ChannelCodecs4 { remoteChannelData_opt: Option[ByteVector]) { def toCommitments: Commitments = { Commitments( - params = params, + channelParams = channelParams, changes = changes, active = active, inactive = inactive, @@ -583,7 +583,7 @@ private[channel] object ChannelCodecs4 { commitmentsSet.flatMap(_.remoteCommit.spec.htlcs.map(_.opposite)) ++ commitmentsSet.flatMap(_.nextRemoteCommit_opt.toList.flatMap(_.commit.spec.htlcs.map(_.opposite))) EncodedCommitments( - params = commitments.params, + channelParams = commitments.channelParams, changes = commitments.changes, htlcs = htlcs, active = commitments.active.toList, diff --git a/eclair-core/src/test/resources/nonreg/codecs/000003-DATA_NORMAL/fundee/data.json b/eclair-core/src/test/resources/nonreg/codecs/000003-DATA_NORMAL/fundee/data.json index 54f68dee87..1f34a0cdee 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/000003-DATA_NORMAL/fundee/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/000003-DATA_NORMAL/fundee/data.json @@ -1,7 +1,7 @@ { "type" : "DATA_NORMAL", "commitments" : { - "params" : { + "channelParams" : { "channelId" : "07738f22c16a24795bcaebc6e09016af61902dd66bbaf64e6e5db50b0c45d63c", "channelConfig" : [ ], "channelFeatures" : [ ], @@ -12,7 +12,7 @@ "maxHtlcValueInFlightMsat" : 5000000000, "initialRequestedChannelReserve_opt" : 167772, "htlcMinimum" : 1, - "toSelfDelay" : 720, + "toRemoteDelay" : 720, "maxAcceptedHtlcs" : 30, "isChannelOpener" : false, "paysCommitTxFees" : false, @@ -32,7 +32,7 @@ "maxHtlcValueInFlightMsat" : 16609443000, "initialRequestedChannelReserve_opt" : 167772, "htlcMinimum" : 1000, - "toSelfDelay" : 2016, + "toRemoteDelay" : 2016, "maxAcceptedHtlcs" : 483, "revocationBasepoint" : "02635ac9eedf5f219afbc4d125e37b5705f73c05deca71b05fe84096a691e055c1", "paymentBasepoint" : "034a711d28e8ed3ad389ec14ec75c199b6a45140c503bcc88110e3524e52ffbfb1", diff --git a/eclair-core/src/test/resources/nonreg/codecs/000003-DATA_NORMAL/funder/data.json b/eclair-core/src/test/resources/nonreg/codecs/000003-DATA_NORMAL/funder/data.json index 56a91bdd4a..e699ba38e5 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/000003-DATA_NORMAL/funder/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/000003-DATA_NORMAL/funder/data.json @@ -1,7 +1,7 @@ { "type" : "DATA_NORMAL", "commitments" : { - "params" : { + "channelParams" : { "channelId" : "6ecfe1e9e01abd3fbe482efde50e4687b3f1f5d8cba609174aebce1c01415611", "channelConfig" : [ ], "channelFeatures" : [ ], @@ -12,7 +12,7 @@ "maxHtlcValueInFlightMsat" : 1000000000, "initialRequestedChannelReserve_opt" : 150000, "htlcMinimum" : 1, - "toSelfDelay" : 144, + "toRemoteDelay" : 144, "maxAcceptedHtlcs" : 30, "isChannelOpener" : true, "paysCommitTxFees" : true, @@ -32,7 +32,7 @@ "maxHtlcValueInFlightMsat" : 14850000000, "initialRequestedChannelReserve_opt" : 150000, "htlcMinimum" : 1000, - "toSelfDelay" : 1802, + "toRemoteDelay" : 1802, "maxAcceptedHtlcs" : 483, "revocationBasepoint" : "03d17fdddddae4aeeb7022dedf059f1d0f06b4b68b6309cade4e55ae1ac0f0230c", "paymentBasepoint" : "03c0c4257191e5c4b6e7dcf2e9fb9be00fc713686f77fc4719987e77ee2436d8bd", diff --git a/eclair-core/src/test/resources/nonreg/codecs/020002-DATA_NORMAL/funder/data.json b/eclair-core/src/test/resources/nonreg/codecs/020002-DATA_NORMAL/funder/data.json index e552713d4a..a594bbd9c4 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/020002-DATA_NORMAL/funder/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/020002-DATA_NORMAL/funder/data.json @@ -1,7 +1,7 @@ { "type" : "DATA_NORMAL", "commitments" : { - "params" : { + "channelParams" : { "channelId" : "5986f644357956c1674f385e0878fb7bb44ab3d57ea9911fab98af8a71e1ad1b", "channelConfig" : [ "funding_pubkey_based_channel_keypath" ], "channelFeatures" : [ "option_static_remotekey" ], @@ -12,7 +12,7 @@ "maxHtlcValueInFlightMsat" : 20000000000, "initialRequestedChannelReserve_opt" : 150000, "htlcMinimum" : 1, - "toSelfDelay" : 720, + "toRemoteDelay" : 720, "maxAcceptedHtlcs" : 30, "isChannelOpener" : true, "paysCommitTxFees" : true, @@ -39,7 +39,7 @@ "maxHtlcValueInFlightMsat" : 14850000000, "initialRequestedChannelReserve_opt" : 150000, "htlcMinimum" : 1, - "toSelfDelay" : 1802, + "toRemoteDelay" : 1802, "maxAcceptedHtlcs" : 483, "revocationBasepoint" : "0343bf4bfbaea5c100f1f2bf1cdf82a0ef97c9a0069a2aec631e7c3084ba929b75", "paymentBasepoint" : "03c54e7d5ccfc13f1a6c7a441ffcfac86248574d1bc0fe9773836f4c724ea7b2bd", diff --git a/eclair-core/src/test/resources/nonreg/codecs/030000-DATA_WAIT_FOR_FUNDING_CONFIRMED/funder/data.json b/eclair-core/src/test/resources/nonreg/codecs/030000-DATA_WAIT_FOR_FUNDING_CONFIRMED/funder/data.json index aaac6823b9..0cb947422d 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/030000-DATA_WAIT_FOR_FUNDING_CONFIRMED/funder/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/030000-DATA_WAIT_FOR_FUNDING_CONFIRMED/funder/data.json @@ -1,7 +1,7 @@ { "type" : "DATA_WAIT_FOR_FUNDING_CONFIRMED", "commitments" : { - "params" : { + "channelParams" : { "channelId" : "e917adc681383fe00f779c6144a1bd91135ba2c9862ad1bc5aa8a14d37bae3f4", "channelConfig" : [ "funding_pubkey_based_channel_keypath" ], "channelFeatures" : [ ], @@ -12,7 +12,7 @@ "maxHtlcValueInFlightMsat" : 500000000, "initialRequestedChannelReserve_opt" : 10000, "htlcMinimum" : 0, - "toSelfDelay" : 144, + "toRemoteDelay" : 144, "maxAcceptedHtlcs" : 100, "isChannelOpener" : true, "paysCommitTxFees" : true, @@ -35,7 +35,7 @@ "maxHtlcValueInFlightMsat" : 18446744073709551615, "initialRequestedChannelReserve_opt" : 20000, "htlcMinimum" : 1000, - "toSelfDelay" : 144, + "toRemoteDelay" : 144, "maxAcceptedHtlcs" : 30, "revocationBasepoint" : "02f7c3bf47cdc640304eda4c761a26dfebfee561de15ba106f3d9982d3ef3fbe10", "paymentBasepoint" : "02be361b7bf1bdfb283cff3f83bf16f6f8fb67d3f480b541e76518939f667ab834", diff --git a/eclair-core/src/test/resources/nonreg/codecs/03000a-DATA_WAIT_FOR_CHANNEL_READY/funder/data.json b/eclair-core/src/test/resources/nonreg/codecs/03000a-DATA_WAIT_FOR_CHANNEL_READY/funder/data.json index 19dc177430..ad75510f4e 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/03000a-DATA_WAIT_FOR_CHANNEL_READY/funder/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/03000a-DATA_WAIT_FOR_CHANNEL_READY/funder/data.json @@ -1,7 +1,7 @@ { "type" : "DATA_WAIT_FOR_CHANNEL_READY", "commitments" : { - "params" : { + "channelParams" : { "channelId" : "83a6dea8adf975b60df17738937034a2f96cb8b784da01e2934e9e172244317d", "channelConfig" : [ "funding_pubkey_based_channel_keypath" ], "channelFeatures" : [ ], @@ -12,7 +12,7 @@ "maxHtlcValueInFlightMsat" : 500000000, "initialRequestedChannelReserve_opt" : 10000, "htlcMinimum" : 0, - "toSelfDelay" : 144, + "toRemoteDelay" : 144, "maxAcceptedHtlcs" : 100, "isChannelOpener" : true, "paysCommitTxFees" : true, @@ -36,7 +36,7 @@ "maxHtlcValueInFlightMsat" : 1000000000, "initialRequestedChannelReserve_opt" : 20000, "htlcMinimum" : 1000, - "toSelfDelay" : 144, + "toRemoteDelay" : 144, "maxAcceptedHtlcs" : 30, "revocationBasepoint" : "033b164d14b54f08a951f9e40fb84e637021f376c9ae2907975f9ff0795431205d", "paymentBasepoint" : "03759da3f6bdcc2f595e1a98eb4803729743ab8608e28788cfe96726b5328c214c", diff --git a/eclair-core/src/test/resources/nonreg/codecs/03000c-DATA_WAIT_FOR_DUAL_FUNDING_READY/funder/data.json b/eclair-core/src/test/resources/nonreg/codecs/03000c-DATA_WAIT_FOR_DUAL_FUNDING_READY/funder/data.json index 78c97bb722..039730f794 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/03000c-DATA_WAIT_FOR_DUAL_FUNDING_READY/funder/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/03000c-DATA_WAIT_FOR_DUAL_FUNDING_READY/funder/data.json @@ -1,7 +1,7 @@ { "type" : "DATA_WAIT_FOR_DUAL_FUNDING_READY", "commitments" : { - "params" : { + "channelParams" : { "channelId" : "f5cafea10bc83c2fe9de16d04bb73c1ddaed2ce9d600dd91301a7d995f7b9134", "channelConfig" : [ "funding_pubkey_based_channel_keypath" ], "channelFeatures" : [ "option_static_remotekey", "option_anchors_zero_fee_htlc_tx", "option_dual_fund" ], @@ -11,7 +11,7 @@ "dustLimit" : 1100, "maxHtlcValueInFlightMsat" : 500000000, "htlcMinimum" : 0, - "toSelfDelay" : 144, + "toRemoteDelay" : 144, "maxAcceptedHtlcs" : 100, "isChannelOpener" : true, "paysCommitTxFees" : true, @@ -38,7 +38,7 @@ "dustLimit" : 1000, "maxHtlcValueInFlightMsat" : 1000000000, "htlcMinimum" : 1000, - "toSelfDelay" : 144, + "toRemoteDelay" : 144, "maxAcceptedHtlcs" : 30, "revocationBasepoint" : "03626342f0af6e87ab41715bd6d1db7d6eee5e95a2a835680b42d9b357003c1c6a", "paymentBasepoint" : "02ed6013749b4e3a820e7c003d3d3c7c5f16dd0d25ce72d3de99e544d4011c0a67", diff --git a/eclair-core/src/test/resources/nonreg/codecs/04000b-DATA_WAIT_FOR_CHANNEL_READY/fundee/data.json b/eclair-core/src/test/resources/nonreg/codecs/04000b-DATA_WAIT_FOR_CHANNEL_READY/fundee/data.json index bca747bcc4..4eed16c4f0 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/04000b-DATA_WAIT_FOR_CHANNEL_READY/fundee/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/04000b-DATA_WAIT_FOR_CHANNEL_READY/fundee/data.json @@ -1,7 +1,7 @@ { "type" : "DATA_WAIT_FOR_CHANNEL_READY", "commitments" : { - "params" : { + "channelParams" : { "channelId" : "7d975ecb75e1497076150f745b83dace95a189eecb6172c20a9a4fe0f91b8d1d", "channelConfig" : [ "funding_pubkey_based_channel_keypath" ], "channelFeatures" : [ "option_static_remotekey" ], @@ -12,7 +12,7 @@ "maxHtlcValueInFlightMsat" : 1000000000, "initialRequestedChannelReserve_opt" : 20000, "htlcMinimum" : 1000, - "toSelfDelay" : 144, + "toRemoteDelay" : 144, "maxAcceptedHtlcs" : 30, "isChannelOpener" : false, "paysCommitTxFees" : false, @@ -41,7 +41,7 @@ "maxHtlcValueInFlightMsat" : 500000000, "initialRequestedChannelReserve_opt" : 10000, "htlcMinimum" : 0, - "toSelfDelay" : 144, + "toRemoteDelay" : 144, "maxAcceptedHtlcs" : 100, "revocationBasepoint" : "02e1a7010650cd5cd6fbf7505f5f213b36e5cc0d127064c74619c83dfa7434ce25", "paymentBasepoint" : "028feba10d0eafd0fad8fe20e6d9206e6bd30242826de05c63f459a00aced24b12", diff --git a/eclair-core/src/test/resources/nonreg/codecs/04000b-DATA_WAIT_FOR_CHANNEL_READY/funder/data.json b/eclair-core/src/test/resources/nonreg/codecs/04000b-DATA_WAIT_FOR_CHANNEL_READY/funder/data.json index bc335c7da4..fc48de0975 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/04000b-DATA_WAIT_FOR_CHANNEL_READY/funder/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/04000b-DATA_WAIT_FOR_CHANNEL_READY/funder/data.json @@ -1,7 +1,7 @@ { "type" : "DATA_WAIT_FOR_CHANNEL_READY", "commitments" : { - "params" : { + "channelParams" : { "channelId" : "7d975ecb75e1497076150f745b83dace95a189eecb6172c20a9a4fe0f91b8d1d", "channelConfig" : [ "funding_pubkey_based_channel_keypath" ], "channelFeatures" : [ "option_static_remotekey" ], @@ -12,7 +12,7 @@ "maxHtlcValueInFlightMsat" : 500000000, "initialRequestedChannelReserve_opt" : 10000, "htlcMinimum" : 0, - "toSelfDelay" : 144, + "toRemoteDelay" : 144, "maxAcceptedHtlcs" : 100, "isChannelOpener" : true, "paysCommitTxFees" : true, @@ -41,7 +41,7 @@ "maxHtlcValueInFlightMsat" : 1000000000, "initialRequestedChannelReserve_opt" : 20000, "htlcMinimum" : 1000, - "toSelfDelay" : 144, + "toRemoteDelay" : 144, "maxAcceptedHtlcs" : 30, "revocationBasepoint" : "0201dd773d2108f3ed8f59669240c7f098d3083963bef5b36ebf940f4bc40724c8", "paymentBasepoint" : "028feba10d0eafd0fad8fe20e6d9206e6bd30242826de05c63f459a00aced24b12", diff --git a/eclair-core/src/test/resources/nonreg/codecs/04000d-DATA_WAIT_FOR_DUAL_FUNDING_READY/fundee/data.json b/eclair-core/src/test/resources/nonreg/codecs/04000d-DATA_WAIT_FOR_DUAL_FUNDING_READY/fundee/data.json index 1c8cbee034..e5426ace13 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/04000d-DATA_WAIT_FOR_DUAL_FUNDING_READY/fundee/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/04000d-DATA_WAIT_FOR_DUAL_FUNDING_READY/fundee/data.json @@ -1,7 +1,7 @@ { "type" : "DATA_WAIT_FOR_DUAL_FUNDING_READY", "commitments" : { - "params" : { + "channelParams" : { "channelId" : "ae58e31828b115b8a900a9d20b060ef2b2da2fcfe18991aff34168579d246b54", "channelConfig" : [ "funding_pubkey_based_channel_keypath" ], "channelFeatures" : [ "option_static_remotekey", "option_anchors_zero_fee_htlc_tx", "option_dual_fund" ], @@ -11,7 +11,7 @@ "dustLimit" : 1000, "maxHtlcValueInFlightMsat" : 1000000000, "htlcMinimum" : 1000, - "toSelfDelay" : 144, + "toRemoteDelay" : 144, "maxAcceptedHtlcs" : 30, "isChannelOpener" : false, "paysCommitTxFees" : false, @@ -40,7 +40,7 @@ "dustLimit" : 1100, "maxHtlcValueInFlightMsat" : 500000000, "htlcMinimum" : 0, - "toSelfDelay" : 144, + "toRemoteDelay" : 144, "maxAcceptedHtlcs" : 100, "revocationBasepoint" : "038039cb4b63c81052cf0893e27f7be58a5808453dffd44c662b1a75aebb1fc74e", "paymentBasepoint" : "0394e61db71e79c20f2ef131e99121996c7ae04330c4c50dae6bccc5afcf493661", diff --git a/eclair-core/src/test/resources/nonreg/codecs/04000d-DATA_WAIT_FOR_DUAL_FUNDING_READY/funder/data.json b/eclair-core/src/test/resources/nonreg/codecs/04000d-DATA_WAIT_FOR_DUAL_FUNDING_READY/funder/data.json index 9f22731a67..fd8d104943 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/04000d-DATA_WAIT_FOR_DUAL_FUNDING_READY/funder/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/04000d-DATA_WAIT_FOR_DUAL_FUNDING_READY/funder/data.json @@ -1,7 +1,7 @@ { "type" : "DATA_WAIT_FOR_DUAL_FUNDING_READY", "commitments" : { - "params" : { + "channelParams" : { "channelId" : "ae58e31828b115b8a900a9d20b060ef2b2da2fcfe18991aff34168579d246b54", "channelConfig" : [ "funding_pubkey_based_channel_keypath" ], "channelFeatures" : [ "option_static_remotekey", "option_anchors_zero_fee_htlc_tx", "option_dual_fund" ], @@ -11,7 +11,7 @@ "dustLimit" : 1100, "maxHtlcValueInFlightMsat" : 500000000, "htlcMinimum" : 0, - "toSelfDelay" : 144, + "toRemoteDelay" : 144, "maxAcceptedHtlcs" : 100, "isChannelOpener" : true, "paysCommitTxFees" : true, @@ -41,7 +41,7 @@ "dustLimit" : 1000, "maxHtlcValueInFlightMsat" : 1000000000, "htlcMinimum" : 1000, - "toSelfDelay" : 144, + "toRemoteDelay" : 144, "maxAcceptedHtlcs" : 30, "revocationBasepoint" : "031a9b266c6a1f5d05f6f2b040b0eea59819c2fb5715945628541c58c2605e5c42", "paymentBasepoint" : "02cb3e21fe0825663cfa1d8a8accc93dedbdb906b0ec4b779bb41b0f030b38fd33", diff --git a/eclair-core/src/test/resources/nonreg/codecs/04000e-DATA_NORMAL/announced/data.json b/eclair-core/src/test/resources/nonreg/codecs/04000e-DATA_NORMAL/announced/data.json index 978c58072e..1ed6f0b14f 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/04000e-DATA_NORMAL/announced/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/04000e-DATA_NORMAL/announced/data.json @@ -1,7 +1,7 @@ { "type" : "DATA_NORMAL", "commitments" : { - "params" : { + "channelParams" : { "channelId" : "c380aa11700db0a6d797dfd0be8aecfadad9397e4975f0fa8c9d10db71feac38", "channelConfig" : [ "funding_pubkey_based_channel_keypath" ], "channelFeatures" : [ "option_static_remotekey" ], @@ -12,7 +12,7 @@ "maxHtlcValueInFlightMsat" : 500000000, "initialRequestedChannelReserve_opt" : 10000, "htlcMinimum" : 0, - "toSelfDelay" : 144, + "toRemoteDelay" : 144, "maxAcceptedHtlcs" : 100, "isChannelOpener" : true, "paysCommitTxFees" : true, @@ -41,7 +41,7 @@ "maxHtlcValueInFlightMsat" : 1000000000, "initialRequestedChannelReserve_opt" : 20000, "htlcMinimum" : 1000, - "toSelfDelay" : 144, + "toRemoteDelay" : 144, "maxAcceptedHtlcs" : 30, "revocationBasepoint" : "02f943c4f199d1425fc6e52f160be536d526e9643af1430cfed4ce63f88beebd2f", "paymentBasepoint" : "028feba10d0eafd0fad8fe20e6d9206e6bd30242826de05c63f459a00aced24b12", diff --git a/eclair-core/src/test/resources/nonreg/codecs/04000e-DATA_NORMAL/splicing-private/data.json b/eclair-core/src/test/resources/nonreg/codecs/04000e-DATA_NORMAL/splicing-private/data.json index 2239df8f75..1000fae8d6 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/04000e-DATA_NORMAL/splicing-private/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/04000e-DATA_NORMAL/splicing-private/data.json @@ -1,7 +1,7 @@ { "type" : "DATA_NORMAL", "commitments" : { - "params" : { + "channelParams" : { "channelId" : "9c5655e99c1ef6d219eb093ca9f29e642167b4c776928df11c73e2293086b749", "channelConfig" : [ "funding_pubkey_based_channel_keypath" ], "channelFeatures" : [ "option_static_remotekey", "option_dual_fund" ], @@ -11,7 +11,7 @@ "dustLimit" : 1000, "maxHtlcValueInFlightMsat" : 9223372036854775807, "htlcMinimum" : 1000, - "toSelfDelay" : 144, + "toRemoteDelay" : 144, "maxAcceptedHtlcs" : 30, "isChannelOpener" : false, "paysCommitTxFees" : false, @@ -40,7 +40,7 @@ "dustLimit" : 1100, "maxHtlcValueInFlightMsat" : 9223372036854775807, "htlcMinimum" : 0, - "toSelfDelay" : 144, + "toRemoteDelay" : 144, "maxAcceptedHtlcs" : 100, "revocationBasepoint" : "02fab0332aecd8006f4937b220ea073b0e814a21e36f4d21de9bb3e5165c3ffa02", "paymentBasepoint" : "038bff1253b7b8e40532508a53d31b95b295df31edf0d067d734479a680bd395de", diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala b/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala index b46d18b45f..b70c83e11a 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala @@ -257,7 +257,7 @@ object TestConstants { offersConfig = OffersConfig(messagePathMinLength = 2, paymentPathCount = 2, paymentPathLength = 4, paymentPathCltvExpiryDelta = CltvExpiryDelta(500)), ) - def channelParams: LocalParams = OpenChannelInterceptor.makeChannelParams( + def channelParams: LocalChannelParams = OpenChannelInterceptor.makeChannelParams( nodeParams, nodeParams.features.initFeatures(), None, @@ -326,8 +326,8 @@ object TestConstants { maxChannelSpentRescanBlocks = 144, htlcMinimum = 1000 msat, minDepth = 3, - toRemoteDelay = CltvExpiryDelta(144), - maxToLocalDelay = CltvExpiryDelta(1000), + toRemoteDelay = CltvExpiryDelta(720), + maxToLocalDelay = CltvExpiryDelta(2016), reserveToFundingRatio = 0.01, // note: not used (overridden below) maxReserveToFundingRatio = 0.05, unhandledExceptionStrategy = UnhandledExceptionStrategy.LocalClose, @@ -447,7 +447,7 @@ object TestConstants { offersConfig = OffersConfig(messagePathMinLength = 2, paymentPathCount = 2, paymentPathLength = 4, paymentPathCltvExpiryDelta = CltvExpiryDelta(500)), ) - def channelParams: LocalParams = OpenChannelInterceptor.makeChannelParams( + def channelParams: LocalChannelParams = OpenChannelInterceptor.makeChannelParams( nodeParams, nodeParams.features.initFeatures(), None, diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/CommitmentsSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/CommitmentsSpec.scala index 4753b16e0f..55e64211a1 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/CommitmentsSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/CommitmentsSpec.scala @@ -491,8 +491,8 @@ object CommitmentsSpec { def makeCommitments(toLocal: MilliSatoshi, toRemote: MilliSatoshi, feeRatePerKw: FeeratePerKw = FeeratePerKw(0 sat), dustLimit: Satoshi = 0 sat, isOpener: Boolean = true, announcement_opt: Option[ChannelAnnouncement] = None): Commitments = { val channelReserve = (toLocal + toRemote).truncateToSatoshi * 0.01 - val localParams = LocalParams(randomKey().publicKey, DeterministicWallet.KeyPath(Seq(42L)), dustLimit, UInt64.MaxValue, Some(channelReserve), 1 msat, CltvExpiryDelta(144), 50, isOpener, isOpener, None, None, Features.empty) - val remoteParams = RemoteParams(randomKey().publicKey, dustLimit, UInt64.MaxValue, Some(channelReserve), 1 msat, CltvExpiryDelta(144), 50, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, Features.empty, None) + val localChannelParams = LocalChannelParams(randomKey().publicKey, DeterministicWallet.KeyPath(Seq(42L)), dustLimit, UInt64.MaxValue, Some(channelReserve), 1 msat, CltvExpiryDelta(144), 50, isOpener, isOpener, None, None, Features.empty) + val remoteChannelParams = RemoteChannelParams(randomKey().publicKey, dustLimit, UInt64.MaxValue, Some(channelReserve), 1 msat, CltvExpiryDelta(144), 50, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, Features.empty, None) val localFundingPubKey = randomKey().publicKey val remoteFundingPubKey = randomKey().publicKey val fundingTx = Transaction(2, Nil, Seq(TxOut((toLocal + toRemote).truncateToSatoshi, Funding.makeFundingScript(localFundingPubKey, remoteFundingPubKey, DefaultCommitmentFormat).pubkeyScript)), 0) @@ -504,7 +504,7 @@ object CommitmentsSpec { case None => LocalFundingStatus.SingleFundedUnconfirmedFundingTx(None) } Commitments( - ChannelParams(randomBytes32(), ChannelConfig.standard, ChannelFeatures(), localParams, remoteParams, ChannelFlags(announceChannel = announcement_opt.nonEmpty)), + ChannelParams(randomBytes32(), ChannelConfig.standard, ChannelFeatures(), localChannelParams, remoteChannelParams, ChannelFlags(announceChannel = announcement_opt.nonEmpty)), CommitmentChanges(LocalChanges(Nil, Nil, Nil), RemoteChanges(Nil, Nil, Nil), localNextHtlcId = 1, remoteNextHtlcId = 1), List(Commitment(0, 0, remoteFundingPubKey, localFundingStatus, RemoteFundingStatus.Locked, localCommit, remoteCommit, None)), inactive = Nil, @@ -516,8 +516,8 @@ object CommitmentsSpec { def makeCommitments(toLocal: MilliSatoshi, toRemote: MilliSatoshi, localNodeId: PublicKey, remoteNodeId: PublicKey, announcement_opt: Option[ChannelAnnouncement]): Commitments = { val channelReserve = (toLocal + toRemote).truncateToSatoshi * 0.01 - val localParams = LocalParams(localNodeId, DeterministicWallet.KeyPath(Seq(42L)), 0 sat, UInt64.MaxValue, Some(channelReserve), 1 msat, CltvExpiryDelta(144), 50, isChannelOpener = true, paysCommitTxFees = true, None, None, Features.empty) - val remoteParams = RemoteParams(remoteNodeId, 0 sat, UInt64.MaxValue, Some(channelReserve), 1 msat, CltvExpiryDelta(144), 50, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, Features.empty, None) + val localChannelParams = LocalChannelParams(localNodeId, DeterministicWallet.KeyPath(Seq(42L)), 0 sat, UInt64.MaxValue, Some(channelReserve), 1 msat, CltvExpiryDelta(144), 50, isChannelOpener = true, paysCommitTxFees = true, None, None, Features.empty) + val remoteChannelParams = RemoteChannelParams(remoteNodeId, 0 sat, UInt64.MaxValue, Some(channelReserve), 1 msat, CltvExpiryDelta(144), 50, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, Features.empty, None) val localFundingPubKey = randomKey().publicKey val remoteFundingPubKey = randomKey().publicKey val fundingTx = Transaction(2, Nil, Seq(TxOut((toLocal + toRemote).truncateToSatoshi, Funding.makeFundingScript(localFundingPubKey, remoteFundingPubKey, DefaultCommitmentFormat).pubkeyScript)), 0) @@ -529,7 +529,7 @@ object CommitmentsSpec { case None => LocalFundingStatus.SingleFundedUnconfirmedFundingTx(None) } Commitments( - ChannelParams(randomBytes32(), ChannelConfig.standard, ChannelFeatures(), localParams, remoteParams, ChannelFlags(announceChannel = announcement_opt.nonEmpty)), + ChannelParams(randomBytes32(), ChannelConfig.standard, ChannelFeatures(), localChannelParams, remoteChannelParams, ChannelFlags(announceChannel = announcement_opt.nonEmpty)), CommitmentChanges(LocalChanges(Nil, Nil, Nil), RemoteChanges(Nil, Nil, Nil), localNextHtlcId = 1, remoteNextHtlcId = 1), List(Commitment(0, 0, remoteFundingPubKey, localFundingStatus, RemoteFundingStatus.Locked, localCommit, remoteCommit, None)), inactive = Nil, diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/FuzzySpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/FuzzySpec.scala index 958d8a8068..f0cd847d75 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/FuzzySpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/FuzzySpec.scala @@ -55,6 +55,10 @@ class FuzzySpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with Channe val pipe = system.actorOf(Props(new FuzzyPipe(fuzzy))) val aliceParams = Alice.nodeParams val bobParams = Bob.nodeParams + val aliceChannelParams = Alice.channelParams + val bobChannelParams = Bob.channelParams + val aliceCommitParams = aliceChannelParams.proposedCommitParams + val bobCommitParams = bobChannelParams.proposedCommitParams val channelFlags = ChannelFlags(announceChannel = false) val alicePeer = TestProbe() val bobPeer = TestProbe() @@ -72,14 +76,14 @@ class FuzzySpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with Channe val alice: TestFSMRef[ChannelState, ChannelData, Channel] = TestFSMRef(new Channel(aliceParams, Alice.channelKeys(), wallet, bobParams.nodeId, alice2blockchain.ref, aliceRelayer, FakeTxPublisherFactory(alice2blockchain)), alicePeer.ref) val bob: TestFSMRef[ChannelState, ChannelData, Channel] = TestFSMRef(new Channel(bobParams, Bob.channelKeys(), wallet, aliceParams.nodeId, bob2blockchain.ref, bobRelayer, FakeTxPublisherFactory(bob2blockchain)), bobPeer.ref) within(30 seconds) { - val aliceInit = Init(Alice.channelParams.initFeatures) - val bobInit = Init(Bob.channelParams.initFeatures) + val aliceInit = Init(aliceChannelParams.initFeatures) + val bobInit = Init(bobChannelParams.initFeatures) aliceRegister ! alice bobRegister ! bob // no announcements - alice ! INPUT_INIT_CHANNEL_INITIATOR(ByteVector32.Zeroes, TestConstants.fundingSatoshis, dualFunded = false, TestConstants.feeratePerKw, TestConstants.feeratePerKw, fundingTxFeeBudget_opt = None, Some(TestConstants.initiatorPushAmount), requireConfirmedInputs = false, requestFunding_opt = None, Alice.channelParams, pipe, bobInit, channelFlags, ChannelConfig.standard, ChannelTypes.Standard(), replyTo = system.deadLetters) + alice ! INPUT_INIT_CHANNEL_INITIATOR(ByteVector32.Zeroes, TestConstants.fundingSatoshis, dualFunded = false, TestConstants.feeratePerKw, TestConstants.feeratePerKw, fundingTxFeeBudget_opt = None, Some(TestConstants.initiatorPushAmount), requireConfirmedInputs = false, requestFunding_opt = None, aliceChannelParams, aliceCommitParams, pipe, bobInit, channelFlags, ChannelConfig.standard, ChannelTypes.Standard(), replyTo = system.deadLetters) alice2blockchain.expectMsgType[TxPublisher.SetChannelId] - bob ! INPUT_INIT_CHANNEL_NON_INITIATOR(ByteVector32.Zeroes, None, dualFunded = false, None, requireConfirmedInputs = false, Bob.channelParams, pipe, aliceInit, ChannelConfig.standard, ChannelTypes.Standard()) + bob ! INPUT_INIT_CHANNEL_NON_INITIATOR(ByteVector32.Zeroes, None, dualFunded = false, None, requireConfirmedInputs = false, bobChannelParams, bobCommitParams, pipe, aliceInit, ChannelConfig.standard, ChannelTypes.Standard()) bob2blockchain.expectMsgType[TxPublisher.SetChannelId] pipe ! (alice, bob) alice2blockchain.expectMsgType[TxPublisher.SetChannelId] diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/InteractiveTxBuilderSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/InteractiveTxBuilderSpec.scala index c3d851266c..ca2cd2c6f9 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/InteractiveTxBuilderSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/InteractiveTxBuilderSpec.scala @@ -95,9 +95,11 @@ class InteractiveTxBuilderSpec extends TestKitBaseClass with AnyFunSuiteLike wit case class FixtureParams(fundingParamsA: InteractiveTxParams, nodeParamsA: NodeParams, channelParamsA: ChannelParams, + commitParamsA: CommitParams, fundingParamsB: InteractiveTxParams, nodeParamsB: NodeParams, channelParamsB: ChannelParams, + commitParamsB: CommitParams, channelFeatures: ChannelFeatures) { val channelId: ByteVector32 = fundingParamsA.channelId val commitFeerate: FeeratePerKw = TestConstants.anchorOutputsFeeratePerKw @@ -217,16 +219,18 @@ class InteractiveTxBuilderSpec extends TestKitBaseClass with AnyFunSuiteLike wit private def createFixtureParams(fundingAmountA: Satoshi, fundingAmountB: Satoshi, targetFeerate: FeeratePerKw, dustLimit: Satoshi, lockTime: Long, requireConfirmedInputs: RequireConfirmedInputs = RequireConfirmedInputs(forLocal = false, forRemote = false), nonInitiatorPaysCommitTxFees: Boolean = false): FixtureParams = { val channelFeatures = ChannelFeatures(ChannelTypes.AnchorOutputsZeroFeeHtlcTx(), Features[InitFeature](Features.DualFunding -> FeatureSupport.Optional), Features[InitFeature](Features.DualFunding -> FeatureSupport.Optional), announceChannel = true) val Seq(nodeParamsA, nodeParamsB) = Seq(TestConstants.Alice.nodeParams, TestConstants.Bob.nodeParams).map(_.copy(features = Features(channelFeatures.features.map(f => f -> FeatureSupport.Optional).toMap[Feature, FeatureSupport]))) - val localParamsA = makeChannelParams(nodeParamsA, nodeParamsA.features.initFeatures(), None, None, isChannelOpener = true, paysCommitTxFees = !nonInitiatorPaysCommitTxFees, dualFunded = true, fundingAmountA, unlimitedMaxHtlcValueInFlight = false) - val localParamsB = makeChannelParams(nodeParamsB, nodeParamsB.features.initFeatures(), None, None, isChannelOpener = false, paysCommitTxFees = nonInitiatorPaysCommitTxFees, dualFunded = true, fundingAmountB, unlimitedMaxHtlcValueInFlight = false) - val channelKeysA = nodeParamsA.channelKeyManager.channelKeys(ChannelConfig.standard, localParamsA.fundingKeyPath) - val channelKeysB = nodeParamsB.channelKeyManager.channelKeys(ChannelConfig.standard, localParamsB.fundingKeyPath) - - val Seq(remoteParamsA, remoteParamsB) = Seq((nodeParamsA, localParamsA, channelKeysA), (nodeParamsB, localParamsB, channelKeysB)).map { + val localChannelParamsA = makeChannelParams(nodeParamsA, nodeParamsA.features.initFeatures(), None, None, isChannelOpener = true, paysCommitTxFees = !nonInitiatorPaysCommitTxFees, dualFunded = true, fundingAmountA, unlimitedMaxHtlcValueInFlight = false) + val commitParamsA = CommitParams(nodeParamsA.channelConf.dustLimit, nodeParamsA.channelConf.htlcMinimum, nodeParamsA.channelConf.maxHtlcValueInFlight(fundingAmountA + fundingAmountB, unlimited = false), nodeParamsA.channelConf.maxAcceptedHtlcs, nodeParamsB.channelConf.toRemoteDelay) + val localChannelParamsB = makeChannelParams(nodeParamsB, nodeParamsB.features.initFeatures(), None, None, isChannelOpener = false, paysCommitTxFees = nonInitiatorPaysCommitTxFees, dualFunded = true, fundingAmountB, unlimitedMaxHtlcValueInFlight = false) + val commitParamsB = CommitParams(nodeParamsB.channelConf.dustLimit, nodeParamsB.channelConf.htlcMinimum, nodeParamsB.channelConf.maxHtlcValueInFlight(fundingAmountA + fundingAmountB, unlimited = false), nodeParamsB.channelConf.maxAcceptedHtlcs, nodeParamsA.channelConf.toRemoteDelay) + val channelKeysA = nodeParamsA.channelKeyManager.channelKeys(ChannelConfig.standard, localChannelParamsA.fundingKeyPath) + val channelKeysB = nodeParamsB.channelKeyManager.channelKeys(ChannelConfig.standard, localChannelParamsB.fundingKeyPath) + + val Seq(remoteChannelParamsA, remoteChannelParamsB) = Seq((nodeParamsA, localChannelParamsA, channelKeysA), (nodeParamsB, localChannelParamsB, channelKeysB)).map { case (nodeParams, localParams, channelKeys) => - RemoteParams( + RemoteChannelParams( nodeParams.nodeId, - localParams.dustLimit, localParams.maxHtlcValueInFlightMsat, None, localParams.htlcMinimum, localParams.toSelfDelay, localParams.maxAcceptedHtlcs, + localParams.dustLimit, localParams.maxHtlcValueInFlightMsat, None, localParams.htlcMinimum, nodeParams.channelConf.toRemoteDelay, localParams.maxAcceptedHtlcs, channelKeys.revocationBasePoint, localParams.walletStaticPaymentBasepoint.getOrElse(channelKeys.paymentBasePoint), channelKeys.delayedPaymentBasePoint, @@ -240,10 +244,10 @@ class InteractiveTxBuilderSpec extends TestKitBaseClass with AnyFunSuiteLike wit val fundingPubKeyB = channelKeysB.fundingKey(fundingTxIndex = 0).publicKey val fundingParamsA = InteractiveTxParams(channelId, isInitiator = true, fundingAmountA, fundingAmountB, None, fundingPubKeyB, Nil, lockTime, dustLimit, targetFeerate, requireConfirmedInputs) val fundingParamsB = InteractiveTxParams(channelId, isInitiator = false, fundingAmountB, fundingAmountA, None, fundingPubKeyA, Nil, lockTime, dustLimit, targetFeerate, requireConfirmedInputs) - val channelParamsA = ChannelParams(channelId, ChannelConfig.standard, channelFeatures, localParamsA, remoteParamsB, ChannelFlags(announceChannel = true)) - val channelParamsB = ChannelParams(channelId, ChannelConfig.standard, channelFeatures, localParamsB, remoteParamsA, ChannelFlags(announceChannel = true)) + val channelParamsA = ChannelParams(channelId, ChannelConfig.standard, channelFeatures, localChannelParamsA, remoteChannelParamsB, ChannelFlags(announceChannel = true)) + val channelParamsB = ChannelParams(channelId, ChannelConfig.standard, channelFeatures, localChannelParamsB, remoteChannelParamsA, ChannelFlags(announceChannel = true)) - FixtureParams(fundingParamsA, nodeParamsA, channelParamsA, fundingParamsB, nodeParamsB, channelParamsB, channelFeatures) + FixtureParams(fundingParamsA, nodeParamsA, channelParamsA, commitParamsA, fundingParamsB, nodeParamsB, channelParamsB, commitParamsB, channelFeatures) } case class Fixture(alice: ActorRef[InteractiveTxBuilder.Command], diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/RestoreSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/RestoreSpec.scala index f6a2347c10..7d0f27c798 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/RestoreSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/RestoreSpec.scala @@ -94,7 +94,7 @@ class RestoreSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with Chan val OP_0 :: OP_PUSHDATA(pubKeyHash, _) :: Nil = Script.parse(ourOutput.publicKeyScript) // check that our output in Bob's commit tx sends to our static payment point - val Some(ourStaticPaymentPoint) = oldStateData.asInstanceOf[DATA_NORMAL].commitments.params.localParams.walletStaticPaymentBasepoint + val Some(ourStaticPaymentPoint) = oldStateData.asInstanceOf[DATA_NORMAL].commitments.localChannelParams.walletStaticPaymentBasepoint assert(pubKeyHash == ourStaticPaymentPoint.hash160) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/publish/ReplaceableTxPublisherSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/publish/ReplaceableTxPublisherSpec.scala index 8b20dc744e..0ef8c61666 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/publish/ReplaceableTxPublisherSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/publish/ReplaceableTxPublisherSpec.scala @@ -1601,7 +1601,7 @@ class ReplaceableTxPublisherSpec extends TestKitBaseClass with AnyFunSuiteLike w // Force-close channel and verify txs sent to watcher. val remoteCommitTx = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.latest.fullySignedLocalCommitTx(bob.underlyingActor.channelKeys) - bob.stateData.asInstanceOf[DATA_NORMAL].commitments.params.commitmentFormat match { + bob.stateData.asInstanceOf[DATA_NORMAL].commitments.latest.commitmentFormat match { case Transactions.DefaultCommitmentFormat => assert(remoteCommitTx.txOut.size == 4) case _: AnchorOutputsCommitmentFormat | _: SimpleTaprootChannelCommitmentFormat => assert(remoteCommitTx.txOut.size == 6) } @@ -1612,11 +1612,11 @@ class ReplaceableTxPublisherSpec extends TestKitBaseClass with AnyFunSuiteLike w probe.expectMsg(remoteCommitTx.txid) generateBlocks(1) - val anchorTx_opt = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.params.commitmentFormat match { + val anchorTx_opt = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.latest.commitmentFormat match { case Transactions.DefaultCommitmentFormat => None case _: AnchorOutputsCommitmentFormat | _: SimpleTaprootChannelCommitmentFormat => Some(alice2blockchain.expectReplaceableTxPublished[ClaimRemoteAnchorTx]) } - val mainTx_opt = if (!bob.stateData.asInstanceOf[DATA_NORMAL].commitments.params.channelFeatures.paysDirectlyToWallet) Some(alice2blockchain.expectFinalTxPublished("remote-main-delayed")) else None + val mainTx_opt = if (!bob.stateData.asInstanceOf[DATA_NORMAL].commitments.channelParams.channelFeatures.paysDirectlyToWallet) Some(alice2blockchain.expectFinalTxPublished("remote-main-delayed")) else None val claimHtlcSuccess = alice2blockchain.expectMsgType[PublishReplaceableTx].copy(confirmationTarget = ConfirmationTarget.Absolute(overrideHtlcTarget)) assert(claimHtlcSuccess.txInfo.isInstanceOf[ClaimHtlcSuccessTx]) val claimHtlcTimeout = alice2blockchain.expectMsgType[PublishReplaceableTx].copy(confirmationTarget = ConfirmationTarget.Absolute(overrideHtlcTarget)) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/ChannelStateTestsHelperMethods.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/ChannelStateTestsHelperMethods.scala index 4f238b3979..84aead51e2 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/ChannelStateTestsHelperMethods.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/ChannelStateTestsHelperMethods.scala @@ -22,7 +22,7 @@ import akka.testkit.{TestFSMRef, TestKit, TestProbe} import com.softwaremill.quicklens.ModifyPimp import fr.acinq.bitcoin.ScriptFlags import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey -import fr.acinq.bitcoin.scalacompat.{ByteVector32, Crypto, SatoshiLong, Script, Transaction} +import fr.acinq.bitcoin.scalacompat.{ByteVector32, Crypto, Satoshi, SatoshiLong, Script, Transaction} import fr.acinq.eclair.TestConstants.{Alice, Bob} import fr.acinq.eclair._ import fr.acinq.eclair.blockchain.bitcoind.ZmqWatcher._ @@ -119,6 +119,77 @@ trait ChannelStateTestsBase extends Assertions with Eventually { def currentBlockHeight: BlockHeight = alice.underlyingActor.nodeParams.currentBlockHeight } + case class ChannelParamsFixture(aliceChannelParams: LocalChannelParams, + aliceCommitParams: CommitParams, + aliceInitFeatures: Features[InitFeature], + bobChannelParams: LocalChannelParams, + bobCommitParams: CommitParams, + bobInitFeatures: Features[InitFeature], + channelType: SupportedChannelType, + alice2bob: TestProbe, + bob2alice: TestProbe, + aliceOpenReplyTo: TestProbe) { + def initChannelAlice(fundingAmount: Satoshi, + dualFunded: Boolean = false, + requireConfirmedInputs: Boolean = false, + channelFlags: ChannelFlags = ChannelFlags(announceChannel = false), + requestFunding_opt: Option[LiquidityAds.RequestFunding] = None, + pushAmount_opt: Option[MilliSatoshi] = None): INPUT_INIT_CHANNEL_INITIATOR = { + INPUT_INIT_CHANNEL_INITIATOR( + temporaryChannelId = ByteVector32.Zeroes, + fundingAmount = fundingAmount, + dualFunded = dualFunded, + commitTxFeerate = channelType.commitmentFormat match { + case DefaultCommitmentFormat => TestConstants.feeratePerKw + case _ => TestConstants.anchorOutputsFeeratePerKw + }, + fundingTxFeerate = TestConstants.feeratePerKw, + fundingTxFeeBudget_opt = None, + pushAmount_opt = pushAmount_opt, + requireConfirmedInputs = requireConfirmedInputs, + requestFunding_opt = requestFunding_opt, + localChannelParams = aliceChannelParams, + proposedCommitParams = ProposedCommitParams( + localDustLimit = aliceCommitParams.dustLimit, + localHtlcMinimum = aliceCommitParams.htlcMinimum, + localMaxHtlcValueInFlight = aliceCommitParams.maxHtlcValueInFlight, + localMaxAcceptedHtlcs = aliceCommitParams.maxAcceptedHtlcs, + toRemoteDelay = bobCommitParams.toSelfDelay + ), + remote = alice2bob.ref, + remoteInit = Init(bobInitFeatures), + channelFlags = channelFlags, + channelConfig = ChannelConfig.standard, + channelType = channelType, + replyTo = aliceOpenReplyTo.ref.toTyped + ) + } + + def initChannelBob(fundingContribution_opt: Option[LiquidityAds.AddFunding] = None, + dualFunded: Boolean = false, + requireConfirmedInputs: Boolean = false, + pushAmount_opt: Option[MilliSatoshi] = None): INPUT_INIT_CHANNEL_NON_INITIATOR = { + INPUT_INIT_CHANNEL_NON_INITIATOR( + temporaryChannelId = ByteVector32.Zeroes, + fundingContribution_opt = fundingContribution_opt, + dualFunded = dualFunded, + pushAmount_opt = pushAmount_opt, + requireConfirmedInputs = requireConfirmedInputs, + localChannelParams = bobChannelParams, + proposedCommitParams = ProposedCommitParams( + localDustLimit = bobCommitParams.dustLimit, + localHtlcMinimum = bobCommitParams.htlcMinimum, + localMaxHtlcValueInFlight = bobCommitParams.maxHtlcValueInFlight, + localMaxAcceptedHtlcs = bobCommitParams.maxAcceptedHtlcs, + toRemoteDelay = aliceCommitParams.toSelfDelay + ), + remote = bob2alice.ref, + remoteInit = Init(aliceInitFeatures), + channelConfig = ChannelConfig.standard, + channelType = channelType) + } + } + implicit val system: ActorSystem val systemA: ActorSystem = ActorSystem("system-alice") val systemB: ActorSystem = ActorSystem("system-bob") @@ -209,13 +280,12 @@ trait ChannelStateTestsBase extends Assertions with Eventually { (nodeParamsA1, nodeParamsB1) } - def computeFeatures(setup: SetupFixture, tags: Set[String], channelFlags: ChannelFlags): (LocalParams, LocalParams, SupportedChannelType) = { + def computeChannelParams(setup: SetupFixture, tags: Set[String], channelFlags: ChannelFlags = ChannelFlags(announceChannel = false)): ChannelParamsFixture = { import setup._ val (nodeParamsA, nodeParamsB) = updateInitFeatures(alice.underlyingActor.nodeParams, bob.underlyingActor.nodeParams, tags) val aliceInitFeatures = nodeParamsA.features.initFeatures() val bobInitFeatures = nodeParamsB.features.initFeatures() - val channelType = ChannelTypes.defaultFromFeatures(aliceInitFeatures, bobInitFeatures, announceChannel = channelFlags.announceChannel) // those features can only be enabled with AnchorOutputsZeroFeeHtlcTxs, this is to prevent incompatible test configurations @@ -223,7 +293,7 @@ trait ChannelStateTestsBase extends Assertions with Eventually { if (tags.contains(ChannelStateTestsTags.ScidAlias)) assert(tags.contains(ChannelStateTestsTags.AnchorOutputsZeroFeeHtlcTxs), "invalid test configuration") implicit val ec: scala.concurrent.ExecutionContext = scala.concurrent.ExecutionContext.global - val aliceParams = Alice.channelParams + val aliceChannelParams = Alice.channelParams .modify(_.initFeatures).setTo(aliceInitFeatures) .modify(_.walletStaticPaymentBasepoint).setToIf(channelType.paysDirectlyToWallet)(Some(Await.result(wallet.getP2wpkhPubkey(), 10 seconds))) .modify(_.maxHtlcValueInFlightMsat).setToIf(tags.contains(ChannelStateTestsTags.NoMaxHtlcValueInFlight))(UInt64.MaxValue) @@ -232,7 +302,7 @@ trait ChannelStateTestsBase extends Assertions with Eventually { .modify(_.dustLimit).setToIf(tags.contains(ChannelStateTestsTags.HighDustLimitDifferenceBobAlice))(1000 sat) .modify(_.initialRequestedChannelReserve_opt).setToIf(tags.contains(ChannelStateTestsTags.DualFunding))(None) .modify(_.upfrontShutdownScript_opt).setToIf(tags.contains(ChannelStateTestsTags.UpfrontShutdownScript))(Some(Script.write(Script.pay2wpkh(Await.result(wallet.getP2wpkhPubkey(), 10 seconds))))) - val bobParams = Bob.channelParams + val bobChannelParams = Bob.channelParams .modify(_.initFeatures).setTo(bobInitFeatures) .modify(_.walletStaticPaymentBasepoint).setToIf(channelType.paysDirectlyToWallet)(Some(Await.result(wallet.getP2wpkhPubkey(), 10 seconds))) .modify(_.maxHtlcValueInFlightMsat).setToIf(tags.contains(ChannelStateTestsTags.NoMaxHtlcValueInFlight))(UInt64.MaxValue) @@ -240,17 +310,17 @@ trait ChannelStateTestsBase extends Assertions with Eventually { .modify(_.dustLimit).setToIf(tags.contains(ChannelStateTestsTags.HighDustLimitDifferenceBobAlice))(5000 sat) .modify(_.initialRequestedChannelReserve_opt).setToIf(tags.contains(ChannelStateTestsTags.DualFunding))(None) .modify(_.upfrontShutdownScript_opt).setToIf(tags.contains(ChannelStateTestsTags.UpfrontShutdownScript))(Some(Script.write(Script.pay2wpkh(Await.result(wallet.getP2wpkhPubkey(), 10 seconds))))) + val aliceCommitParams = CommitParams(aliceChannelParams.dustLimit, aliceChannelParams.htlcMinimum, aliceChannelParams.maxHtlcValueInFlightMsat, aliceChannelParams.maxAcceptedHtlcs, bobChannelParams.toRemoteDelay) + val bobCommitParams = CommitParams(bobChannelParams.dustLimit, bobChannelParams.htlcMinimum, bobChannelParams.maxHtlcValueInFlightMsat, bobChannelParams.maxAcceptedHtlcs, aliceChannelParams.toRemoteDelay) - (aliceParams, bobParams, channelType) + ChannelParamsFixture(aliceChannelParams, aliceCommitParams, aliceInitFeatures, bobChannelParams, bobCommitParams, bobInitFeatures, channelType, alice2bob, bob2alice, aliceOpenReplyTo) } def reachNormal(setup: SetupFixture, tags: Set[String] = Set.empty): Transaction = { import setup._ - val channelConfig = ChannelConfig.standard val channelFlags = ChannelFlags(announceChannel = tags.contains(ChannelStateTestsTags.ChannelsPublic)) - val (aliceParams, bobParams, channelType) = computeFeatures(setup, tags, channelFlags) - val commitTxFeerate = if (tags.contains(ChannelStateTestsTags.AnchorOutputs) || tags.contains(ChannelStateTestsTags.AnchorOutputsZeroFeeHtlcTxs)) TestConstants.anchorOutputsFeeratePerKw else TestConstants.feeratePerKw + val channelParams = computeChannelParams(setup, tags, channelFlags) val fundingAmount = TestConstants.fundingSatoshis val initiatorPushAmount = if (tags.contains(ChannelStateTestsTags.NoPushAmount)) None else Some(TestConstants.initiatorPushAmount) val nonInitiatorPushAmount = if (tags.contains(ChannelStateTestsTags.NonInitiatorPushAmount)) Some(TestConstants.nonInitiatorPushAmount) else None @@ -271,11 +341,9 @@ trait ChannelStateTestsBase extends Assertions with Eventually { val eventListener = TestProbe() systemA.eventStream.subscribe(eventListener.ref, classOf[TransactionPublished]) - val aliceInit = Init(aliceParams.initFeatures) - val bobInit = Init(bobParams.initFeatures) - alice ! INPUT_INIT_CHANNEL_INITIATOR(ByteVector32.Zeroes, fundingAmount, dualFunded, commitTxFeerate, TestConstants.feeratePerKw, fundingTxFeeBudget_opt = None, initiatorPushAmount, requireConfirmedInputs = false, requestFunds_opt, aliceParams, alice2bob.ref, bobInit, channelFlags, channelConfig, channelType, replyTo = aliceOpenReplyTo.ref.toTyped) + alice ! channelParams.initChannelAlice(fundingAmount, dualFunded, pushAmount_opt = initiatorPushAmount, requestFunding_opt = requestFunds_opt, channelFlags = channelFlags) assert(alice2blockchain.expectMsgType[TxPublisher.SetChannelId].channelId == ByteVector32.Zeroes) - bob ! INPUT_INIT_CHANNEL_NON_INITIATOR(ByteVector32.Zeroes, nonInitiatorFunding_opt, dualFunded, nonInitiatorPushAmount, requireConfirmedInputs = false, bobParams, bob2alice.ref, aliceInit, channelConfig, channelType) + bob ! channelParams.initChannelBob(nonInitiatorFunding_opt, dualFunded, pushAmount_opt = nonInitiatorPushAmount) assert(bob2blockchain.expectMsgType[TxPublisher.SetChannelId].channelId == ByteVector32.Zeroes) val fundingTx = if (!dualFunded) { @@ -292,7 +360,7 @@ trait ChannelStateTestsBase extends Assertions with Eventually { val fundingTx = eventListener.expectMsgType[TransactionPublished].tx eventually(assert(alice.stateName == WAIT_FOR_FUNDING_CONFIRMED)) eventually(assert(bob.stateName == WAIT_FOR_FUNDING_CONFIRMED)) - if (channelType.features.contains(Features.ZeroConf)) { + if (channelParams.channelType.features.contains(Features.ZeroConf)) { alice2blockchain.expectMsgType[WatchPublished] bob2blockchain.expectMsgType[WatchPublished] alice ! WatchPublishedTriggered(fundingTx) @@ -346,7 +414,7 @@ trait ChannelStateTestsBase extends Assertions with Eventually { val fundingTx = eventListener.expectMsgType[TransactionPublished].tx eventually(assert(alice.stateName == WAIT_FOR_DUAL_FUNDING_CONFIRMED)) eventually(assert(bob.stateName == WAIT_FOR_DUAL_FUNDING_CONFIRMED)) - if (channelType.features.contains(Features.ZeroConf)) { + if (channelParams.channelType.features.contains(Features.ZeroConf)) { alice2blockchain.expectMsgType[WatchPublished] bob2blockchain.expectMsgType[WatchPublished] alice ! WatchPublishedTriggered(fundingTx) @@ -369,7 +437,7 @@ trait ChannelStateTestsBase extends Assertions with Eventually { } if (!tags.contains(ChannelStateTestsTags.DoNotInterceptGossip)) { - if (tags.contains(ChannelStateTestsTags.ChannelsPublic) && !channelType.features.contains(Features.ZeroConf)) { + if (tags.contains(ChannelStateTestsTags.ChannelsPublic) && !channelParams.channelType.features.contains(Features.ZeroConf)) { alice2bob.expectMsgType[AnnouncementSignatures] bob2alice.expectMsgType[AnnouncementSignatures] } @@ -517,7 +585,7 @@ trait ChannelStateTestsBase extends Assertions with Eventually { s2r.forward(r) r2s.expectMsgType[Shutdown] r2s.forward(s) - if (s.stateData.asInstanceOf[ChannelDataWithCommitments].commitments.params.localParams.initFeatures.hasFeature(Features.SimpleClose)) { + if (s.stateData.asInstanceOf[ChannelDataWithCommitments].commitments.localChannelParams.initFeatures.hasFeature(Features.SimpleClose)) { s2r.expectMsgType[ClosingComplete] s2r.forward(r) r2s.expectMsgType[ClosingComplete] @@ -573,13 +641,13 @@ trait ChannelStateTestsBase extends Assertions with Eventually { assert(commitTx.txid == closingState.commitments.latest.localCommit.txId) val commitInput = closingState.commitments.latest.commitInput Transaction.correctlySpends(commitTx, Map(commitInput.outPoint -> commitInput.txOut), ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS) - val publishedAnchorTx_opt = closingState.commitments.params.commitmentFormat match { + val publishedAnchorTx_opt = closingState.commitments.latest.commitmentFormat match { case DefaultCommitmentFormat => None case _: AnchorOutputsCommitmentFormat | _: SimpleTaprootChannelCommitmentFormat => Some(s2blockchain.expectReplaceableTxPublished[ClaimLocalAnchorTx].tx) } // if s has a main output in the commit tx (when it has a non-dust balance), it should be claimed val publishedMainTx_opt = localCommitPublished.localOutput_opt.map(_ => s2blockchain.expectFinalTxPublished("local-main-delayed").tx) - val (publishedHtlcSuccessTxs, publishedHtlcTimeoutTxs) = closingState.commitments.params.commitmentFormat match { + val (publishedHtlcSuccessTxs, publishedHtlcTimeoutTxs) = closingState.commitments.latest.commitmentFormat match { case Transactions.DefaultCommitmentFormat => // all htlcs success/timeout should be published as-is, we cannot RBF val publishedHtlcTxs = (0 until htlcSuccessCount + htlcTimeoutCount).map { _ => @@ -652,7 +720,7 @@ trait ChannelStateTestsBase extends Assertions with Eventually { assert(remoteCommitPublished.outgoingHtlcs.size == htlcTimeoutCount) // If anchor outputs is used, we use the anchor output to bump the fees if necessary. - val publishedAnchorTx_opt = closingData.commitments.params.commitmentFormat match { + val publishedAnchorTx_opt = closingData.commitments.latest.commitmentFormat match { case _: AnchorOutputsCommitmentFormat | _: SimpleTaprootChannelCommitmentFormat => Some(s2blockchain.expectReplaceableTxPublished[ClaimRemoteAnchorTx].tx) case Transactions.DefaultCommitmentFormat => None } @@ -710,9 +778,11 @@ object ChannelStateTestsBase { implicit class PimpTestFSM(private val channel: TestFSMRef[ChannelState, ChannelData, Channel]) { val nodeParams: NodeParams = channel.underlyingActor.nodeParams - def signCommitTx(): Transaction = channel.stateData.asInstanceOf[ChannelDataWithCommitments].commitments.latest.fullySignedLocalCommitTx(channel.underlyingActor.channelKeys) + def commitments: Commitments = channel.stateData.asInstanceOf[ChannelDataWithCommitments].commitments + + def signCommitTx(): Transaction = commitments.latest.fullySignedLocalCommitTx(channel.underlyingActor.channelKeys) - def htlcTxs(): Seq[UnsignedHtlcTx] = channel.stateData.asInstanceOf[ChannelDataWithCommitments].commitments.latest.htlcTxs(channel.underlyingActor.channelKeys).map(_._1) + def htlcTxs(): Seq[UnsignedHtlcTx] = commitments.latest.htlcTxs(channel.underlyingActor.channelKeys).map(_._1) def setBitcoinCoreFeerates(feerates: FeeratesPerKw): Unit = channel.underlyingActor.nodeParams.setBitcoinCoreFeerates(feerates) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForAcceptChannelStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForAcceptChannelStateSpec.scala index b66f872891..6987e09afa 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForAcceptChannelStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForAcceptChannelStateSpec.scala @@ -16,7 +16,6 @@ package fr.acinq.eclair.channel.states.a -import akka.actor.typed.scaladsl.adapter.ClassicActorRefOps import akka.testkit.{TestFSMRef, TestProbe} import com.softwaremill.quicklens.ModifyPimp import fr.acinq.bitcoin.scalacompat.{ByteVector32, SatoshiLong} @@ -28,8 +27,8 @@ import fr.acinq.eclair.channel.fsm.Channel.TickChannelOpenTimeout import fr.acinq.eclair.channel.states.{ChannelStateTestsBase, ChannelStateTestsTags} import fr.acinq.eclair.io.Peer.OpenChannelResponse import fr.acinq.eclair.transactions.Transactions.{DefaultCommitmentFormat, UnsafeLegacyAnchorOutputsCommitmentFormat, ZeroFeeHtlcTxAnchorOutputsCommitmentFormat} -import fr.acinq.eclair.wire.protocol.{AcceptChannel, ChannelTlv, Error, Init, OpenChannel, TlvStream} -import fr.acinq.eclair.{CltvExpiryDelta, FeatureSupport, Features, TestConstants, TestKitBaseClass} +import fr.acinq.eclair.wire.protocol.{AcceptChannel, ChannelTlv, Error, OpenChannel, TlvStream} +import fr.acinq.eclair.{CltvExpiryDelta, TestConstants, TestKitBaseClass} import org.scalatest.funsuite.FixtureAnyFunSuiteLike import org.scalatest.{Outcome, Tag} import scodec.bits.ByteVector @@ -51,22 +50,16 @@ class WaitForAcceptChannelStateSpec extends TestKitBaseClass with FixtureAnyFunS import com.softwaremill.quicklens._ val aliceNodeParams = Alice.nodeParams.modify(_.channelConf.maxRemoteDustLimit).setToIf(test.tags.contains(HighRemoteDustLimit))(15_000 sat) - val setup = init(aliceNodeParams, Bob.nodeParams, wallet_opt = Some(new NoOpOnChainWallet()), test.tags) import setup._ - val channelConfig = ChannelConfig.standard - val channelFlags = ChannelFlags(announceChannel = false) - val (aliceParams, bobParams, defaultChannelType) = computeFeatures(setup, test.tags, channelFlags) - val channelType = if (test.tags.contains(StandardChannelType)) ChannelTypes.Standard() else defaultChannelType - val commitTxFeerate = if (channelType.isInstanceOf[ChannelTypes.AnchorOutputs] || channelType.isInstanceOf[ChannelTypes.AnchorOutputsZeroFeeHtlcTx]) TestConstants.anchorOutputsFeeratePerKw else TestConstants.feeratePerKw - val aliceInit = Init(aliceParams.initFeatures) - val bobInit = Init(bobParams.initFeatures) + val channelParams = computeChannelParams(setup, test.tags) + .modify(_.channelType).setToIf(test.tags.contains(StandardChannelType))(ChannelTypes.Standard()) val listener = TestProbe() within(30 seconds) { alice.underlying.system.eventStream.subscribe(listener.ref, classOf[ChannelAborted]) - alice ! INPUT_INIT_CHANNEL_INITIATOR(ByteVector32.Zeroes, TestConstants.fundingSatoshis, dualFunded = false, commitTxFeerate, TestConstants.feeratePerKw, fundingTxFeeBudget_opt = None, Some(TestConstants.initiatorPushAmount), requireConfirmedInputs = false, requestFunding_opt = None, aliceParams, alice2bob.ref, bobInit, channelFlags, channelConfig, channelType, replyTo = aliceOpenReplyTo.ref.toTyped) - bob ! INPUT_INIT_CHANNEL_NON_INITIATOR(ByteVector32.Zeroes, None, dualFunded = false, None, requireConfirmedInputs = false, bobParams, bob2alice.ref, aliceInit, channelConfig, channelType) + alice ! channelParams.initChannelAlice(TestConstants.fundingSatoshis, pushAmount_opt = Some(TestConstants.initiatorPushAmount)) + bob ! channelParams.initChannelBob() alice2bob.expectMsgType[OpenChannel] alice2bob.forward(bob) awaitCond(alice.stateName == WAIT_FOR_ACCEPT_CHANNEL) @@ -91,7 +84,7 @@ class WaitForAcceptChannelStateSpec extends TestKitBaseClass with FixtureAnyFunS assert(accept.channelType_opt.contains(ChannelTypes.AnchorOutputs())) bob2alice.forward(alice) awaitCond(alice.stateName == WAIT_FOR_FUNDING_INTERNAL) - assert(alice.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_INTERNAL].params.commitmentFormat == UnsafeLegacyAnchorOutputsCommitmentFormat) + assert(alice.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_INTERNAL].channelParams.commitmentFormat == UnsafeLegacyAnchorOutputsCommitmentFormat) aliceOpenReplyTo.expectNoMessage() } @@ -101,7 +94,7 @@ class WaitForAcceptChannelStateSpec extends TestKitBaseClass with FixtureAnyFunS assert(accept.channelType_opt.contains(ChannelTypes.AnchorOutputsZeroFeeHtlcTx())) bob2alice.forward(alice) awaitCond(alice.stateName == WAIT_FOR_FUNDING_INTERNAL) - assert(alice.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_INTERNAL].params.commitmentFormat == ZeroFeeHtlcTxAnchorOutputsCommitmentFormat) + assert(alice.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_INTERNAL].channelParams.commitmentFormat == ZeroFeeHtlcTxAnchorOutputsCommitmentFormat) aliceOpenReplyTo.expectNoMessage() } @@ -111,7 +104,7 @@ class WaitForAcceptChannelStateSpec extends TestKitBaseClass with FixtureAnyFunS assert(accept.channelType_opt.contains(ChannelTypes.AnchorOutputsZeroFeeHtlcTx(scidAlias = true))) bob2alice.forward(alice) awaitCond(alice.stateName == WAIT_FOR_FUNDING_INTERNAL) - assert(alice.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_INTERNAL].params.commitmentFormat == ZeroFeeHtlcTxAnchorOutputsCommitmentFormat) + assert(alice.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_INTERNAL].channelParams.commitmentFormat == ZeroFeeHtlcTxAnchorOutputsCommitmentFormat) aliceOpenReplyTo.expectNoMessage() } @@ -133,29 +126,7 @@ class WaitForAcceptChannelStateSpec extends TestKitBaseClass with FixtureAnyFunS assert(accept.channelType_opt.contains(ChannelTypes.Standard())) bob2alice.forward(alice, accept) awaitCond(alice.stateName == WAIT_FOR_FUNDING_INTERNAL) - assert(alice.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_INTERNAL].params.commitmentFormat == DefaultCommitmentFormat) - aliceOpenReplyTo.expectNoMessage() - } - - test("recv AcceptChannel (anchor outputs channel type without enabling the feature)") { () => - val setup = init(Alice.nodeParams, Bob.nodeParams, wallet_opt = Some(new NoOpOnChainWallet())) - import setup._ - - val channelConfig = ChannelConfig.standard - val channelFlags = ChannelFlags(announceChannel = false) - // Bob advertises support for anchor outputs, but Alice doesn't. - val aliceParams = Alice.channelParams - val bobParams = Bob.channelParams.copy(initFeatures = Features(Features.StaticRemoteKey -> FeatureSupport.Optional, Features.AnchorOutputs -> FeatureSupport.Optional, Features.ChannelType -> FeatureSupport.Mandatory)) - alice ! INPUT_INIT_CHANNEL_INITIATOR(ByteVector32.Zeroes, TestConstants.fundingSatoshis, dualFunded = false, TestConstants.anchorOutputsFeeratePerKw, TestConstants.feeratePerKw, fundingTxFeeBudget_opt = None, Some(TestConstants.initiatorPushAmount), requireConfirmedInputs = false, requestFunding_opt = None, aliceParams, alice2bob.ref, Init(bobParams.initFeatures), channelFlags, channelConfig, ChannelTypes.AnchorOutputs(), replyTo = aliceOpenReplyTo.ref.toTyped) - bob ! INPUT_INIT_CHANNEL_NON_INITIATOR(ByteVector32.Zeroes, None, dualFunded = false, None, requireConfirmedInputs = false, bobParams, bob2alice.ref, Init(bobParams.initFeatures), channelConfig, ChannelTypes.AnchorOutputs()) - val open = alice2bob.expectMsgType[OpenChannel] - assert(open.channelType_opt.contains(ChannelTypes.AnchorOutputs())) - alice2bob.forward(bob, open) - val accept = bob2alice.expectMsgType[AcceptChannel] - assert(accept.channelType_opt.contains(ChannelTypes.AnchorOutputs())) - bob2alice.forward(alice, accept) - awaitCond(alice.stateName == WAIT_FOR_FUNDING_INTERNAL) - assert(alice.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_INTERNAL].params.commitmentFormat == UnsafeLegacyAnchorOutputsCommitmentFormat) + assert(alice.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_INTERNAL].channelParams.commitmentFormat == DefaultCommitmentFormat) aliceOpenReplyTo.expectNoMessage() } @@ -275,24 +246,24 @@ class WaitForAcceptChannelStateSpec extends TestKitBaseClass with FixtureAnyFunS test("recv AcceptChannel (upfront shutdown script)", Tag(ChannelStateTestsTags.UpfrontShutdownScript)) { f => import f._ val accept = bob2alice.expectMsgType[AcceptChannel] - assert(accept.upfrontShutdownScript_opt.contains(bob.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_CREATED].params.localParams.upfrontShutdownScript_opt.get)) + assert(accept.upfrontShutdownScript_opt.contains(bob.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_CREATED].channelParams.localParams.upfrontShutdownScript_opt.get)) bob2alice.forward(alice, accept) awaitCond(alice.stateName == WAIT_FOR_FUNDING_INTERNAL) - assert(alice.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_INTERNAL].params.remoteParams.upfrontShutdownScript_opt == accept.upfrontShutdownScript_opt) + assert(alice.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_INTERNAL].channelParams.remoteParams.upfrontShutdownScript_opt == accept.upfrontShutdownScript_opt) aliceOpenReplyTo.expectNoMessage() } test("recv AcceptChannel (empty upfront shutdown script)", Tag(ChannelStateTestsTags.UpfrontShutdownScript)) { f => import f._ val accept = bob2alice.expectMsgType[AcceptChannel] - assert(accept.upfrontShutdownScript_opt.contains(bob.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_CREATED].params.localParams.upfrontShutdownScript_opt.get)) + assert(accept.upfrontShutdownScript_opt.contains(bob.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_CREATED].channelParams.localParams.upfrontShutdownScript_opt.get)) val accept1 = accept .modify(_.tlvStream.records).using(_.filterNot(_.isInstanceOf[ChannelTlv.UpfrontShutdownScriptTlv])) .modify(_.tlvStream.records).using(_ + ChannelTlv.UpfrontShutdownScriptTlv(ByteVector.empty)) bob2alice.forward(alice, accept1) alice2bob.expectNoMessage(100 millis) awaitCond(alice.stateName == WAIT_FOR_FUNDING_INTERNAL) - assert(alice.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_INTERNAL].params.remoteParams.upfrontShutdownScript_opt.isEmpty) + assert(alice.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_INTERNAL].channelParams.remoteParams.upfrontShutdownScript_opt.isEmpty) aliceOpenReplyTo.expectNoMessage() } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForAcceptDualFundedChannelStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForAcceptDualFundedChannelStateSpec.scala index 4f90628095..38e52ad4e7 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForAcceptDualFundedChannelStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForAcceptDualFundedChannelStateSpec.scala @@ -16,7 +16,6 @@ package fr.acinq.eclair.channel.states.a -import akka.actor.typed.scaladsl.adapter.ClassicActorRefOps import akka.testkit.{TestFSMRef, TestProbe} import com.softwaremill.quicklens.ModifyPimp import fr.acinq.bitcoin.scalacompat.{ByteVector32, SatoshiLong} @@ -26,7 +25,7 @@ import fr.acinq.eclair.channel.fsm.Channel import fr.acinq.eclair.channel.fsm.Channel.TickChannelOpenTimeout import fr.acinq.eclair.channel.states.{ChannelStateTestsBase, ChannelStateTestsTags} import fr.acinq.eclair.io.Peer.OpenChannelResponse -import fr.acinq.eclair.wire.protocol.{AcceptDualFundedChannel, ChannelTlv, Error, Init, LiquidityAds, OpenDualFundedChannel} +import fr.acinq.eclair.wire.protocol.{AcceptDualFundedChannel, ChannelTlv, Error, LiquidityAds, OpenDualFundedChannel} import fr.acinq.eclair.{MilliSatoshiLong, TestConstants, TestKitBaseClass, randomBytes64} import org.scalatest.funsuite.FixtureAnyFunSuiteLike import org.scalatest.{Outcome, Tag} @@ -49,11 +48,7 @@ class WaitForAcceptDualFundedChannelStateSpec extends TestKitBaseClass with Fixt val setup = init(nodeParamsB = bobNodeParams, tags = test.tags) import setup._ - val channelConfig = ChannelConfig.standard - val channelFlags = ChannelFlags(announceChannel = false) - val (aliceParams, bobParams, channelType) = computeFeatures(setup, test.tags, channelFlags) - val aliceInit = Init(aliceParams.initFeatures) - val bobInit = Init(bobParams.initFeatures) + val channelParams = computeChannelParams(setup, test.tags) val nonInitiatorContribution = if (test.tags.contains(ChannelStateTestsTags.LiquidityAds)) Some(LiquidityAds.AddFunding(TestConstants.nonInitiatorFundingSatoshis, Some(TestConstants.defaultLiquidityRates))) else None val requestFunds_opt = if (test.tags.contains(ChannelStateTestsTags.LiquidityAds)) { Some(LiquidityAds.RequestFunding(TestConstants.nonInitiatorFundingSatoshis, TestConstants.defaultLiquidityRates.fundingRates.head, LiquidityAds.PaymentDetails.FromChannelBalance)) @@ -64,8 +59,8 @@ class WaitForAcceptDualFundedChannelStateSpec extends TestKitBaseClass with Fixt val listener = TestProbe() within(30 seconds) { alice.underlying.system.eventStream.subscribe(listener.ref, classOf[ChannelAborted]) - alice ! INPUT_INIT_CHANNEL_INITIATOR(ByteVector32.Zeroes, TestConstants.fundingSatoshis, dualFunded = true, TestConstants.anchorOutputsFeeratePerKw, TestConstants.feeratePerKw, fundingTxFeeBudget_opt = None, None, requireConfirmedInputs = false, requestFunds_opt, aliceParams, alice2bob.ref, bobInit, channelFlags, channelConfig, channelType, replyTo = aliceOpenReplyTo.ref.toTyped) - bob ! INPUT_INIT_CHANNEL_NON_INITIATOR(ByteVector32.Zeroes, nonInitiatorContribution, dualFunded = true, nonInitiatorPushAmount, requireConfirmedInputs = test.tags.contains(bobRequiresConfirmedInputs), bobParams, bob2alice.ref, aliceInit, channelConfig, channelType) + alice ! channelParams.initChannelAlice(TestConstants.fundingSatoshis, dualFunded = true, requestFunding_opt = requestFunds_opt) + bob ! channelParams.initChannelBob(nonInitiatorContribution, dualFunded = true, pushAmount_opt = nonInitiatorPushAmount, requireConfirmedInputs = test.tags.contains(bobRequiresConfirmedInputs)) val open = alice2bob.expectMsgType[OpenDualFundedChannel] alice2bob.forward(bob, open) awaitCond(alice.stateName == WAIT_FOR_ACCEPT_DUAL_FUNDED_CHANNEL) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForOpenChannelStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForOpenChannelStateSpec.scala index fb09112a72..2bcd596e15 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForOpenChannelStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForOpenChannelStateSpec.scala @@ -16,8 +16,8 @@ package fr.acinq.eclair.channel.states.a -import akka.actor.typed.scaladsl.adapter.ClassicActorRefOps import akka.testkit.{TestFSMRef, TestProbe} +import com.softwaremill.quicklens.ModifyPimp import fr.acinq.bitcoin.scalacompat.{Block, Btc, ByteVector32, SatoshiLong} import fr.acinq.eclair.TestConstants.{Alice, Bob} import fr.acinq.eclair.blockchain.fee.FeeratePerKw @@ -25,7 +25,7 @@ import fr.acinq.eclair.channel._ import fr.acinq.eclair.channel.fsm.Channel import fr.acinq.eclair.channel.states.{ChannelStateTestsBase, ChannelStateTestsTags} import fr.acinq.eclair.transactions.Transactions.{DefaultCommitmentFormat, UnsafeLegacyAnchorOutputsCommitmentFormat, ZeroFeeHtlcTxAnchorOutputsCommitmentFormat} -import fr.acinq.eclair.wire.protocol.{AcceptChannel, ChannelTlv, Error, Init, OpenChannel, TlvStream} +import fr.acinq.eclair.wire.protocol.{AcceptChannel, ChannelTlv, Error, OpenChannel, TlvStream} import fr.acinq.eclair.{CltvExpiryDelta, MilliSatoshiLong, TestConstants, TestKitBaseClass, ToMilliSatoshiConversion} import org.scalatest.funsuite.FixtureAnyFunSuiteLike import org.scalatest.{Outcome, Tag} @@ -47,18 +47,13 @@ class WaitForOpenChannelStateSpec extends TestKitBaseClass with FixtureAnyFunSui val setup = init(tags = test.tags) import setup._ - val channelConfig = ChannelConfig.standard - val channelFlags = ChannelFlags(announceChannel = false) - val (aliceParams, bobParams, defaultChannelType) = computeFeatures(setup, test.tags, channelFlags) - val channelType = if (test.tags.contains(StandardChannelType)) ChannelTypes.Standard() else defaultChannelType - val commitTxFeerate = if (channelType.isInstanceOf[ChannelTypes.AnchorOutputs] || channelType.isInstanceOf[ChannelTypes.AnchorOutputsZeroFeeHtlcTx]) TestConstants.anchorOutputsFeeratePerKw else TestConstants.feeratePerKw - val aliceInit = Init(aliceParams.initFeatures) - val bobInit = Init(bobParams.initFeatures) + val channelParams = computeChannelParams(setup, test.tags) + .modify(_.channelType).setToIf(test.tags.contains(StandardChannelType))(ChannelTypes.Standard()) val listener = TestProbe() within(30 seconds) { bob.underlying.system.eventStream.subscribe(listener.ref, classOf[ChannelAborted]) - alice ! INPUT_INIT_CHANNEL_INITIATOR(ByteVector32.Zeroes, TestConstants.fundingSatoshis, dualFunded = false, commitTxFeerate, TestConstants.feeratePerKw, fundingTxFeeBudget_opt = None, Some(TestConstants.initiatorPushAmount), requireConfirmedInputs = false, requestFunding_opt = None, aliceParams, alice2bob.ref, bobInit, channelFlags, channelConfig, channelType, replyTo = aliceOpenReplyTo.ref.toTyped) - bob ! INPUT_INIT_CHANNEL_NON_INITIATOR(ByteVector32.Zeroes, None, dualFunded = false, None, requireConfirmedInputs = false, bobParams, bob2alice.ref, aliceInit, channelConfig, channelType) + alice ! channelParams.initChannelAlice(TestConstants.fundingSatoshis, pushAmount_opt = Some(TestConstants.initiatorPushAmount)) + bob ! channelParams.initChannelBob() awaitCond(bob.stateName == WAIT_FOR_OPEN_CHANNEL) withFixture(test.toNoArgTest(FixtureParam(alice, bob, alice2bob, bob2alice, bob2blockchain, listener))) } @@ -73,7 +68,7 @@ class WaitForOpenChannelStateSpec extends TestKitBaseClass with FixtureAnyFunSui assert(open.channelType_opt.contains(ChannelTypes.StaticRemoteKey())) alice2bob.forward(bob) awaitCond(bob.stateName == WAIT_FOR_FUNDING_CREATED) - assert(bob.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_CREATED].params.commitmentFormat == DefaultCommitmentFormat) + assert(bob.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_CREATED].channelParams.commitmentFormat == DefaultCommitmentFormat) } test("recv OpenChannel (anchor outputs)", Tag(ChannelStateTestsTags.AnchorOutputs)) { f => @@ -82,7 +77,7 @@ class WaitForOpenChannelStateSpec extends TestKitBaseClass with FixtureAnyFunSui assert(open.channelType_opt.contains(ChannelTypes.AnchorOutputs())) alice2bob.forward(bob) awaitCond(bob.stateName == WAIT_FOR_FUNDING_CREATED) - assert(bob.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_CREATED].params.commitmentFormat == UnsafeLegacyAnchorOutputsCommitmentFormat) + assert(bob.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_CREATED].channelParams.commitmentFormat == UnsafeLegacyAnchorOutputsCommitmentFormat) } test("recv OpenChannel (anchor outputs zero fee htlc txs)", Tag(ChannelStateTestsTags.AnchorOutputsZeroFeeHtlcTxs)) { f => @@ -91,7 +86,7 @@ class WaitForOpenChannelStateSpec extends TestKitBaseClass with FixtureAnyFunSui assert(open.channelType_opt.contains(ChannelTypes.AnchorOutputsZeroFeeHtlcTx())) alice2bob.forward(bob) awaitCond(bob.stateName == WAIT_FOR_FUNDING_CREATED) - assert(bob.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_CREATED].params.commitmentFormat == ZeroFeeHtlcTxAnchorOutputsCommitmentFormat) + assert(bob.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_CREATED].channelParams.commitmentFormat == ZeroFeeHtlcTxAnchorOutputsCommitmentFormat) } test("recv OpenChannel (anchor outputs zero fee htlc txs and scid alias)", Tag(ChannelStateTestsTags.AnchorOutputsZeroFeeHtlcTxs), Tag(ChannelStateTestsTags.ScidAlias)) { f => @@ -100,7 +95,7 @@ class WaitForOpenChannelStateSpec extends TestKitBaseClass with FixtureAnyFunSui assert(open.channelType_opt.contains(ChannelTypes.AnchorOutputsZeroFeeHtlcTx(scidAlias = true))) alice2bob.forward(bob) awaitCond(bob.stateName == WAIT_FOR_FUNDING_CREATED) - assert(bob.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_CREATED].params.commitmentFormat == ZeroFeeHtlcTxAnchorOutputsCommitmentFormat) + assert(bob.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_CREATED].channelParams.commitmentFormat == ZeroFeeHtlcTxAnchorOutputsCommitmentFormat) } test("recv OpenChannel (non-default channel type)", Tag(ChannelStateTestsTags.AnchorOutputsZeroFeeHtlcTxs), Tag(StandardChannelType)) { f => @@ -109,7 +104,7 @@ class WaitForOpenChannelStateSpec extends TestKitBaseClass with FixtureAnyFunSui assert(open.channelType_opt.contains(ChannelTypes.Standard())) alice2bob.forward(bob) awaitCond(bob.stateName == WAIT_FOR_FUNDING_CREATED) - assert(bob.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_CREATED].params.commitmentFormat == DefaultCommitmentFormat) + assert(bob.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_CREATED].channelParams.commitmentFormat == DefaultCommitmentFormat) } test("recv OpenChannel (invalid chain)") { f => @@ -187,7 +182,7 @@ class WaitForOpenChannelStateSpec extends TestKitBaseClass with FixtureAnyFunSui val delayTooHigh = CltvExpiryDelta(10000) bob ! open.copy(toSelfDelay = delayTooHigh) val error = bob2alice.expectMsgType[Error] - assert(error == Error(open.temporaryChannelId, ToSelfDelayTooHigh(open.temporaryChannelId, delayTooHigh, Alice.nodeParams.channelConf.maxToLocalDelay).getMessage)) + assert(error == Error(open.temporaryChannelId, ToSelfDelayTooHigh(open.temporaryChannelId, delayTooHigh, Bob.nodeParams.channelConf.maxToLocalDelay).getMessage)) listener.expectMsgType[ChannelAborted] awaitCond(bob.stateName == CLOSED) } @@ -278,10 +273,10 @@ class WaitForOpenChannelStateSpec extends TestKitBaseClass with FixtureAnyFunSui test("recv OpenChannel (upfront shutdown script)", Tag(ChannelStateTestsTags.UpfrontShutdownScript)) { f => import f._ val open = alice2bob.expectMsgType[OpenChannel] - assert(open.upfrontShutdownScript_opt.contains(alice.stateData.asInstanceOf[DATA_WAIT_FOR_ACCEPT_CHANNEL].initFunder.localParams.upfrontShutdownScript_opt.get)) + assert(open.upfrontShutdownScript_opt.contains(alice.stateData.asInstanceOf[DATA_WAIT_FOR_ACCEPT_CHANNEL].initFunder.localChannelParams.upfrontShutdownScript_opt.get)) alice2bob.forward(bob, open) awaitCond(bob.stateName == WAIT_FOR_FUNDING_CREATED) - assert(bob.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_CREATED].params.remoteParams.upfrontShutdownScript_opt == open.upfrontShutdownScript_opt) + assert(bob.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_CREATED].channelParams.remoteParams.upfrontShutdownScript_opt == open.upfrontShutdownScript_opt) } test("recv OpenChannel (empty upfront shutdown script)", Tag(ChannelStateTestsTags.UpfrontShutdownScript)) { f => @@ -290,7 +285,7 @@ class WaitForOpenChannelStateSpec extends TestKitBaseClass with FixtureAnyFunSui val open1 = open.copy(tlvStream = TlvStream(ChannelTlv.UpfrontShutdownScriptTlv(ByteVector.empty))) alice2bob.forward(bob, open1) awaitCond(bob.stateName == WAIT_FOR_FUNDING_CREATED) - assert(bob.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_CREATED].params.remoteParams.upfrontShutdownScript_opt.isEmpty) + assert(bob.stateData.asInstanceOf[DATA_WAIT_FOR_FUNDING_CREATED].channelParams.remoteParams.upfrontShutdownScript_opt.isEmpty) } test("recv OpenChannel (invalid upfront shutdown script)", Tag(ChannelStateTestsTags.UpfrontShutdownScript)) { f => diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForOpenDualFundedChannelStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForOpenDualFundedChannelStateSpec.scala index 246a6fc34c..e0436d5203 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForOpenDualFundedChannelStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForOpenDualFundedChannelStateSpec.scala @@ -16,14 +16,13 @@ package fr.acinq.eclair.channel.states.a -import akka.actor.typed.scaladsl.adapter.ClassicActorRefOps import akka.testkit.{TestFSMRef, TestProbe} import fr.acinq.bitcoin.scalacompat.{Block, BlockHash, ByteVector32, SatoshiLong} import fr.acinq.eclair.TestConstants.{Alice, Bob} import fr.acinq.eclair.channel._ import fr.acinq.eclair.channel.fsm.Channel import fr.acinq.eclair.channel.states.{ChannelStateTestsBase, ChannelStateTestsTags} -import fr.acinq.eclair.wire.protocol.{AcceptDualFundedChannel, ChannelTlv, Error, Init, LiquidityAds, OpenDualFundedChannel} +import fr.acinq.eclair.wire.protocol.{AcceptDualFundedChannel, ChannelTlv, Error, LiquidityAds, OpenDualFundedChannel} import fr.acinq.eclair.{MilliSatoshiLong, TestConstants, TestKitBaseClass, randomBytes32} import org.scalatest.funsuite.FixtureAnyFunSuiteLike import org.scalatest.{Outcome, Tag} @@ -49,17 +48,13 @@ class WaitForOpenDualFundedChannelStateSpec extends TestKitBaseClass with Fixtur bob.underlyingActor.context.system.eventStream.subscribe(bobListener.ref, classOf[ChannelIdAssigned]) bob.underlyingActor.context.system.eventStream.subscribe(bobListener.ref, classOf[ChannelAborted]) - val channelConfig = ChannelConfig.standard - val channelFlags = ChannelFlags(announceChannel = false) val pushAmount = if (test.tags.contains(ChannelStateTestsTags.NoPushAmount)) None else Some(TestConstants.initiatorPushAmount) val nonInitiatorContribution = if (test.tags.contains(ChannelStateTestsTags.LiquidityAds)) Some(LiquidityAds.AddFunding(TestConstants.nonInitiatorFundingSatoshis, Some(TestConstants.defaultLiquidityRates))) else None - val (aliceParams, bobParams, channelType) = computeFeatures(setup, test.tags, channelFlags) - val aliceInit = Init(aliceParams.initFeatures) - val bobInit = Init(bobParams.initFeatures) + val channelParams = computeChannelParams(setup, test.tags) val requireConfirmedInputs = test.tags.contains(aliceRequiresConfirmedInputs) within(30 seconds) { - alice ! INPUT_INIT_CHANNEL_INITIATOR(ByteVector32.Zeroes, TestConstants.fundingSatoshis, dualFunded = true, TestConstants.anchorOutputsFeeratePerKw, TestConstants.feeratePerKw, fundingTxFeeBudget_opt = None, pushAmount, requireConfirmedInputs, None, aliceParams, alice2bob.ref, bobInit, channelFlags, channelConfig, channelType, replyTo = aliceOpenReplyTo.ref.toTyped) - bob ! INPUT_INIT_CHANNEL_NON_INITIATOR(ByteVector32.Zeroes, nonInitiatorContribution, dualFunded = true, None, requireConfirmedInputs = false, bobParams, bob2alice.ref, aliceInit, channelConfig, channelType) + alice ! channelParams.initChannelAlice(TestConstants.fundingSatoshis, dualFunded = true, requireConfirmedInputs = requireConfirmedInputs, pushAmount_opt = pushAmount) + bob ! channelParams.initChannelBob(nonInitiatorContribution, dualFunded = true) awaitCond(bob.stateName == WAIT_FOR_OPEN_DUAL_FUNDED_CHANNEL) withFixture(test.toNoArgTest(FixtureParam(alice, bob, alice2bob, bob2alice, aliceListener, bobListener))) } @@ -188,10 +183,10 @@ class WaitForOpenDualFundedChannelStateSpec extends TestKitBaseClass with Fixtur test("recv OpenDualFundedChannel (to_self_delay too high)", Tag(ChannelStateTestsTags.DualFunding), Tag(ChannelStateTestsTags.AnchorOutputsZeroFeeHtlcTxs)) { f => import f._ val open = alice2bob.expectMsgType[OpenDualFundedChannel] - val delayTooHigh = Alice.nodeParams.channelConf.maxToLocalDelay + 1 + val delayTooHigh = Bob.nodeParams.channelConf.maxToLocalDelay + 1 bob ! open.copy(toSelfDelay = delayTooHigh) val error = bob2alice.expectMsgType[Error] - assert(error == Error(open.temporaryChannelId, ToSelfDelayTooHigh(open.temporaryChannelId, delayTooHigh, Alice.nodeParams.channelConf.maxToLocalDelay).getMessage)) + assert(error == Error(open.temporaryChannelId, ToSelfDelayTooHigh(open.temporaryChannelId, delayTooHigh, Bob.nodeParams.channelConf.maxToLocalDelay).getMessage)) bobListener.expectMsgType[ChannelAborted] awaitCond(bob.stateName == CLOSED) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/b/WaitForDualFundingCreatedStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/b/WaitForDualFundingCreatedStateSpec.scala index ad5feb7184..b548765b94 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/b/WaitForDualFundingCreatedStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/b/WaitForDualFundingCreatedStateSpec.scala @@ -16,9 +16,8 @@ package fr.acinq.eclair.channel.states.b -import akka.actor.typed.scaladsl.adapter.ClassicActorRefOps import akka.testkit.{TestFSMRef, TestProbe} -import fr.acinq.bitcoin.scalacompat.{ByteVector32, SatoshiLong, Script} +import fr.acinq.bitcoin.scalacompat.{SatoshiLong, Script} import fr.acinq.eclair.blockchain.SingleKeyOnChainWallet import fr.acinq.eclair.blockchain.fee.FeeratePerKw import fr.acinq.eclair.channel._ @@ -43,18 +42,14 @@ class WaitForDualFundingCreatedStateSpec extends TestKitBaseClass with FixtureAn val wallet = new SingleKeyOnChainWallet() val setup = init(wallet_opt = Some(wallet), tags = test.tags) import setup._ - val channelConfig = ChannelConfig.standard - val channelFlags = ChannelFlags(announceChannel = false) - val (aliceParams, bobParams, channelType) = computeFeatures(setup, test.tags, channelFlags) - val aliceInit = Init(aliceParams.initFeatures) - val bobInit = Init(bobParams.initFeatures) + val channelParams = computeChannelParams(setup, test.tags) val aliceListener = TestProbe() val bobListener = TestProbe() within(30 seconds) { alice.underlying.system.eventStream.subscribe(aliceListener.ref, classOf[ChannelAborted]) bob.underlying.system.eventStream.subscribe(bobListener.ref, classOf[ChannelAborted]) - alice ! INPUT_INIT_CHANNEL_INITIATOR(ByteVector32.Zeroes, TestConstants.fundingSatoshis, dualFunded = true, TestConstants.feeratePerKw, TestConstants.feeratePerKw, fundingTxFeeBudget_opt = None, None, requireConfirmedInputs = false, requestFunding_opt = None, aliceParams, alice2bob.ref, bobInit, channelFlags, channelConfig, channelType, replyTo = aliceOpenReplyTo.ref.toTyped) - bob ! INPUT_INIT_CHANNEL_NON_INITIATOR(ByteVector32.Zeroes, Some(LiquidityAds.AddFunding(TestConstants.nonInitiatorFundingSatoshis, None)), dualFunded = true, None, requireConfirmedInputs = false, bobParams, bob2alice.ref, aliceInit, channelConfig, channelType) + alice ! channelParams.initChannelAlice(TestConstants.fundingSatoshis, dualFunded = true) + bob ! channelParams.initChannelBob(Some(LiquidityAds.AddFunding(TestConstants.nonInitiatorFundingSatoshis, None)), dualFunded = true) alice2blockchain.expectMsgType[TxPublisher.SetChannelId] // temporary channel id bob2blockchain.expectMsgType[TxPublisher.SetChannelId] // temporary channel id alice2bob.expectMsgType[OpenDualFundedChannel] diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/b/WaitForDualFundingSignedStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/b/WaitForDualFundingSignedStateSpec.scala index 77a4549802..f71c2963b8 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/b/WaitForDualFundingSignedStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/b/WaitForDualFundingSignedStateSpec.scala @@ -16,9 +16,8 @@ package fr.acinq.eclair.channel.states.b -import akka.actor.typed.scaladsl.adapter.ClassicActorRefOps import akka.testkit.{TestFSMRef, TestProbe} -import fr.acinq.bitcoin.scalacompat.{ByteVector32, ByteVector64, SatoshiLong, TxId} +import fr.acinq.bitcoin.scalacompat.{ByteVector64, SatoshiLong, TxId} import fr.acinq.eclair.TestUtils.randomTxId import fr.acinq.eclair.blockchain.SingleKeyOnChainWallet import fr.acinq.eclair.blockchain.bitcoind.ZmqWatcher.{WatchFundingConfirmed, WatchPublished, WatchPublishedTriggered} @@ -29,7 +28,6 @@ import fr.acinq.eclair.channel.fund.InteractiveTxBuilder.{FullySignedSharedTrans import fr.acinq.eclair.channel.publish.TxPublisher import fr.acinq.eclair.channel.states.{ChannelStateTestsBase, ChannelStateTestsTags} import fr.acinq.eclair.io.Peer.{LiquidityPurchaseSigned, OpenChannelResponse} -import fr.acinq.eclair.transactions.Transactions import fr.acinq.eclair.wire.protocol._ import fr.acinq.eclair.{Features, MilliSatoshiLong, TestConstants, TestKitBaseClass, ToMilliSatoshiConversion} import org.scalatest.funsuite.FixtureAnyFunSuiteLike @@ -45,25 +43,17 @@ class WaitForDualFundingSignedStateSpec extends TestKitBaseClass with FixtureAny val wallet = new SingleKeyOnChainWallet() val setup = init(wallet_opt = Some(wallet), tags = test.tags) import setup._ - val channelConfig = ChannelConfig.standard - val channelFlags = ChannelFlags(announceChannel = false) - val (aliceParams, bobParams, channelType) = computeFeatures(setup, test.tags, channelFlags) - val aliceInit = Init(aliceParams.initFeatures) - val bobInit = Init(bobParams.initFeatures) - val bobContribution = if (channelType.features.contains(Features.ZeroConf)) None else Some(LiquidityAds.AddFunding(TestConstants.nonInitiatorFundingSatoshis, Some(TestConstants.defaultLiquidityRates))) + val channelParams = computeChannelParams(setup, test.tags) + val bobContribution = if (channelParams.channelType.features.contains(Features.ZeroConf)) None else Some(LiquidityAds.AddFunding(TestConstants.nonInitiatorFundingSatoshis, Some(TestConstants.defaultLiquidityRates))) val requestFunding_opt = if (test.tags.contains(ChannelStateTestsTags.LiquidityAds)) Some(LiquidityAds.RequestFunding(TestConstants.nonInitiatorFundingSatoshis, TestConstants.defaultLiquidityRates.fundingRates.head, LiquidityAds.PaymentDetails.FromChannelBalance)) else None val (initiatorPushAmount, nonInitiatorPushAmount) = if (test.tags.contains("both_push_amount")) (Some(TestConstants.initiatorPushAmount), Some(TestConstants.nonInitiatorPushAmount)) else (None, None) - val commitFeerate = channelType.commitmentFormat match { - case Transactions.DefaultCommitmentFormat => TestConstants.feeratePerKw - case _: Transactions.AnchorOutputsCommitmentFormat | _: Transactions.SimpleTaprootChannelCommitmentFormat => TestConstants.anchorOutputsFeeratePerKw - } val aliceListener = TestProbe() val bobListener = TestProbe() within(30 seconds) { alice.underlying.system.eventStream.subscribe(aliceListener.ref, classOf[ChannelAborted]) bob.underlying.system.eventStream.subscribe(bobListener.ref, classOf[ChannelAborted]) - alice ! INPUT_INIT_CHANNEL_INITIATOR(ByteVector32.Zeroes, TestConstants.fundingSatoshis, dualFunded = true, commitFeerate, TestConstants.feeratePerKw, fundingTxFeeBudget_opt = None, initiatorPushAmount, requireConfirmedInputs = false, requestFunding_opt, aliceParams, alice2bob.ref, bobInit, channelFlags, channelConfig, channelType, replyTo = aliceOpenReplyTo.ref.toTyped) - bob ! INPUT_INIT_CHANNEL_NON_INITIATOR(ByteVector32.Zeroes, bobContribution, dualFunded = true, nonInitiatorPushAmount, requireConfirmedInputs = false, bobParams, bob2alice.ref, aliceInit, channelConfig, channelType) + alice ! channelParams.initChannelAlice(TestConstants.fundingSatoshis, dualFunded = true, requestFunding_opt = requestFunding_opt, pushAmount_opt = initiatorPushAmount) + bob ! channelParams.initChannelBob(bobContribution, dualFunded = true, pushAmount_opt = nonInitiatorPushAmount) alice2blockchain.expectMsgType[TxPublisher.SetChannelId] // temporary channel id bob2blockchain.expectMsgType[TxPublisher.SetChannelId] // temporary channel id alice2bob.expectMsgType[OpenDualFundedChannel] @@ -115,7 +105,7 @@ class WaitForDualFundingSignedStateSpec extends TestKitBaseClass with FixtureAny bob2alice.expectMsgType[TxSignatures] awaitCond(bob.stateName == WAIT_FOR_DUAL_FUNDING_CONFIRMED) val bobData = bob.stateData.asInstanceOf[DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED] - assert(bobData.commitments.params.channelFeatures.hasFeature(Features.DualFunding)) + assert(bobData.commitments.channelParams.channelFeatures.hasFeature(Features.DualFunding)) assert(bobData.latestFundingTx.sharedTx.isInstanceOf[PartiallySignedSharedTransaction]) val fundingTxId = bobData.latestFundingTx.sharedTx.asInstanceOf[PartiallySignedSharedTransaction].txId assert(bob2blockchain.expectMsgType[WatchFundingConfirmed].txId == fundingTxId) @@ -127,7 +117,7 @@ class WaitForDualFundingSignedStateSpec extends TestKitBaseClass with FixtureAny alice2bob.expectMsgType[TxSignatures] awaitCond(alice.stateName == WAIT_FOR_DUAL_FUNDING_CONFIRMED) val aliceData = alice.stateData.asInstanceOf[DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED] - assert(aliceData.commitments.params.channelFeatures.hasFeature(Features.DualFunding)) + assert(aliceData.commitments.channelParams.channelFeatures.hasFeature(Features.DualFunding)) assert(aliceData.latestFundingTx.sharedTx.isInstanceOf[FullySignedSharedTransaction]) assert(aliceData.latestFundingTx.sharedTx.asInstanceOf[FullySignedSharedTransaction].signedTx.txid == fundingTxId) } @@ -147,7 +137,7 @@ class WaitForDualFundingSignedStateSpec extends TestKitBaseClass with FixtureAny bob2alice.expectMsgType[TxSignatures] awaitCond(bob.stateName == WAIT_FOR_DUAL_FUNDING_CONFIRMED) val bobData = bob.stateData.asInstanceOf[DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED] - assert(bobData.commitments.params.channelFeatures.hasFeature(Features.DualFunding)) + assert(bobData.commitments.channelParams.channelFeatures.hasFeature(Features.DualFunding)) assert(bobData.latestFundingTx.sharedTx.isInstanceOf[PartiallySignedSharedTransaction]) val fundingTxId = bobData.latestFundingTx.sharedTx.asInstanceOf[PartiallySignedSharedTransaction].tx.buildUnsignedTx().txid assert(bob2blockchain.expectMsgType[WatchPublished].txId == fundingTxId) @@ -160,7 +150,7 @@ class WaitForDualFundingSignedStateSpec extends TestKitBaseClass with FixtureAny alice2bob.expectMsgType[TxSignatures] awaitCond(alice.stateName == WAIT_FOR_DUAL_FUNDING_CONFIRMED) val aliceData = alice.stateData.asInstanceOf[DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED] - assert(aliceData.commitments.params.channelFeatures.hasFeature(Features.DualFunding)) + assert(aliceData.commitments.channelParams.channelFeatures.hasFeature(Features.DualFunding)) assert(aliceData.latestFundingTx.sharedTx.isInstanceOf[FullySignedSharedTransaction]) assert(aliceData.latestFundingTx.sharedTx.asInstanceOf[FullySignedSharedTransaction].signedTx.txid == fundingTxId) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/b/WaitForFundingCreatedStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/b/WaitForFundingCreatedStateSpec.scala index de687186b1..2a13707216 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/b/WaitForFundingCreatedStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/b/WaitForFundingCreatedStateSpec.scala @@ -17,7 +17,6 @@ package fr.acinq.eclair.channel.states.b import akka.actor.ActorRef -import akka.actor.typed.scaladsl.adapter.ClassicActorRefOps import akka.testkit.{TestFSMRef, TestProbe} import fr.acinq.bitcoin.scalacompat.{ByteVector32, SatoshiLong} import fr.acinq.eclair.TestConstants.{Alice, Bob} @@ -48,23 +47,18 @@ class WaitForFundingCreatedStateSpec extends TestKitBaseClass with FixtureAnyFun val setup = init(Alice.nodeParams, Bob.nodeParams, tags = test.tags) import setup._ - val (fundingSatoshis, pushMsat) = if (test.tags.contains(FunderBelowCommitFees)) { + val channelParams = computeChannelParams(setup, test.tags) + val (fundingAmount, pushAmount) = if (test.tags.contains(FunderBelowCommitFees)) { (1_000_100 sat, (1_000_000 sat).toMilliSatoshi) // toLocal = 100 satoshis } else { (TestConstants.fundingSatoshis, TestConstants.initiatorPushAmount) } - - val channelConfig = ChannelConfig.standard - val channelFlags = ChannelFlags(announceChannel = false) - val (aliceParams, bobParams, channelType) = computeFeatures(setup, test.tags, channelFlags) - val aliceInit = Init(aliceParams.initFeatures) - val bobInit = Init(bobParams.initFeatures) val listener = TestProbe() within(30 seconds) { bob.underlying.system.eventStream.subscribe(listener.ref, classOf[ChannelAborted]) - alice ! INPUT_INIT_CHANNEL_INITIATOR(ByteVector32.Zeroes, fundingSatoshis, dualFunded = false, TestConstants.feeratePerKw, TestConstants.feeratePerKw, fundingTxFeeBudget_opt = None, Some(pushMsat), requireConfirmedInputs = false, requestFunding_opt = None, aliceParams, alice2bob.ref, bobInit, channelFlags, channelConfig, channelType, replyTo = aliceOpenReplyTo.ref.toTyped) + alice ! channelParams.initChannelAlice(fundingAmount, pushAmount_opt = Some(pushAmount)) alice2blockchain.expectMsgType[TxPublisher.SetChannelId] - bob ! INPUT_INIT_CHANNEL_NON_INITIATOR(ByteVector32.Zeroes, None, dualFunded = false, None, requireConfirmedInputs = false, bobParams, bob2alice.ref, aliceInit, channelConfig, channelType) + bob ! channelParams.initChannelBob() bob2blockchain.expectMsgType[TxPublisher.SetChannelId] alice2bob.expectMsgType[OpenChannel] alice2bob.forward(bob) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/b/WaitForFundingInternalStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/b/WaitForFundingInternalStateSpec.scala index 2c6a39d236..3b262317d6 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/b/WaitForFundingInternalStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/b/WaitForFundingInternalStateSpec.scala @@ -17,7 +17,6 @@ package fr.acinq.eclair.channel.states.b import akka.actor.Status -import akka.actor.typed.scaladsl.adapter.ClassicActorRefOps import akka.testkit.{TestFSMRef, TestProbe} import fr.acinq.bitcoin.scalacompat.ByteVector32 import fr.acinq.eclair.blockchain.NoOpOnChainWallet @@ -44,16 +43,12 @@ class WaitForFundingInternalStateSpec extends TestKitBaseClass with FixtureAnyFu override def withFixture(test: OneArgTest): Outcome = { val setup = init(wallet_opt = Some(new NoOpOnChainWallet()), tags = test.tags) import setup._ - val channelConfig = ChannelConfig.standard - val channelFlags = ChannelFlags(announceChannel = false) - val (aliceParams, bobParams, channelType) = computeFeatures(setup, test.tags, channelFlags) - val aliceInit = Init(aliceParams.initFeatures) - val bobInit = Init(bobParams.initFeatures) + val channelParams = computeChannelParams(setup, test.tags) val listener = TestProbe() within(30 seconds) { alice.underlying.system.eventStream.subscribe(listener.ref, classOf[ChannelAborted]) - alice ! INPUT_INIT_CHANNEL_INITIATOR(ByteVector32.Zeroes, TestConstants.fundingSatoshis, dualFunded = false, TestConstants.feeratePerKw, TestConstants.feeratePerKw, fundingTxFeeBudget_opt = None, Some(TestConstants.initiatorPushAmount), requireConfirmedInputs = false, requestFunding_opt = None, aliceParams, alice2bob.ref, bobInit, channelFlags, channelConfig, channelType, replyTo = aliceOpenReplyTo.ref.toTyped) - bob ! INPUT_INIT_CHANNEL_NON_INITIATOR(ByteVector32.Zeroes, None, dualFunded = false, None, requireConfirmedInputs = false, bobParams, bob2alice.ref, aliceInit, channelConfig, channelType) + alice ! channelParams.initChannelAlice(TestConstants.fundingSatoshis, pushAmount_opt = Some(TestConstants.initiatorPushAmount)) + bob ! channelParams.initChannelBob() alice2bob.expectMsgType[OpenChannel] alice2bob.forward(bob) bob2alice.expectMsgType[AcceptChannel] diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/b/WaitForFundingSignedStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/b/WaitForFundingSignedStateSpec.scala index d62d60b40f..c468cc203d 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/b/WaitForFundingSignedStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/b/WaitForFundingSignedStateSpec.scala @@ -16,7 +16,6 @@ package fr.acinq.eclair.channel.states.b -import akka.actor.typed.scaladsl.adapter.ClassicActorRefOps import akka.testkit.{TestFSMRef, TestProbe} import fr.acinq.bitcoin.scalacompat.{Btc, ByteVector32, ByteVector64, SatoshiLong} import fr.acinq.eclair.TestConstants.{Alice, Bob} @@ -28,8 +27,7 @@ import fr.acinq.eclair.channel.fsm.Channel.TickChannelOpenTimeout import fr.acinq.eclair.channel.publish.TxPublisher import fr.acinq.eclair.channel.states.{ChannelStateTestsBase, ChannelStateTestsTags} import fr.acinq.eclair.io.Peer.OpenChannelResponse -import fr.acinq.eclair.transactions.Transactions -import fr.acinq.eclair.wire.protocol.{AcceptChannel, Error, FundingCreated, FundingSigned, Init, OpenChannel} +import fr.acinq.eclair.wire.protocol.{AcceptChannel, Error, FundingCreated, FundingSigned, OpenChannel} import fr.acinq.eclair.{TestConstants, TestKitBaseClass} import org.scalatest.funsuite.FixtureAnyFunSuiteLike import org.scalatest.{Outcome, Tag} @@ -50,27 +48,18 @@ class WaitForFundingSignedStateSpec extends TestKitBaseClass with FixtureAnyFunS val setup = init(Alice.nodeParams, Bob.nodeParams, tags = test.tags) import setup._ - val (fundingSatoshis, pushMsat) = if (test.tags.contains(LargeChannel)) { + val channelParams = computeChannelParams(setup, test.tags) + val (fundingAmount, pushAmount) = if (test.tags.contains(LargeChannel)) { (Btc(5).toSatoshi, TestConstants.initiatorPushAmount) } else { (TestConstants.fundingSatoshis, TestConstants.initiatorPushAmount) } - - val channelConfig = ChannelConfig.standard - val channelFlags = ChannelFlags(announceChannel = false) - val (aliceParams, bobParams, channelType) = computeFeatures(setup, test.tags, channelFlags) - val commitFeerate = channelType.commitmentFormat match { - case Transactions.DefaultCommitmentFormat => TestConstants.feeratePerKw - case _: Transactions.AnchorOutputsCommitmentFormat | _: Transactions.SimpleTaprootChannelCommitmentFormat => TestConstants.anchorOutputsFeeratePerKw - } - val aliceInit = Init(aliceParams.initFeatures) - val bobInit = Init(bobParams.initFeatures) val listener = TestProbe() within(30 seconds) { alice.underlying.system.eventStream.subscribe(listener.ref, classOf[ChannelAborted]) - alice ! INPUT_INIT_CHANNEL_INITIATOR(ByteVector32.Zeroes, fundingSatoshis, dualFunded = false, commitFeerate, TestConstants.feeratePerKw, fundingTxFeeBudget_opt = None, Some(pushMsat), requireConfirmedInputs = false, requestFunding_opt = None, aliceParams, alice2bob.ref, bobInit, channelFlags, channelConfig, channelType, replyTo = aliceOpenReplyTo.ref.toTyped) + alice ! channelParams.initChannelAlice(fundingAmount, pushAmount_opt = Some(pushAmount)) alice2blockchain.expectMsgType[TxPublisher.SetChannelId] - bob ! INPUT_INIT_CHANNEL_NON_INITIATOR(ByteVector32.Zeroes, None, dualFunded = false, None, requireConfirmedInputs = false, bobParams, bob2alice.ref, aliceInit, channelConfig, channelType) + bob ! channelParams.initChannelBob() bob2blockchain.expectMsgType[TxPublisher.SetChannelId] alice2bob.expectMsgType[OpenChannel] alice2bob.forward(bob) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForChannelReadyStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForChannelReadyStateSpec.scala index d424d07832..1b813e610e 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForChannelReadyStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForChannelReadyStateSpec.scala @@ -16,7 +16,6 @@ package fr.acinq.eclair.channel.states.c -import akka.actor.typed.scaladsl.adapter.ClassicActorRefOps import akka.testkit.{TestFSMRef, TestProbe} import com.softwaremill.quicklens.ModifyPimp import fr.acinq.bitcoin.scalacompat.{ByteVector32, Transaction} @@ -28,7 +27,6 @@ import fr.acinq.eclair.channel.states.ChannelStateTestsBase.PimpTestFSM import fr.acinq.eclair.channel.states.{ChannelStateTestsBase, ChannelStateTestsTags} import fr.acinq.eclair.payment.relay.Relayer.RelayFees import fr.acinq.eclair.router.Announcements -import fr.acinq.eclair.transactions.Transactions import fr.acinq.eclair.wire.protocol._ import fr.acinq.eclair.{BlockHeight, MilliSatoshiLong, TestConstants, TestKitBaseClass} import org.scalatest.funsuite.FixtureAnyFunSuiteLike @@ -49,26 +47,18 @@ class WaitForChannelReadyStateSpec extends TestKitBaseClass with FixtureAnyFunSu override def withFixture(test: OneArgTest): Outcome = { val setup = init(tags = test.tags) import setup._ - val channelConfig = ChannelConfig.standard val channelFlags = ChannelFlags(announceChannel = test.tags.contains(ChannelStateTestsTags.ChannelsPublic)) - val (aliceParams, bobParams, channelType) = computeFeatures(setup, test.tags, channelFlags) - val commitFeerate = channelType.commitmentFormat match { - case Transactions.DefaultCommitmentFormat => TestConstants.feeratePerKw - case _: Transactions.AnchorOutputsCommitmentFormat | _: Transactions.SimpleTaprootChannelCommitmentFormat => TestConstants.anchorOutputsFeeratePerKw - } - val pushMsat = if (test.tags.contains(ChannelStateTestsTags.NoPushAmount)) None else Some(TestConstants.initiatorPushAmount) - val aliceInit = Init(aliceParams.initFeatures) - val bobInit = Init(bobParams.initFeatures) + val channelParams = computeChannelParams(setup, test.tags, channelFlags) + val pushAmount = if (test.tags.contains(ChannelStateTestsTags.NoPushAmount)) None else Some(TestConstants.initiatorPushAmount) val aliceListener = TestProbe() val bobListener = TestProbe() - within(30 seconds) { alice.underlying.system.eventStream.subscribe(aliceListener.ref, classOf[ChannelAborted]) bob.underlying.system.eventStream.subscribe(bobListener.ref, classOf[ChannelAborted]) - alice.underlyingActor.nodeParams.db.peers.addOrUpdateRelayFees(bobParams.nodeId, relayFees) - alice ! INPUT_INIT_CHANNEL_INITIATOR(ByteVector32.Zeroes, TestConstants.fundingSatoshis, dualFunded = false, commitFeerate, TestConstants.feeratePerKw, fundingTxFeeBudget_opt = None, pushMsat, requireConfirmedInputs = false, requestFunding_opt = None, aliceParams, alice2bob.ref, bobInit, channelFlags, channelConfig, channelType, replyTo = aliceOpenReplyTo.ref.toTyped) + alice.underlyingActor.nodeParams.db.peers.addOrUpdateRelayFees(channelParams.bobChannelParams.nodeId, relayFees) + alice ! channelParams.initChannelAlice(TestConstants.fundingSatoshis, pushAmount_opt = pushAmount, channelFlags = channelFlags) alice2blockchain.expectMsgType[TxPublisher.SetChannelId] - bob ! INPUT_INIT_CHANNEL_NON_INITIATOR(ByteVector32.Zeroes, None, dualFunded = false, None, requireConfirmedInputs = false, bobParams, bob2alice.ref, aliceInit, channelConfig, channelType) + bob ! channelParams.initChannelBob() bob2blockchain.expectMsgType[TxPublisher.SetChannelId] alice2bob.expectMsgType[OpenChannel] alice2bob.forward(bob) @@ -207,9 +197,9 @@ class WaitForChannelReadyStateSpec extends TestKitBaseClass with FixtureAnyFunSu import f._ // we have a real scid at this stage, because this isn't a zero-conf channel val aliceIds = alice.stateData.asInstanceOf[DATA_WAIT_FOR_CHANNEL_READY].aliases - assert(alice.stateData.asInstanceOf[DATA_WAIT_FOR_CHANNEL_READY].commitments.params.channelFlags.announceChannel) + assert(alice.stateData.asInstanceOf[DATA_WAIT_FOR_CHANNEL_READY].commitments.announceChannel) val bobIds = bob.stateData.asInstanceOf[DATA_WAIT_FOR_CHANNEL_READY].aliases - assert(bob.stateData.asInstanceOf[DATA_WAIT_FOR_CHANNEL_READY].commitments.params.channelFlags.announceChannel) + assert(bob.stateData.asInstanceOf[DATA_WAIT_FOR_CHANNEL_READY].commitments.announceChannel) val channelReady = bob2alice.expectMsgType[ChannelReady] assert(channelReady.alias_opt.contains(bobIds.localAlias)) bob2alice.forward(alice) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForDualFundingConfirmedStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForDualFundingConfirmedStateSpec.scala index 697d77efb1..f144173b41 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForDualFundingConfirmedStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForDualFundingConfirmedStateSpec.scala @@ -16,7 +16,7 @@ package fr.acinq.eclair.channel.states.c -import akka.actor.typed.scaladsl.adapter.{ClassicActorRefOps, actorRefAdapter} +import akka.actor.typed.scaladsl.adapter.actorRefAdapter import akka.testkit.{TestFSMRef, TestProbe} import com.softwaremill.quicklens.{ModifyPimp, QuicklensAt} import fr.acinq.bitcoin.ScriptFlags @@ -34,7 +34,6 @@ import fr.acinq.eclair.channel.publish.TxPublisher.SetChannelId import fr.acinq.eclair.channel.states.ChannelStateTestsBase.{FakeTxPublisherFactory, PimpTestFSM} import fr.acinq.eclair.channel.states.{ChannelStateTestsBase, ChannelStateTestsTags} import fr.acinq.eclair.testutils.PimpTestProbe.convert -import fr.acinq.eclair.transactions.Transactions import fr.acinq.eclair.transactions.Transactions.{ClaimLocalAnchorTx, ClaimRemoteAnchorTx} import fr.acinq.eclair.wire.protocol._ import fr.acinq.eclair.{BlockHeight, MilliSatoshiLong, TestConstants, TestKitBaseClass, ToMilliSatoshiConversion} @@ -69,15 +68,7 @@ class WaitForDualFundingConfirmedStateSpec extends TestKitBaseClass with Fixture bob.underlying.system.eventStream.subscribe(bobListener.ref, classOf[ChannelAborted]) bob.underlying.system.eventStream.subscribe(bobListener.ref, classOf[ChannelClosed]) - val channelConfig = ChannelConfig.standard - val channelFlags = ChannelFlags(announceChannel = false) - val (aliceParams, bobParams, channelType) = computeFeatures(setup, test.tags, channelFlags) - val commitFeerate = channelType.commitmentFormat match { - case Transactions.DefaultCommitmentFormat => TestConstants.feeratePerKw - case _: Transactions.AnchorOutputsCommitmentFormat | _: Transactions.SimpleTaprootChannelCommitmentFormat => TestConstants.anchorOutputsFeeratePerKw - } - val aliceInit = Init(aliceParams.initFeatures) - val bobInit = Init(bobParams.initFeatures) + val channelParams = computeChannelParams(setup, test.tags) val (requestFunding_opt, bobContribution) = if (test.tags.contains(noFundingContribution)) { (None, None) } else if (test.tags.contains(liquidityPurchase)) { @@ -90,8 +81,8 @@ class WaitForDualFundingConfirmedStateSpec extends TestKitBaseClass with Fixture } val (initiatorPushAmount, nonInitiatorPushAmount) = if (test.tags.contains(bothPushAmount)) (Some(TestConstants.initiatorPushAmount), Some(TestConstants.nonInitiatorPushAmount)) else (None, None) within(30 seconds) { - alice ! INPUT_INIT_CHANNEL_INITIATOR(ByteVector32.Zeroes, TestConstants.fundingSatoshis, dualFunded = true, commitFeerate, TestConstants.feeratePerKw, fundingTxFeeBudget_opt = None, initiatorPushAmount, requireConfirmedInputs = false, requestFunding_opt, aliceParams, alice2bob.ref, bobInit, channelFlags, channelConfig, channelType, replyTo = aliceOpenReplyTo.ref.toTyped) - bob ! INPUT_INIT_CHANNEL_NON_INITIATOR(ByteVector32.Zeroes, bobContribution, dualFunded = true, nonInitiatorPushAmount, requireConfirmedInputs = false, bobParams, bob2alice.ref, aliceInit, channelConfig, channelType) + alice ! channelParams.initChannelAlice(TestConstants.fundingSatoshis, dualFunded = true, pushAmount_opt = initiatorPushAmount, requestFunding_opt = requestFunding_opt) + bob ! channelParams.initChannelBob(bobContribution, dualFunded = true, pushAmount_opt = nonInitiatorPushAmount) alice2blockchain.expectMsgType[SetChannelId] // temporary channel id bob2blockchain.expectMsgType[SetChannelId] // temporary channel id alice2bob.expectMsgType[OpenDualFundedChannel] diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForDualFundingReadyStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForDualFundingReadyStateSpec.scala index a2c691dd7e..a921194a25 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForDualFundingReadyStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForDualFundingReadyStateSpec.scala @@ -16,7 +16,6 @@ package fr.acinq.eclair.channel.states.c -import akka.actor.typed.scaladsl.adapter.ClassicActorRefOps import akka.testkit.{TestFSMRef, TestProbe} import fr.acinq.bitcoin.scalacompat.{ByteVector32, Transaction} import fr.acinq.eclair.blockchain.bitcoind.ZmqWatcher._ @@ -46,16 +45,13 @@ class WaitForDualFundingReadyStateSpec extends TestKitBaseClass with FixtureAnyF val setup = init(tags = test.tags) import setup._ - val channelConfig = ChannelConfig.standard val channelFlags = ChannelFlags(announceChannel = test.tags.contains(ChannelStateTestsTags.ChannelsPublic)) - val (aliceParams, bobParams, channelType) = computeFeatures(setup, test.tags, channelFlags) - val aliceInit = Init(aliceParams.initFeatures) - val bobInit = Init(bobParams.initFeatures) + val channelParams = computeChannelParams(setup, test.tags, channelFlags) val listener = TestProbe() within(30 seconds) { alice.underlying.system.eventStream.subscribe(listener.ref, classOf[ChannelAborted]) - alice ! INPUT_INIT_CHANNEL_INITIATOR(ByteVector32.Zeroes, TestConstants.fundingSatoshis, dualFunded = true, TestConstants.anchorOutputsFeeratePerKw, TestConstants.feeratePerKw, fundingTxFeeBudget_opt = None, None, requireConfirmedInputs = false, requestFunding_opt = None, aliceParams, alice2bob.ref, bobInit, channelFlags, channelConfig, channelType, replyTo = aliceOpenReplyTo.ref.toTyped) - bob ! INPUT_INIT_CHANNEL_NON_INITIATOR(ByteVector32.Zeroes, Some(LiquidityAds.AddFunding(TestConstants.nonInitiatorFundingSatoshis, None)), dualFunded = true, None, requireConfirmedInputs = false, bobParams, bob2alice.ref, aliceInit, channelConfig, channelType) + alice ! channelParams.initChannelAlice(TestConstants.fundingSatoshis, dualFunded = true, channelFlags = channelFlags) + bob ! channelParams.initChannelBob(Some(LiquidityAds.AddFunding(TestConstants.nonInitiatorFundingSatoshis, None)), dualFunded = true) alice2blockchain.expectMsgType[SetChannelId] // temporary channel id bob2blockchain.expectMsgType[SetChannelId] // temporary channel id alice2bob.expectMsgType[OpenDualFundedChannel] diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForFundingConfirmedStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForFundingConfirmedStateSpec.scala index 88a4c7b116..5b9ae47675 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForFundingConfirmedStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForFundingConfirmedStateSpec.scala @@ -16,7 +16,6 @@ package fr.acinq.eclair.channel.states.c -import akka.actor.typed.scaladsl.adapter.ClassicActorRefOps import akka.testkit.{TestFSMRef, TestProbe} import fr.acinq.bitcoin.scalacompat.{ByteVector32, SatoshiLong, Script, Transaction} import fr.acinq.eclair.blockchain.CurrentBlockHeight @@ -29,7 +28,7 @@ import fr.acinq.eclair.channel.publish.TxPublisher.PublishFinalTx import fr.acinq.eclair.channel.states.ChannelStateTestsBase.PimpTestFSM import fr.acinq.eclair.channel.states.{ChannelStateTestsBase, ChannelStateTestsTags} import fr.acinq.eclair.transactions.Scripts.multiSig2of2 -import fr.acinq.eclair.wire.protocol.{AcceptChannel, ChannelReady, Error, FundingCreated, FundingSigned, Init, OpenChannel, TlvStream} +import fr.acinq.eclair.wire.protocol.{AcceptChannel, ChannelReady, Error, FundingCreated, FundingSigned, OpenChannel, TlvStream} import fr.acinq.eclair.{BlockHeight, MilliSatoshiLong, TestConstants, TestKitBaseClass, randomKey} import org.scalatest.funsuite.FixtureAnyFunSuiteLike import org.scalatest.{Outcome, Tag} @@ -47,13 +46,8 @@ class WaitForFundingConfirmedStateSpec extends TestKitBaseClass with FixtureAnyF override def withFixture(test: OneArgTest): Outcome = { val setup = init(tags = test.tags) import setup._ - val channelConfig = ChannelConfig.standard - val channelFlags = ChannelFlags(announceChannel = false) - val (aliceParams, bobParams, channelType) = computeFeatures(setup, test.tags, channelFlags) - val pushMsat = if (test.tags.contains(ChannelStateTestsTags.NoPushAmount)) 0.msat else TestConstants.initiatorPushAmount - val aliceInit = Init(aliceParams.initFeatures) - val bobInit = Init(bobParams.initFeatures) - + val channelParams = computeChannelParams(setup, test.tags) + val pushAmount = if (test.tags.contains(ChannelStateTestsTags.NoPushAmount)) 0.msat else TestConstants.initiatorPushAmount within(30 seconds) { val listener = TestProbe() alice.underlying.system.eventStream.subscribe(listener.ref, classOf[TransactionPublished]) @@ -61,10 +55,9 @@ class WaitForFundingConfirmedStateSpec extends TestKitBaseClass with FixtureAnyF alice.underlying.system.eventStream.subscribe(listener.ref, classOf[ChannelClosed]) bob.underlying.system.eventStream.subscribe(listener.ref, classOf[ChannelAborted]) bob.underlying.system.eventStream.subscribe(listener.ref, classOf[ChannelClosed]) - val commitTxFeerate = if (test.tags.contains(ChannelStateTestsTags.AnchorOutputs) || test.tags.contains(ChannelStateTestsTags.AnchorOutputsZeroFeeHtlcTxs)) TestConstants.anchorOutputsFeeratePerKw else TestConstants.feeratePerKw - alice ! INPUT_INIT_CHANNEL_INITIATOR(ByteVector32.Zeroes, TestConstants.fundingSatoshis, dualFunded = false, commitTxFeerate, TestConstants.feeratePerKw, fundingTxFeeBudget_opt = None, Some(pushMsat), requireConfirmedInputs = false, requestFunding_opt = None, aliceParams, alice2bob.ref, bobInit, channelFlags, channelConfig, channelType, replyTo = aliceOpenReplyTo.ref.toTyped) + alice ! channelParams.initChannelAlice(TestConstants.fundingSatoshis, pushAmount_opt = Some(pushAmount)) alice2blockchain.expectMsgType[TxPublisher.SetChannelId] - bob ! INPUT_INIT_CHANNEL_NON_INITIATOR(ByteVector32.Zeroes, None, dualFunded = false, None, requireConfirmedInputs = false, bobParams, bob2alice.ref, aliceInit, channelConfig, channelType) + bob ! channelParams.initChannelBob() bob2blockchain.expectMsgType[TxPublisher.SetChannelId] alice2bob.expectMsgType[OpenChannel] alice2bob.forward(bob) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalQuiescentStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalQuiescentStateSpec.scala index e732f5f159..cd89e65153 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalQuiescentStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalQuiescentStateSpec.scala @@ -68,8 +68,8 @@ class NormalQuiescentStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteL private def reconnect(f: FixtureParam): Unit = { import f._ - val aliceInit = Init(alice.stateData.asInstanceOf[ChannelDataWithCommitments].commitments.params.localParams.initFeatures) - val bobInit = Init(bob.stateData.asInstanceOf[ChannelDataWithCommitments].commitments.params.localParams.initFeatures) + val aliceInit = Init(alice.commitments.localChannelParams.initFeatures) + val bobInit = Init(bob.commitments.localChannelParams.initFeatures) alice ! INPUT_RECONNECTED(alice2bob.ref, aliceInit, bobInit) bob ! INPUT_RECONNECTED(bob2alice.ref, bobInit, aliceInit) alice2bob.expectMsgType[ChannelReestablish] diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalSplicesStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalSplicesStateSpec.scala index 94ec27bb12..1436580307 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalSplicesStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalSplicesStateSpec.scala @@ -377,7 +377,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik bob2alice.ignoreMsg { case _: ChannelUpdate => true } awaitCond(alice.stateName == NORMAL && bob.stateName == NORMAL) val initialState = alice.stateData.asInstanceOf[DATA_NORMAL] - assert(!initialState.commitments.params.channelFeatures.hasFeature(Features.DualFunding)) + assert(!initialState.commitments.channelParams.channelFeatures.hasFeature(Features.DualFunding)) assert(initialState.commitments.latest.capacity == 1_000_000.sat) assert(initialState.commitments.latest.localCommit.spec.toLocal == 800_000_000.msat) assert(initialState.commitments.latest.localCommit.spec.toRemote == 200_000_000.msat) @@ -388,7 +388,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik // We can splice on top of a non dual-funded channel. initiateSplice(f, spliceIn_opt = Some(SpliceIn(500_000 sat))) val postSpliceState = alice.stateData.asInstanceOf[DATA_NORMAL] - assert(!postSpliceState.commitments.params.channelFeatures.hasFeature(Features.DualFunding)) + assert(!postSpliceState.commitments.channelParams.channelFeatures.hasFeature(Features.DualFunding)) assert(postSpliceState.commitments.latest.capacity == 1_500_000.sat) assert(postSpliceState.commitments.latest.localCommit.spec.toLocal == 1_300_000_000.msat) assert(postSpliceState.commitments.latest.localCommit.spec.toRemote == 200_000_000.msat) @@ -598,7 +598,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik val commitment = alice.stateData.asInstanceOf[DATA_NORMAL].commitments.latest assert(commitment.localCommit.spec.toLocal == 770_000_000.msat) assert(commitment.localChannelReserve == 15_000.sat) - val commitFees = Transactions.commitTxTotalCost(commitment.remoteParams.dustLimit, commitment.remoteCommit.spec, commitment.params.commitmentFormat) + val commitFees = Transactions.commitTxTotalCost(commitment.remoteCommitParams.dustLimit, commitment.remoteCommit.spec, commitment.commitmentFormat) assert(commitFees < 15_000.sat) val sender = TestProbe() @@ -618,7 +618,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik val commitment = alice.stateData.asInstanceOf[DATA_NORMAL].commitments.latest assert(commitment.localCommit.spec.toLocal == 650_000_000.msat) assert(commitment.localChannelReserve == 15_000.sat) - val commitFees = Transactions.commitTxTotalCost(commitment.remoteParams.dustLimit, commitment.remoteCommit.spec, commitment.params.commitmentFormat) + val commitFees = Transactions.commitTxTotalCost(commitment.remoteCommitParams.dustLimit, commitment.remoteCommit.spec, commitment.commitmentFormat) assert(commitFees > 20_000.sat) val sender = TestProbe() @@ -1715,8 +1715,8 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik private def reconnect(f: FixtureParam, sendReestablish: Boolean = true): (ChannelReestablish, ChannelReestablish) = { import f._ - val aliceInit = Init(alice.stateData.asInstanceOf[ChannelDataWithCommitments].commitments.params.localParams.initFeatures) - val bobInit = Init(bob.stateData.asInstanceOf[ChannelDataWithCommitments].commitments.params.localParams.initFeatures) + val aliceInit = Init(alice.commitments.localChannelParams.initFeatures) + val bobInit = Init(bob.commitments.localChannelParams.initFeatures) alice ! INPUT_RECONNECTED(alice2bob.ref, aliceInit, bobInit) bob ! INPUT_RECONNECTED(bob2alice.ref, bobInit, aliceInit) val channelReestablishAlice = alice2bob.expectMsgType[ChannelReestablish] @@ -3118,8 +3118,8 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik // Bob publishes his commit tx for the first splice transaction (which double-spends the second splice transaction). val bobCommitments = bob.stateData.asInstanceOf[ChannelDataWithCommitments].commitments val previousCommitment = bobCommitments.active.find(_.fundingTxIndex == 1).get - val bobCommitTx1 = previousCommitment.fullySignedLocalCommitTx(bobCommitments.params, bob.underlyingActor.channelKeys) - val bobHtlcTxs = previousCommitment.htlcTxs(bobCommitments.params, bob.underlyingActor.channelKeys).map(_._1) + val bobCommitTx1 = previousCommitment.fullySignedLocalCommitTx(bobCommitments.channelParams, bob.underlyingActor.channelKeys) + val bobHtlcTxs = previousCommitment.htlcTxs(bobCommitments.channelParams, bob.underlyingActor.channelKeys).map(_._1) Transaction.correctlySpends(bobCommitTx1, Seq(fundingTx1), ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS) alice ! WatchFundingSpentTriggered(bobCommitTx1) assert(alice2blockchain.expectMsgType[WatchAlternativeCommitTxConfirmed].txId == bobCommitTx1.txid) @@ -3557,12 +3557,12 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik crossSign(bob, alice, bob2alice, alice2bob) val aliceCommitments1 = alice.stateData.asInstanceOf[DATA_NORMAL].commitments aliceCommitments1.active.foreach { c => - val commitTx = c.fullySignedLocalCommitTx(aliceCommitments1.params, alice.underlyingActor.channelKeys) + val commitTx = c.fullySignedLocalCommitTx(aliceCommitments1.channelParams, alice.underlyingActor.channelKeys) Transaction.correctlySpends(commitTx, Map(c.commitInput.outPoint -> c.commitInput.txOut), ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS) } val bobCommitments1 = bob.stateData.asInstanceOf[DATA_NORMAL].commitments bobCommitments1.active.foreach { c => - val commitTx = c.fullySignedLocalCommitTx(bobCommitments1.params, bob.underlyingActor.channelKeys) + val commitTx = c.fullySignedLocalCommitTx(bobCommitments1.channelParams, bob.underlyingActor.channelKeys) Transaction.correctlySpends(commitTx, Map(c.commitInput.outPoint -> c.commitInput.txOut), ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS) } @@ -3571,12 +3571,12 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik crossSign(alice, bob, alice2bob, bob2alice) val aliceCommitments2 = alice.stateData.asInstanceOf[DATA_NORMAL].commitments aliceCommitments2.active.foreach { c => - val commitTx = c.fullySignedLocalCommitTx(aliceCommitments2.params, alice.underlyingActor.channelKeys) + val commitTx = c.fullySignedLocalCommitTx(aliceCommitments2.channelParams, alice.underlyingActor.channelKeys) Transaction.correctlySpends(commitTx, Map(c.commitInput.outPoint -> c.commitInput.txOut), ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS) } val bobCommitments2 = bob.stateData.asInstanceOf[DATA_NORMAL].commitments bobCommitments2.active.foreach { c => - val commitTx = c.fullySignedLocalCommitTx(bobCommitments2.params, bob.underlyingActor.channelKeys) + val commitTx = c.fullySignedLocalCommitTx(bobCommitments2.channelParams, bob.underlyingActor.channelKeys) Transaction.correctlySpends(commitTx, Map(c.commitInput.outPoint -> c.commitInput.txOut), ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala index 6cc4db2eac..94625fd169 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala @@ -31,7 +31,6 @@ import fr.acinq.eclair.blockchain.{CurrentBlockHeight, CurrentFeerates} import fr.acinq.eclair.channel._ import fr.acinq.eclair.channel.fsm.Channel._ import fr.acinq.eclair.channel.publish.TxPublisher.{PublishFinalTx, PublishReplaceableTx} -import fr.acinq.eclair.channel.publish._ import fr.acinq.eclair.channel.states.ChannelStateTestsBase.PimpTestFSM import fr.acinq.eclair.channel.states.{ChannelStateTestsBase, ChannelStateTestsTags} import fr.acinq.eclair.crypto.Sphinx @@ -189,7 +188,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with import f._ val sender = TestProbe() // Alice has a minimum set to 0 msat (which should be invalid, but may mislead Bob into relaying 0-value HTLCs which is forbidden by the spec). - assert(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.params.localParams.htlcMinimum == 0.msat) + assert(alice.commitments.latest.localCommitParams.htlcMinimum == 0.msat) val initialState = bob.stateData.asInstanceOf[DATA_NORMAL] val add = CMD_ADD_HTLC(sender.ref, 0 msat, randomBytes32(), CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, None, 1.0, None, localOrigin(sender.ref)) bob ! add @@ -224,7 +223,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with val sender = TestProbe() val initialState = alice.stateData.asInstanceOf[DATA_NORMAL] // The anchor outputs commitment format costs more fees for the funder (bigger commit tx + cost of anchor outputs) - assert(initialState.commitments.availableBalanceForSend < initialState.commitments.modify(_.params.channelFeatures).setTo(ChannelFeatures()).availableBalanceForSend) + assert(initialState.commitments.availableBalanceForSend < initialState.commitments.modify(_.channelParams.channelFeatures).setTo(ChannelFeatures()).availableBalanceForSend) val add = CMD_ADD_HTLC(sender.ref, initialState.commitments.availableBalanceForSend + 1.msat, randomBytes32(), CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, None, 1.0, None, localOrigin(sender.ref)) alice ! add @@ -345,8 +344,8 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with import f._ val sender = TestProbe() val initialState = bob.stateData.asInstanceOf[DATA_NORMAL] - assert(initialState.commitments.params.localParams.maxHtlcValueInFlightMsat == UInt64(initialState.commitments.latest.capacity.toMilliSatoshi.toLong)) - assert(initialState.commitments.params.remoteParams.maxHtlcValueInFlightMsat == UInt64(150_000_000)) + assert(initialState.commitments.latest.localCommitParams.maxHtlcValueInFlight == UInt64(initialState.commitments.latest.capacity.toMilliSatoshi.toLong)) + assert(initialState.commitments.latest.remoteCommitParams.maxHtlcValueInFlight == UInt64(150_000_000)) val add = CMD_ADD_HTLC(sender.ref, 151_000_000 msat, randomBytes32(), CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, None, 1.0, None, localOrigin(sender.ref)) bob ! add val error = HtlcValueTooHighInFlight(channelId(bob), maximum = UInt64(150_000_000), actual = 151_000_000 msat) @@ -358,8 +357,8 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with import f._ val sender = TestProbe() val initialState = bob.stateData.asInstanceOf[DATA_NORMAL] - assert(initialState.commitments.params.localParams.maxHtlcValueInFlightMsat == UInt64(initialState.commitments.latest.capacity.toMilliSatoshi.toLong)) - assert(initialState.commitments.params.remoteParams.maxHtlcValueInFlightMsat == UInt64(150_000_000)) + assert(initialState.commitments.latest.localCommitParams.maxHtlcValueInFlight == UInt64(initialState.commitments.latest.capacity.toMilliSatoshi.toLong)) + assert(initialState.commitments.latest.remoteCommitParams.maxHtlcValueInFlight == UInt64(150_000_000)) val add = CMD_ADD_HTLC(sender.ref, 75_500_000 msat, randomBytes32(), CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, None, 1.0, None, localOrigin(sender.ref)) bob ! add sender.expectMsgType[RES_SUCCESS[CMD_ADD_HTLC]] @@ -375,8 +374,8 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with import f._ val sender = TestProbe() val initialState = alice.stateData.asInstanceOf[DATA_NORMAL] - assert(initialState.commitments.params.localParams.maxHtlcValueInFlightMsat == UInt64(150_000_000)) - assert(initialState.commitments.params.remoteParams.maxHtlcValueInFlightMsat == UInt64(initialState.commitments.latest.capacity.toMilliSatoshi.toLong)) + assert(initialState.commitments.latest.localCommitParams.maxHtlcValueInFlight == UInt64(150_000_000)) + assert(initialState.commitments.latest.remoteCommitParams.maxHtlcValueInFlight == UInt64(initialState.commitments.latest.capacity.toMilliSatoshi.toLong)) val add = CMD_ADD_HTLC(sender.ref, 151_000_000 msat, randomBytes32(), CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, None, 1.0, None, localOrigin(sender.ref)) alice ! add val error = HtlcValueTooHighInFlight(channelId(alice), maximum = UInt64(150_000_000), actual = 151_000_000 msat) @@ -388,14 +387,14 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with import f._ val sender = TestProbe() val initialState = alice.stateData.asInstanceOf[DATA_NORMAL] - assert(initialState.commitments.params.localParams.maxAcceptedHtlcs == 100) - assert(initialState.commitments.params.remoteParams.maxAcceptedHtlcs == 30) // Bob accepts a maximum of 30 htlcs + assert(initialState.commitments.latest.localCommitParams.maxAcceptedHtlcs == 100) + assert(initialState.commitments.latest.remoteCommitParams.maxAcceptedHtlcs == 30) // Bob accepts a maximum of 30 htlcs for (_ <- 0 until 30) { - alice ! CMD_ADD_HTLC(sender.ref, 10000000 msat, randomBytes32(), CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, None, 1.0, None, localOrigin(sender.ref)) + alice ! CMD_ADD_HTLC(sender.ref, 10_000_000 msat, randomBytes32(), CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, None, 1.0, None, localOrigin(sender.ref)) sender.expectMsgType[RES_SUCCESS[CMD_ADD_HTLC]] alice2bob.expectMsgType[UpdateAddHtlc] } - val add = CMD_ADD_HTLC(sender.ref, 10000000 msat, randomBytes32(), CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, None, 1.0, None, localOrigin(sender.ref)) + val add = CMD_ADD_HTLC(sender.ref, 10_000_000 msat, randomBytes32(), CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, None, 1.0, None, localOrigin(sender.ref)) alice ! add val error = TooManyAcceptedHtlcs(channelId(alice), maximum = 30) sender.expectMsg(RES_ADD_FAILED(add, error, Some(initialState.channelUpdate))) @@ -406,14 +405,14 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with import f._ val sender = TestProbe() val initialState = bob.stateData.asInstanceOf[DATA_NORMAL] - assert(initialState.commitments.params.localParams.maxAcceptedHtlcs == 30) // Bob accepts a maximum of 30 htlcs - assert(initialState.commitments.params.remoteParams.maxAcceptedHtlcs == 100) // Alice accepts more, but Bob will stop at 30 HTLCs + assert(initialState.commitments.latest.localCommitParams.maxAcceptedHtlcs == 30) // Bob accepts a maximum of 30 htlcs + assert(initialState.commitments.latest.remoteCommitParams.maxAcceptedHtlcs == 100) // Alice accepts more, but Bob will stop at 30 HTLCs for (_ <- 0 until 30) { - bob ! CMD_ADD_HTLC(sender.ref, 500000 msat, randomBytes32(), CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, None, 1.0, None, localOrigin(sender.ref)) + bob ! CMD_ADD_HTLC(sender.ref, 500_000 msat, randomBytes32(), CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, None, 1.0, None, localOrigin(sender.ref)) sender.expectMsgType[RES_SUCCESS[CMD_ADD_HTLC]] bob2alice.expectMsgType[UpdateAddHtlc] } - val add = CMD_ADD_HTLC(sender.ref, 500000 msat, randomBytes32(), CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, None, 1.0, None, localOrigin(sender.ref)) + val add = CMD_ADD_HTLC(sender.ref, 500_000 msat, randomBytes32(), CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, None, 1.0, None, localOrigin(sender.ref)) bob ! add val error = TooManyAcceptedHtlcs(channelId(bob), maximum = 30) sender.expectMsg(RES_ADD_FAILED(add, error, Some(initialState.channelUpdate))) @@ -426,10 +425,10 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with val initialState = alice.stateData.asInstanceOf[DATA_NORMAL] val aliceCommitments = initialState.commitments assert(alice.underlyingActor.nodeParams.onChainFeeConf.feerateToleranceFor(bob.underlyingActor.nodeParams.nodeId).dustTolerance.maxExposure == 25_000.sat) - assert(Transactions.offeredHtlcTrimThreshold(aliceCommitments.params.localParams.dustLimit, aliceCommitments.latest.localCommit.spec, aliceCommitments.params.commitmentFormat) == 7730.sat) - assert(Transactions.receivedHtlcTrimThreshold(aliceCommitments.params.localParams.dustLimit, aliceCommitments.latest.localCommit.spec, aliceCommitments.params.commitmentFormat) == 8130.sat) - assert(Transactions.offeredHtlcTrimThreshold(aliceCommitments.params.remoteParams.dustLimit, aliceCommitments.latest.localCommit.spec, aliceCommitments.params.commitmentFormat) == 7630.sat) - assert(Transactions.receivedHtlcTrimThreshold(aliceCommitments.params.remoteParams.dustLimit, aliceCommitments.latest.localCommit.spec, aliceCommitments.params.commitmentFormat) == 8030.sat) + assert(Transactions.offeredHtlcTrimThreshold(aliceCommitments.latest.localCommitParams.dustLimit, aliceCommitments.latest.localCommit.spec, aliceCommitments.latest.commitmentFormat) == 7730.sat) + assert(Transactions.receivedHtlcTrimThreshold(aliceCommitments.latest.localCommitParams.dustLimit, aliceCommitments.latest.localCommit.spec, aliceCommitments.latest.commitmentFormat) == 8130.sat) + assert(Transactions.offeredHtlcTrimThreshold(aliceCommitments.latest.remoteCommitParams.dustLimit, aliceCommitments.latest.localCommit.spec, aliceCommitments.latest.commitmentFormat) == 7630.sat) + assert(Transactions.receivedHtlcTrimThreshold(aliceCommitments.latest.remoteCommitParams.dustLimit, aliceCommitments.latest.localCommit.spec, aliceCommitments.latest.commitmentFormat) == 8030.sat) // Alice sends HTLCs to Bob that add 10 000 sat to the dust exposure: addHtlc(500.sat.toMilliSatoshi, alice, bob, alice2bob, bob2alice) // dust htlc @@ -937,8 +936,8 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with } assert(alice.stateData.asInstanceOf[DATA_NORMAL].channelUpdate.channelFlags.isEnabled) inside(bobListener.expectMsgType[LocalChannelUpdate]) { lcu => - assert(lcu.commitments.params.localParams.htlcMinimum == 1000.msat) - assert(lcu.commitments.params.remoteParams.htlcMinimum == 0.msat) + assert(lcu.commitments.channelParams.localCommitParams.htlcMinimum == 1000.msat) + assert(lcu.commitments.channelParams.remoteCommitParams.htlcMinimum == 0.msat) assert(lcu.channelUpdate.htlcMaximumMsat == 1000.msat) assert(lcu.channelUpdate.shortChannelId.isInstanceOf[RealShortChannelId]) assert(lcu.channelUpdate.channelFlags.isEnabled) @@ -1395,8 +1394,8 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with import f._ val aliceCommitments = alice.stateData.asInstanceOf[DATA_NORMAL].commitments assert(alice.underlyingActor.nodeParams.onChainFeeConf.feerateToleranceFor(bob.underlyingActor.nodeParams.nodeId).dustTolerance.maxExposure == 25_000.sat) - assert(Transactions.offeredHtlcTrimThreshold(aliceCommitments.params.localParams.dustLimit, aliceCommitments.latest.localCommit.spec, aliceCommitments.params.commitmentFormat) == 7730.sat) - assert(Transactions.receivedHtlcTrimThreshold(aliceCommitments.params.remoteParams.dustLimit, aliceCommitments.latest.localCommit.spec, aliceCommitments.params.commitmentFormat) == 8030.sat) + assert(Transactions.offeredHtlcTrimThreshold(aliceCommitments.latest.localCommitParams.dustLimit, aliceCommitments.latest.localCommit.spec, aliceCommitments.latest.commitmentFormat) == 7730.sat) + assert(Transactions.receivedHtlcTrimThreshold(aliceCommitments.latest.remoteCommitParams.dustLimit, aliceCommitments.latest.localCommit.spec, aliceCommitments.latest.commitmentFormat) == 8030.sat) // Alice sends HTLCs to Bob that add 10 000 sat to the dust exposure: addHtlc(500.sat.toMilliSatoshi, alice, bob, alice2bob, bob2alice) // dust htlc @@ -1586,8 +1585,8 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with def testRevokeAndAckHtlcStaticRemoteKey(f: FixtureParam): Unit = { import f._ - assert(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.params.localParams.initFeatures.hasFeature(StaticRemoteKey)) - assert(bob.stateData.asInstanceOf[DATA_NORMAL].commitments.params.localParams.initFeatures.hasFeature(StaticRemoteKey)) + assert(alice.commitments.localChannelParams.initFeatures.hasFeature(StaticRemoteKey)) + assert(bob.commitments.localChannelParams.initFeatures.hasFeature(StaticRemoteKey)) def aliceToRemoteScript(): ByteVector = { val toRemoteAmount = alice.stateData.asInstanceOf[DATA_NORMAL].commitments.latest.localCommit.spec.toRemote @@ -1597,7 +1596,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with val initialToRemoteScript = aliceToRemoteScript() - addHtlc(50000000 msat, alice, bob, alice2bob, bob2alice) + addHtlc(50_000_000 msat, alice, bob, alice2bob, bob2alice) alice ! CMD_SIGN() alice2bob.expectMsgType[CommitSig] @@ -1639,10 +1638,10 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with alice2bob.forward(bob) // actual test begins - awaitCond(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.remoteNextCommitInfo.isLeft) + awaitCond(alice.commitments.remoteNextCommitInfo.isLeft) val peer = TestProbe() - alice ! RevocationTimeout(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.remoteCommitIndex, peer.ref) - peer.expectMsg(Peer.Disconnect(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.params.remoteParams.nodeId)) + alice ! RevocationTimeout(alice.commitments.remoteCommitIndex, peer.ref) + peer.expectMsg(Peer.Disconnect(alice.commitments.remoteNodeId)) } private def testReceiveCmdFulfillHtlc(f: FixtureParam): Unit = { @@ -2084,8 +2083,8 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with addHtlc(14000.sat.toMilliSatoshi, alice, bob, alice2bob, bob2alice) crossSign(alice, bob, alice2bob, bob2alice) val aliceCommitments = alice.stateData.asInstanceOf[DATA_NORMAL].commitments - assert(DustExposure.computeExposure(aliceCommitments.latest.localCommit.spec, aliceCommitments.params.localParams.dustLimit, aliceCommitments.params.commitmentFormat) == 0.msat) - assert(DustExposure.computeExposure(aliceCommitments.latest.remoteCommit.spec, aliceCommitments.params.remoteParams.dustLimit, aliceCommitments.params.commitmentFormat) == 0.msat) + assert(DustExposure.computeExposure(aliceCommitments.latest.localCommit.spec, aliceCommitments.latest.localCommitParams.dustLimit, aliceCommitments.latest.commitmentFormat) == 0.msat) + assert(DustExposure.computeExposure(aliceCommitments.latest.remoteCommit.spec, aliceCommitments.latest.remoteCommitParams.dustLimit, aliceCommitments.latest.commitmentFormat) == 0.msat) // A large feerate increase would make these HTLCs overflow alice's dust exposure, so she rejects it: val sender = TestProbe() @@ -2109,8 +2108,8 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with // Alice sends another HTLC to Bob that is not included in the dust exposure at the current feerate. addHtlc(14000.sat.toMilliSatoshi, alice, bob, alice2bob, bob2alice) val aliceCommitments = alice.stateData.asInstanceOf[DATA_NORMAL].commitments - assert(DustExposure.computeExposure(aliceCommitments.latest.localCommit.spec, aliceCommitments.params.localParams.dustLimit, aliceCommitments.params.commitmentFormat) == 0.msat) - assert(DustExposure.computeExposure(aliceCommitments.latest.remoteCommit.spec, aliceCommitments.params.remoteParams.dustLimit, aliceCommitments.params.commitmentFormat) == 0.msat) + assert(DustExposure.computeExposure(aliceCommitments.latest.localCommit.spec, aliceCommitments.latest.localCommitParams.dustLimit, aliceCommitments.latest.commitmentFormat) == 0.msat) + assert(DustExposure.computeExposure(aliceCommitments.latest.remoteCommit.spec, aliceCommitments.latest.remoteCommitParams.dustLimit, aliceCommitments.latest.commitmentFormat) == 0.msat) // A large feerate increase would make these HTLCs overflow alice's dust exposure, so she rejects it: val cmd = CMD_UPDATE_FEE(FeeratePerKw(20000 sat), replyTo_opt = Some(sender.ref)) @@ -2128,20 +2127,20 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with updateFee(initialFeerate, alice, bob, alice2bob, bob2alice) val aliceCommitments = alice.stateData.asInstanceOf[DATA_NORMAL].commitments assert(alice.underlyingActor.nodeParams.onChainFeeConf.feerateToleranceFor(bob.underlyingActor.nodeParams.nodeId).dustTolerance.maxExposure == 25_000.sat) - val higherDustLimit = Seq(aliceCommitments.params.localParams.dustLimit, aliceCommitments.params.remoteParams.dustLimit).max - val lowerDustLimit = Seq(aliceCommitments.params.localParams.dustLimit, aliceCommitments.params.remoteParams.dustLimit).min + val higherDustLimit = Seq(aliceCommitments.latest.localCommitParams.dustLimit, aliceCommitments.latest.remoteCommitParams.dustLimit).max + val lowerDustLimit = Seq(aliceCommitments.latest.localCommitParams.dustLimit, aliceCommitments.latest.remoteCommitParams.dustLimit).min // We have the following dust thresholds at the current feerate - assert(Transactions.offeredHtlcTrimThreshold(higherDustLimit, aliceCommitments.latest.localCommit.spec.copy(commitTxFeerate = DustExposure.feerateForDustExposure(initialFeerate)), aliceCommitments.params.commitmentFormat) == 6989.sat) - assert(Transactions.receivedHtlcTrimThreshold(higherDustLimit, aliceCommitments.latest.localCommit.spec.copy(commitTxFeerate = DustExposure.feerateForDustExposure(initialFeerate)), aliceCommitments.params.commitmentFormat) == 7109.sat) - assert(Transactions.offeredHtlcTrimThreshold(lowerDustLimit, aliceCommitments.latest.localCommit.spec.copy(commitTxFeerate = DustExposure.feerateForDustExposure(initialFeerate)), aliceCommitments.params.commitmentFormat) == 2989.sat) - assert(Transactions.receivedHtlcTrimThreshold(lowerDustLimit, aliceCommitments.latest.localCommit.spec.copy(commitTxFeerate = DustExposure.feerateForDustExposure(initialFeerate)), aliceCommitments.params.commitmentFormat) == 3109.sat) + assert(Transactions.offeredHtlcTrimThreshold(higherDustLimit, aliceCommitments.latest.localCommit.spec.copy(commitTxFeerate = DustExposure.feerateForDustExposure(initialFeerate)), aliceCommitments.latest.commitmentFormat) == 6989.sat) + assert(Transactions.receivedHtlcTrimThreshold(higherDustLimit, aliceCommitments.latest.localCommit.spec.copy(commitTxFeerate = DustExposure.feerateForDustExposure(initialFeerate)), aliceCommitments.latest.commitmentFormat) == 7109.sat) + assert(Transactions.offeredHtlcTrimThreshold(lowerDustLimit, aliceCommitments.latest.localCommit.spec.copy(commitTxFeerate = DustExposure.feerateForDustExposure(initialFeerate)), aliceCommitments.latest.commitmentFormat) == 2989.sat) + assert(Transactions.receivedHtlcTrimThreshold(lowerDustLimit, aliceCommitments.latest.localCommit.spec.copy(commitTxFeerate = DustExposure.feerateForDustExposure(initialFeerate)), aliceCommitments.latest.commitmentFormat) == 3109.sat) // And the following thresholds after the feerate update // NB: we apply the real feerate when sending update_fee, not the one adjusted for dust val updatedFeerate = FeeratePerKw(4000 sat) - assert(Transactions.offeredHtlcTrimThreshold(higherDustLimit, aliceCommitments.latest.localCommit.spec.copy(commitTxFeerate = updatedFeerate), aliceCommitments.params.commitmentFormat) == 7652.sat) - assert(Transactions.receivedHtlcTrimThreshold(higherDustLimit, aliceCommitments.latest.localCommit.spec.copy(commitTxFeerate = updatedFeerate), aliceCommitments.params.commitmentFormat) == 7812.sat) - assert(Transactions.offeredHtlcTrimThreshold(lowerDustLimit, aliceCommitments.latest.localCommit.spec.copy(commitTxFeerate = updatedFeerate), aliceCommitments.params.commitmentFormat) == 3652.sat) - assert(Transactions.receivedHtlcTrimThreshold(lowerDustLimit, aliceCommitments.latest.localCommit.spec.copy(commitTxFeerate = updatedFeerate), aliceCommitments.params.commitmentFormat) == 3812.sat) + assert(Transactions.offeredHtlcTrimThreshold(higherDustLimit, aliceCommitments.latest.localCommit.spec.copy(commitTxFeerate = updatedFeerate), aliceCommitments.latest.commitmentFormat) == 7652.sat) + assert(Transactions.receivedHtlcTrimThreshold(higherDustLimit, aliceCommitments.latest.localCommit.spec.copy(commitTxFeerate = updatedFeerate), aliceCommitments.latest.commitmentFormat) == 7812.sat) + assert(Transactions.offeredHtlcTrimThreshold(lowerDustLimit, aliceCommitments.latest.localCommit.spec.copy(commitTxFeerate = updatedFeerate), aliceCommitments.latest.commitmentFormat) == 3652.sat) + assert(Transactions.receivedHtlcTrimThreshold(lowerDustLimit, aliceCommitments.latest.localCommit.spec.copy(commitTxFeerate = updatedFeerate), aliceCommitments.latest.commitmentFormat) == 3812.sat) // Alice send HTLCs to Bob that are not included in the dust exposure at the current feerate. // She signs them but Bob doesn't answer yet. @@ -2158,7 +2157,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with alice.setBitcoinCoreFeerate(updatedFeerate) bob.setBitcoinCoreFeerate(updatedFeerate) alice ! cmd - if (higherDustLimit == aliceCommitments.params.localParams.dustLimit) { + if (higherDustLimit == aliceCommitments.latest.localCommitParams.dustLimit) { sender.expectMsg(RES_FAILURE(cmd, LocalDustHtlcExposureTooHigh(channelId(alice), 25000 sat, 29600000 msat))) } else { sender.expectMsg(RES_FAILURE(cmd, RemoteDustHtlcExposureTooHigh(channelId(alice), 25000 sat, 29600000 msat))) @@ -2322,7 +2321,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with import f._ val bobCommitments = bob.stateData.asInstanceOf[DATA_NORMAL].commitments val tx = bob.signCommitTx() - val expectedFeeratePerKw = bob.underlyingActor.nodeParams.onChainFeeConf.getCommitmentFeerate(bob.underlyingActor.nodeParams.currentBitcoinCoreFeerates, bob.underlyingActor.remoteNodeId, bobCommitments.params.commitmentFormat, bobCommitments.latest.capacity) + val expectedFeeratePerKw = bob.underlyingActor.nodeParams.onChainFeeConf.getCommitmentFeerate(bob.underlyingActor.nodeParams.currentBitcoinCoreFeerates, bob.underlyingActor.remoteNodeId, bobCommitments.latest.commitmentFormat, bobCommitments.latest.capacity) assert(bobCommitments.latest.localCommit.spec.commitTxFeerate == expectedFeeratePerKw) bob ! UpdateFee(ByteVector32.Zeroes, FeeratePerKw(252 sat)) val error = bob2alice.expectMsgType[Error] @@ -2344,8 +2343,8 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with addHtlc(14000.sat.toMilliSatoshi, alice, bob, alice2bob, bob2alice) crossSign(alice, bob, alice2bob, bob2alice) val bobCommitments = bob.stateData.asInstanceOf[DATA_NORMAL].commitments - assert(DustExposure.computeExposure(bobCommitments.latest.localCommit.spec, bobCommitments.params.localParams.dustLimit, bobCommitments.params.commitmentFormat) == 0.msat) - assert(DustExposure.computeExposure(bobCommitments.latest.remoteCommit.spec, bobCommitments.params.remoteParams.dustLimit, bobCommitments.params.commitmentFormat) == 0.msat) + assert(DustExposure.computeExposure(bobCommitments.latest.localCommit.spec, bobCommitments.latest.localCommitParams.dustLimit, bobCommitments.latest.commitmentFormat) == 0.msat) + assert(DustExposure.computeExposure(bobCommitments.latest.remoteCommit.spec, bobCommitments.latest.remoteCommitParams.dustLimit, bobCommitments.latest.commitmentFormat) == 0.msat) val tx = bob.signCommitTx() // A large feerate increase would make these HTLCs overflow Bob's dust exposure, so he force-closes: @@ -2373,8 +2372,8 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with // Bob sends another HTLC to Alice that is not included in the dust exposure at the current feerate. addHtlc(14000.sat.toMilliSatoshi, bob, alice, bob2alice, alice2bob) val bobCommitments = bob.stateData.asInstanceOf[DATA_NORMAL].commitments - assert(DustExposure.computeExposure(bobCommitments.latest.localCommit.spec, bobCommitments.params.localParams.dustLimit, bobCommitments.params.commitmentFormat) == 0.msat) - assert(DustExposure.computeExposure(bobCommitments.latest.remoteCommit.spec, bobCommitments.params.remoteParams.dustLimit, bobCommitments.params.commitmentFormat) == 0.msat) + assert(DustExposure.computeExposure(bobCommitments.latest.localCommit.spec, bobCommitments.latest.localCommitParams.dustLimit, bobCommitments.latest.commitmentFormat) == 0.msat) + assert(DustExposure.computeExposure(bobCommitments.latest.remoteCommit.spec, bobCommitments.latest.remoteCommitParams.dustLimit, bobCommitments.latest.commitmentFormat) == 0.msat) // A large feerate increase would make these HTLCs overflow Bob's dust exposure, so he force-close: val tx = bob.signCommitTx() @@ -2397,20 +2396,20 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with val initialState = alice.stateData.asInstanceOf[DATA_NORMAL] val aliceCommitments = initialState.commitments assert(alice.underlyingActor.nodeParams.onChainFeeConf.feerateToleranceFor(bob.underlyingActor.nodeParams.nodeId).dustTolerance.maxExposure == 25_000.sat) - val higherDustLimit = Seq(aliceCommitments.params.localParams.dustLimit, aliceCommitments.params.remoteParams.dustLimit).max - val lowerDustLimit = Seq(aliceCommitments.params.localParams.dustLimit, aliceCommitments.params.remoteParams.dustLimit).min + val higherDustLimit = Seq(aliceCommitments.latest.localCommitParams.dustLimit, aliceCommitments.latest.remoteCommitParams.dustLimit).max + val lowerDustLimit = Seq(aliceCommitments.latest.localCommitParams.dustLimit, aliceCommitments.latest.remoteCommitParams.dustLimit).min // We have the following dust thresholds at the current feerate - assert(Transactions.offeredHtlcTrimThreshold(higherDustLimit, aliceCommitments.latest.localCommit.spec.copy(commitTxFeerate = DustExposure.feerateForDustExposure(initialFeerate)), aliceCommitments.params.commitmentFormat) == 6989.sat) - assert(Transactions.receivedHtlcTrimThreshold(higherDustLimit, aliceCommitments.latest.localCommit.spec.copy(commitTxFeerate = DustExposure.feerateForDustExposure(initialFeerate)), aliceCommitments.params.commitmentFormat) == 7109.sat) - assert(Transactions.offeredHtlcTrimThreshold(lowerDustLimit, aliceCommitments.latest.localCommit.spec.copy(commitTxFeerate = DustExposure.feerateForDustExposure(initialFeerate)), aliceCommitments.params.commitmentFormat) == 2989.sat) - assert(Transactions.receivedHtlcTrimThreshold(lowerDustLimit, aliceCommitments.latest.localCommit.spec.copy(commitTxFeerate = DustExposure.feerateForDustExposure(initialFeerate)), aliceCommitments.params.commitmentFormat) == 3109.sat) + assert(Transactions.offeredHtlcTrimThreshold(higherDustLimit, aliceCommitments.latest.localCommit.spec.copy(commitTxFeerate = DustExposure.feerateForDustExposure(initialFeerate)), aliceCommitments.latest.commitmentFormat) == 6989.sat) + assert(Transactions.receivedHtlcTrimThreshold(higherDustLimit, aliceCommitments.latest.localCommit.spec.copy(commitTxFeerate = DustExposure.feerateForDustExposure(initialFeerate)), aliceCommitments.latest.commitmentFormat) == 7109.sat) + assert(Transactions.offeredHtlcTrimThreshold(lowerDustLimit, aliceCommitments.latest.localCommit.spec.copy(commitTxFeerate = DustExposure.feerateForDustExposure(initialFeerate)), aliceCommitments.latest.commitmentFormat) == 2989.sat) + assert(Transactions.receivedHtlcTrimThreshold(lowerDustLimit, aliceCommitments.latest.localCommit.spec.copy(commitTxFeerate = DustExposure.feerateForDustExposure(initialFeerate)), aliceCommitments.latest.commitmentFormat) == 3109.sat) // And the following thresholds after the feerate update // NB: we apply the real feerate when sending update_fee, not the one adjusted for dust val updatedFeerate = FeeratePerKw(4000 sat) - assert(Transactions.offeredHtlcTrimThreshold(higherDustLimit, aliceCommitments.latest.localCommit.spec.copy(commitTxFeerate = updatedFeerate), aliceCommitments.params.commitmentFormat) == 7652.sat) - assert(Transactions.receivedHtlcTrimThreshold(higherDustLimit, aliceCommitments.latest.localCommit.spec.copy(commitTxFeerate = updatedFeerate), aliceCommitments.params.commitmentFormat) == 7812.sat) - assert(Transactions.offeredHtlcTrimThreshold(lowerDustLimit, aliceCommitments.latest.localCommit.spec.copy(commitTxFeerate = updatedFeerate), aliceCommitments.params.commitmentFormat) == 3652.sat) - assert(Transactions.receivedHtlcTrimThreshold(lowerDustLimit, aliceCommitments.latest.localCommit.spec.copy(commitTxFeerate = updatedFeerate), aliceCommitments.params.commitmentFormat) == 3812.sat) + assert(Transactions.offeredHtlcTrimThreshold(higherDustLimit, aliceCommitments.latest.localCommit.spec.copy(commitTxFeerate = updatedFeerate), aliceCommitments.latest.commitmentFormat) == 7652.sat) + assert(Transactions.receivedHtlcTrimThreshold(higherDustLimit, aliceCommitments.latest.localCommit.spec.copy(commitTxFeerate = updatedFeerate), aliceCommitments.latest.commitmentFormat) == 7812.sat) + assert(Transactions.offeredHtlcTrimThreshold(lowerDustLimit, aliceCommitments.latest.localCommit.spec.copy(commitTxFeerate = updatedFeerate), aliceCommitments.latest.commitmentFormat) == 3652.sat) + assert(Transactions.receivedHtlcTrimThreshold(lowerDustLimit, aliceCommitments.latest.localCommit.spec.copy(commitTxFeerate = updatedFeerate), aliceCommitments.latest.commitmentFormat) == 3812.sat) // Bob send HTLCs to Alice that are not included in the dust exposure at the current feerate. // He signs them but Alice doesn't answer yet. @@ -2594,11 +2593,11 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with test("recv CMD_CLOSE (with a script that does match our upfront shutdown script)", Tag(ChannelStateTestsTags.UpfrontShutdownScript)) { f => import f._ val sender = TestProbe() - val shutdownScript = alice.stateData.asInstanceOf[DATA_NORMAL].commitments.params.localParams.upfrontShutdownScript_opt.get + val shutdownScript = alice.commitments.localChannelParams.upfrontShutdownScript_opt.get alice ! CMD_CLOSE(sender.ref, Some(shutdownScript), None) sender.expectMsgType[RES_SUCCESS[CMD_CLOSE]] val shutdown = alice2bob.expectMsgType[Shutdown] - assert(shutdown.scriptPubKey == alice.stateData.asInstanceOf[DATA_NORMAL].commitments.params.localParams.upfrontShutdownScript_opt.get) + assert(shutdown.scriptPubKey == alice.commitments.localChannelParams.upfrontShutdownScript_opt.get) awaitCond(alice.stateName == NORMAL) awaitCond(alice.stateData.asInstanceOf[DATA_NORMAL].localShutdown.isDefined) } @@ -2609,7 +2608,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with alice ! CMD_CLOSE(sender.ref, None, None) sender.expectMsgType[RES_SUCCESS[CMD_CLOSE]] val shutdown = alice2bob.expectMsgType[Shutdown] - assert(shutdown.scriptPubKey == alice.stateData.asInstanceOf[DATA_NORMAL].commitments.params.localParams.upfrontShutdownScript_opt.get) + assert(shutdown.scriptPubKey == alice.commitments.localChannelParams.upfrontShutdownScript_opt.get) awaitCond(alice.stateName == NORMAL) awaitCond(alice.stateData.asInstanceOf[DATA_NORMAL].localShutdown.isDefined) } @@ -2720,7 +2719,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with bob2alice.expectMsgType[Warning] // we should fail the connection as per the BOLTs bobPeer.fishForMessage(3 seconds) { - case Peer.Disconnect(nodeId, _) if nodeId == bob.stateData.asInstanceOf[DATA_NORMAL].commitments.params.remoteParams.nodeId => true + case Peer.Disconnect(nodeId, _) if nodeId == bob.commitments.remoteNodeId => true case _ => false } } @@ -2731,7 +2730,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with bob2alice.expectMsgType[Warning] // we should fail the connection as per the BOLTs bobPeer.fishForMessage(3 seconds) { - case Peer.Disconnect(nodeId, _) if nodeId == bob.stateData.asInstanceOf[DATA_NORMAL].commitments.params.remoteParams.nodeId => true + case Peer.Disconnect(nodeId, _) if nodeId == bob.commitments.remoteNodeId => true case _ => false } } @@ -2751,7 +2750,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with bob ! Shutdown(ByteVector32.Zeroes, hex"00112233445566778899") // we should fail the connection as per the BOLTs bobPeer.fishForMessage(3 seconds) { - case Peer.Disconnect(nodeId, _) if nodeId == bob.stateData.asInstanceOf[DATA_NORMAL].commitments.params.remoteParams.nodeId => true + case Peer.Disconnect(nodeId, _) if nodeId == bob.commitments.remoteNodeId => true case _ => false } } @@ -2762,7 +2761,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with // we should fail the connection as per the BOLTs bobPeer.fishForMessage(3 seconds) { - case Peer.Disconnect(nodeId, _) if nodeId == bob.stateData.asInstanceOf[DATA_NORMAL].commitments.params.remoteParams.nodeId => true + case Peer.Disconnect(nodeId, _) if nodeId == bob.commitments.remoteNodeId => true case _ => false } } @@ -2984,7 +2983,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with val event = CurrentFeerates.BitcoinCore(FeeratesPerKw(minimum = FeeratePerKw(250 sat), fastest = FeeratePerKw(10_000 sat), fast = FeeratePerKw(5_000 sat), medium = FeeratePerKw(1000 sat), slow = FeeratePerKw(500 sat))) alice.setBitcoinCoreFeerates(event.feeratesPerKw) alice ! event - alice2bob.expectMsg(UpdateFee(initialState.commitments.channelId, alice.underlyingActor.nodeParams.onChainFeeConf.getCommitmentFeerate(alice.underlyingActor.nodeParams.currentBitcoinCoreFeerates, alice.underlyingActor.remoteNodeId, initialState.commitments.params.commitmentFormat, initialState.commitments.latest.capacity))) + alice2bob.expectMsg(UpdateFee(initialState.commitments.channelId, alice.underlyingActor.nodeParams.onChainFeeConf.getCommitmentFeerate(alice.underlyingActor.nodeParams.currentBitcoinCoreFeerates, alice.underlyingActor.remoteNodeId, initialState.commitments.latest.commitmentFormat, initialState.commitments.latest.capacity))) } test("recv CurrentFeerate (when funder, triggers an UpdateFee, anchor outputs)", Tag(ChannelStateTestsTags.AnchorOutputsZeroFeeHtlcTxs)) { f => diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/f/ShutdownStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/f/ShutdownStateSpec.scala index 733aa8e9ed..b2094f76e4 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/f/ShutdownStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/f/ShutdownStateSpec.scala @@ -668,7 +668,7 @@ class ShutdownStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike wit val event = CurrentFeerates.BitcoinCore(FeeratesPerKw(minimum = FeeratePerKw(250 sat), fastest = FeeratePerKw(10_000 sat), fast = FeeratePerKw(5_000 sat), medium = FeeratePerKw(1000 sat), slow = FeeratePerKw(500 sat))) alice.setBitcoinCoreFeerates(event.feeratesPerKw) alice ! event - alice2bob.expectMsg(UpdateFee(initialState.commitments.channelId, alice.underlyingActor.nodeParams.onChainFeeConf.getCommitmentFeerate(alice.underlyingActor.nodeParams.currentBitcoinCoreFeerates, alice.underlyingActor.remoteNodeId, initialState.commitments.params.commitmentFormat, initialState.commitments.latest.capacity))) + alice2bob.expectMsg(UpdateFee(initialState.commitments.channelId, alice.underlyingActor.nodeParams.onChainFeeConf.getCommitmentFeerate(alice.underlyingActor.nodeParams.currentBitcoinCoreFeerates, alice.underlyingActor.remoteNodeId, initialState.commitments.latest.commitmentFormat, initialState.commitments.latest.capacity))) } test("recv CurrentFeerate (when funder, triggers an UpdateFee, anchor outputs)", Tag(ChannelStateTestsTags.AnchorOutputsZeroFeeHtlcTxs)) { f => diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/g/NegotiatingStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/g/NegotiatingStateSpec.scala index 6ddb12b258..4d33b4001b 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/g/NegotiatingStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/g/NegotiatingStateSpec.scala @@ -65,14 +65,14 @@ class NegotiatingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike alice2bob.forward(bob, aliceShutdown) val bobShutdown = bob2alice.expectMsgType[Shutdown] bob2alice.forward(alice, bobShutdown) - if (alice.stateData.asInstanceOf[ChannelDataWithCommitments].commitments.params.localParams.initFeatures.hasFeature(Features.SimpleClose)) { + if (alice.stateData.asInstanceOf[ChannelDataWithCommitments].commitments.localChannelParams.initFeatures.hasFeature(Features.SimpleClose)) { awaitCond(alice.stateName == NEGOTIATING_SIMPLE) awaitCond(bob.stateName == NEGOTIATING_SIMPLE) } else { awaitCond(alice.stateName == NEGOTIATING) - assert(alice.stateData.asInstanceOf[DATA_NEGOTIATING].commitments.params.localParams.upfrontShutdownScript_opt.forall(_ == aliceShutdown.scriptPubKey)) + assert(alice.stateData.asInstanceOf[DATA_NEGOTIATING].commitments.localChannelParams.upfrontShutdownScript_opt.forall(_ == aliceShutdown.scriptPubKey)) awaitCond(bob.stateName == NEGOTIATING) - assert(bob.stateData.asInstanceOf[DATA_NEGOTIATING].commitments.params.localParams.upfrontShutdownScript_opt.forall(_ == bobShutdown.scriptPubKey)) + assert(bob.stateData.asInstanceOf[DATA_NEGOTIATING].commitments.localChannelParams.upfrontShutdownScript_opt.forall(_ == bobShutdown.scriptPubKey)) } } @@ -85,14 +85,14 @@ class NegotiatingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike bob2alice.forward(alice, bobShutdown) val aliceShutdown = alice2bob.expectMsgType[Shutdown] alice2bob.forward(bob, aliceShutdown) - if (bob.stateData.asInstanceOf[ChannelDataWithCommitments].commitments.params.localParams.initFeatures.hasFeature(Features.SimpleClose)) { + if (bob.stateData.asInstanceOf[ChannelDataWithCommitments].commitments.localChannelParams.initFeatures.hasFeature(Features.SimpleClose)) { awaitCond(alice.stateName == NEGOTIATING_SIMPLE) awaitCond(bob.stateName == NEGOTIATING_SIMPLE) } else { awaitCond(alice.stateName == NEGOTIATING) - assert(alice.stateData.asInstanceOf[DATA_NEGOTIATING].commitments.params.localParams.upfrontShutdownScript_opt.forall(_ == aliceShutdown.scriptPubKey)) + assert(alice.stateData.asInstanceOf[DATA_NEGOTIATING].commitments.localChannelParams.upfrontShutdownScript_opt.forall(_ == aliceShutdown.scriptPubKey)) awaitCond(bob.stateName == NEGOTIATING) - assert(bob.stateData.asInstanceOf[DATA_NEGOTIATING].commitments.params.localParams.upfrontShutdownScript_opt.forall(_ == bobShutdown.scriptPubKey)) + assert(bob.stateData.asInstanceOf[DATA_NEGOTIATING].commitments.localChannelParams.upfrontShutdownScript_opt.forall(_ == bobShutdown.scriptPubKey)) } } @@ -106,7 +106,7 @@ class NegotiatingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike systemA.eventStream.subscribe(aliceListener.ref, classOf[LocalChannelUpdate]) val bobListener = TestProbe() systemB.eventStream.subscribe(bobListener.ref, classOf[LocalChannelUpdate]) - + alice2bob.expectMsgType[AnnouncementSignatures] alice2bob.forward(bob) alice2bob.expectMsgType[ChannelUpdate] @@ -162,11 +162,11 @@ class NegotiatingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike assert(alice.stateData.asInstanceOf[DATA_NEGOTIATING].closingTxProposed.length == 1) assert(alice.stateData.asInstanceOf[DATA_NEGOTIATING].closingTxProposed.last.length == 1) assert(alice.stateData.asInstanceOf[DATA_NEGOTIATING].bestUnpublishedClosingTx_opt.isEmpty) - if (alice.stateData.asInstanceOf[DATA_NEGOTIATING].commitments.params.channelFeatures.hasFeature(Features.UpfrontShutdownScript)) { + if (alice.stateData.asInstanceOf[DATA_NEGOTIATING].commitments.channelParams.channelFeatures.hasFeature(Features.UpfrontShutdownScript)) { // check that the closing tx uses Alice and Bob's default closing scripts val closingTx = alice.stateData.asInstanceOf[DATA_NEGOTIATING].closingTxProposed.last.head.unsignedTx.tx - val expectedLocalScript = alice.stateData.asInstanceOf[DATA_NEGOTIATING].commitments.params.localParams.upfrontShutdownScript_opt.get - val expectedRemoteScript = bob.stateData.asInstanceOf[DATA_NEGOTIATING].commitments.params.localParams.upfrontShutdownScript_opt.get + val expectedLocalScript = alice.stateData.asInstanceOf[DATA_NEGOTIATING].commitments.localChannelParams.upfrontShutdownScript_opt.get + val expectedRemoteScript = bob.stateData.asInstanceOf[DATA_NEGOTIATING].commitments.localChannelParams.upfrontShutdownScript_opt.get assert(closingTx.txOut.map(_.publicKeyScript).toSet == Set(expectedLocalScript, expectedRemoteScript)) } alice2bob.forward(bob) @@ -456,7 +456,7 @@ class NegotiatingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike test("recv ClosingSigned (fee higher than commit tx fee)", Tag(ChannelStateTestsTags.AnchorOutputsZeroFeeHtlcTxs)) { f => import f._ val commitment = alice.stateData.asInstanceOf[DATA_NORMAL].commitments.latest - val commitFee = Transactions.commitTxFeeMsat(commitment.localParams.dustLimit, commitment.localCommit.spec, ZeroFeeHtlcTxAnchorOutputsCommitmentFormat) + val commitFee = Transactions.commitTxFeeMsat(commitment.localCommitParams.dustLimit, commitment.localCommit.spec, ZeroFeeHtlcTxAnchorOutputsCommitmentFormat) aliceClose(f) val aliceCloseSig = alice2bob.expectMsgType[ClosingSigned] assert(aliceCloseSig.feeSatoshis > commitFee.truncateToSatoshi) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/h/ClosingStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/h/ClosingStateSpec.scala index bc278337cb..7e9745a9c5 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/h/ClosingStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/h/ClosingStateSpec.scala @@ -16,7 +16,7 @@ package fr.acinq.eclair.channel.states.h -import akka.actor.typed.scaladsl.adapter.{ClassicActorRefOps, actorRefAdapter} +import akka.actor.typed.scaladsl.adapter.actorRefAdapter import akka.testkit.{TestFSMRef, TestProbe} import fr.acinq.bitcoin.ScriptFlags import fr.acinq.bitcoin.scalacompat.Crypto.PrivateKey @@ -71,14 +71,10 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with if (unconfirmedFundingTx) { within(30 seconds) { - val channelConfig = ChannelConfig.standard - val channelFlags = ChannelFlags(announceChannel = false) - val (aliceParams, bobParams, channelType) = computeFeatures(setup, test.tags, channelFlags) - val aliceInit = Init(aliceParams.initFeatures) - val bobInit = Init(bobParams.initFeatures) - alice ! INPUT_INIT_CHANNEL_INITIATOR(ByteVector32.Zeroes, TestConstants.fundingSatoshis, dualFunded = false, TestConstants.feeratePerKw, TestConstants.feeratePerKw, fundingTxFeeBudget_opt = None, Some(TestConstants.initiatorPushAmount), requireConfirmedInputs = false, requestFunding_opt = None, aliceParams, alice2bob.ref, bobInit, channelFlags, channelConfig, channelType, replyTo = aliceOpenReplyTo.ref.toTyped) + val channelParams = computeChannelParams(setup, test.tags) + alice ! channelParams.initChannelAlice(TestConstants.fundingSatoshis, pushAmount_opt = Some(TestConstants.initiatorPushAmount)) alice2blockchain.expectMsgType[SetChannelId] - bob ! INPUT_INIT_CHANNEL_NON_INITIATOR(ByteVector32.Zeroes, None, dualFunded = false, None, requireConfirmedInputs = false, bobParams, bob2alice.ref, aliceInit, channelConfig, channelType) + bob ! channelParams.initChannelBob() bob2blockchain.expectMsgType[SetChannelId] alice2bob.expectMsgType[OpenChannel] alice2bob.forward(bob) @@ -298,7 +294,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with def testMutualCloseBeforeConverge(f: FixtureParam, channelFeatures: ChannelFeatures): Unit = { import f._ val sender = TestProbe() - assert(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.params.channelFeatures == channelFeatures) + assert(alice.commitments.channelParams.channelFeatures == channelFeatures) bob.setBitcoinCoreFeerates(FeeratesPerKw.single(FeeratePerKw(2500 sat)).copy(minimum = FeeratePerKw(250 sat), slow = FeeratePerKw(250 sat))) // alice initiates a closing with a low fee alice ! CMD_CLOSE(sender.ref, None, Some(ClosingFeerates(FeeratePerKw(500 sat), FeeratePerKw(250 sat), FeeratePerKw(1000 sat)))) @@ -399,7 +395,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with // Bob claims the htlc output from Alice's commit tx using its preimage. bob ! WatchFundingSpentTriggered(lcp.commitTx) - initialState.commitments.params.commitmentFormat match { + initialState.commitments.latest.commitmentFormat match { case DefaultCommitmentFormat => () case _: AnchorOutputsCommitmentFormat | _: SimpleTaprootChannelCommitmentFormat => bob2blockchain.expectReplaceableTxPublished[ClaimRemoteAnchorTx] @@ -508,7 +504,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with // Alice prepares Claim-HTLC-timeout transactions for each HTLC. alice ! WatchFundingSpentTriggered(rcp.commitTx) - val (anchorTx_opt, mainTx_opt) = bobStateWithHtlc.commitments.params.commitmentFormat match { + val (anchorTx_opt, mainTx_opt) = bobStateWithHtlc.commitments.latest.commitmentFormat match { case DefaultCommitmentFormat => (None, None) case _: AnchorOutputsCommitmentFormat | _: SimpleTaprootChannelCommitmentFormat => val anchorTx = alice2blockchain.expectReplaceableTxPublished[ClaimRemoteAnchorTx] @@ -588,7 +584,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with assert(closingTxs.htlcTxs.isEmpty) // Bob receives the preimage for the first two HTLCs. bob ! CMD_FULFILL_HTLC(htlc1.id, preimage, None, None) - val htlcSuccessTxs = aliceStateWithoutHtlcs.commitments.params.commitmentFormat match { + val htlcSuccessTxs = aliceStateWithoutHtlcs.commitments.latest.commitmentFormat match { case DefaultCommitmentFormat => (0 until 2).map(_ => bob2blockchain.expectFinalTxPublished("htlc-success").tx) case _: AnchorOutputsCommitmentFormat | _: SimpleTaprootChannelCommitmentFormat => val htlcSuccess = (0 until 2).map(_ => bob2blockchain.expectReplaceableTxPublished[HtlcSuccessTx]) @@ -600,7 +596,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with // Alice prepares Claim-HTLC-timeout transactions for each HTLC. alice ! WatchFundingSpentTriggered(rcp.commitTx) - val (anchorTx_opt, mainTx_opt) = aliceStateWithoutHtlcs.commitments.params.commitmentFormat match { + val (anchorTx_opt, mainTx_opt) = aliceStateWithoutHtlcs.commitments.latest.commitmentFormat match { case DefaultCommitmentFormat => (None, None) case _: AnchorOutputsCommitmentFormat | _: SimpleTaprootChannelCommitmentFormat => val anchorTx = alice2blockchain.expectReplaceableTxPublished[ClaimRemoteAnchorTx] @@ -672,7 +668,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with def testLocalCommitTxConfirmed(f: FixtureParam, channelFeatures: ChannelFeatures): Unit = { import f._ - assert(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.params.channelFeatures == channelFeatures) + assert(alice.commitments.channelParams.channelFeatures == channelFeatures) val listener = TestProbe() systemA.eventStream.subscribe(listener.ref, classOf[LocalCommitConfirmed]) @@ -681,7 +677,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with // alice sends an htlc to bob val (_, htlca1) = addHtlc(50_000_000 msat, alice, bob, alice2bob, bob2alice) // alice sends an htlc below dust to bob - val amountBelowDust = alice.stateData.asInstanceOf[DATA_NORMAL].commitments.params.localParams.dustLimit - 100.msat + val amountBelowDust = alice.commitments.latest.localCommitParams.dustLimit - 100.msat val (_, htlca2) = addHtlc(amountBelowDust, alice, bob, alice2bob, bob2alice) crossSign(alice, bob, alice2bob, bob2alice) val (closingState, closingTxs) = localClose(alice, alice2blockchain, htlcTimeoutCount = 1) @@ -695,7 +691,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with assert(closingState.htlcDelayedOutputs.isEmpty) alice ! WatchTxConfirmedTriggered(BlockHeight(42), 0, closingState.commitTx) assert(txListener.expectMsgType[TransactionConfirmed].tx == closingState.commitTx) - assert(listener.expectMsgType[LocalCommitConfirmed].refundAtBlock == BlockHeight(42) + bob.stateData.asInstanceOf[DATA_NORMAL].commitments.params.localParams.toSelfDelay.toInt) + assert(listener.expectMsgType[LocalCommitConfirmed].refundAtBlock == BlockHeight(42) + alice.commitments.latest.localCommitParams.toSelfDelay.toInt) assert(listener.expectMsgType[PaymentSettlingOnChain].paymentHash == htlca1.paymentHash) // htlcs below dust will never reach the chain, once the commit tx is confirmed we can consider them failed inside(alice2relayer.expectMsgType[RES_ADD_SETTLED[Origin, HtlcResult.OnChainFail]]) { settled => @@ -743,7 +739,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with val htlca2 = addHtlc(cmd2, alice, bob, alice2bob, bob2alice) val (_, cmd3) = makeCmdAdd(30_000_000 msat, bob.nodeParams.nodeId, alice.nodeParams.currentBlockHeight, ra1) val htlca3 = addHtlc(cmd3, alice, bob, alice2bob, bob2alice) - val amountBelowDust = alice.stateData.asInstanceOf[DATA_NORMAL].commitments.params.localParams.dustLimit - 100.msat + val amountBelowDust = alice.commitments.latest.localCommitParams.dustLimit - 100.msat val (_, dustCmd) = makeCmdAdd(amountBelowDust, bob.nodeParams.nodeId, alice.nodeParams.currentBlockHeight, ra1) val dust = addHtlc(dustCmd, alice, bob, alice2bob, bob2alice) val (_, cmd4) = makeCmdAdd(20_000_000 msat, bob.nodeParams.nodeId, alice.nodeParams.currentBlockHeight + 1, ra1) @@ -1416,7 +1412,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with test("recv WatchTxConfirmedTriggered (remote commit, option_static_remotekey)", Tag(ChannelStateTestsTags.StaticRemoteKey), Tag(ChannelStateTestsTags.SimpleClose)) { f => import f._ mutualClose(alice, bob, alice2bob, bob2alice, alice2blockchain, bob2blockchain) - assert(alice.stateData.asInstanceOf[DATA_NEGOTIATING_SIMPLE].commitments.params.channelFeatures == ChannelFeatures(Features.StaticRemoteKey)) + assert(alice.commitments.channelParams.channelFeatures == ChannelFeatures(Features.StaticRemoteKey)) // bob publishes his last current commit tx, the one it had when entering NEGOTIATING state val bobCommitTx = bobCommitTxs.last assert(bobCommitTx.txOut.size == 2) // two main outputs @@ -1434,7 +1430,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with import f._ mutualClose(alice, bob, alice2bob, bob2alice, alice2blockchain, bob2blockchain) val initialState = alice.stateData.asInstanceOf[DATA_CLOSING] - assert(initialState.commitments.params.channelFeatures == ChannelFeatures(Features.StaticRemoteKey, Features.AnchorOutputsZeroFeeHtlcTx)) + assert(initialState.commitments.channelParams.channelFeatures == ChannelFeatures(Features.StaticRemoteKey, Features.AnchorOutputsZeroFeeHtlcTx)) // bob publishes his last current commit tx, the one it had when entering NEGOTIATING state val bobCommitTx = bobCommitTxs.last assert(bobCommitTx.txOut.size == 4) // two main outputs + two anchors @@ -1453,7 +1449,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with def testRemoteCommitTxWithHtlcsConfirmed(f: FixtureParam, channelFeatures: ChannelFeatures): Unit = { import f._ - assert(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.params.channelFeatures == channelFeatures) + assert(alice.commitments.channelParams.channelFeatures == channelFeatures) // alice sends a first htlc to bob val (ra1, htlca1) = addHtlc(15_000_000 msat, alice, bob, alice2bob, bob2alice) @@ -1595,7 +1591,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with private def testNextRemoteCommitTxConfirmed(f: FixtureParam, channelFeatures: ChannelFeatures): (Transaction, PublishedForceCloseTxs, Set[UpdateAddHtlc]) = { import f._ - assert(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.params.channelFeatures == channelFeatures) + assert(alice.commitments.channelParams.channelFeatures == channelFeatures) // alice sends a first htlc to bob val (ra1, htlca1) = addHtlc(15_000_000 msat, alice, bob, alice2bob, bob2alice) @@ -1776,7 +1772,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with private def testFutureRemoteCommitTxConfirmed(f: FixtureParam, channelFeatures: ChannelFeatures): Transaction = { import f._ val oldStateData = alice.stateData - assert(oldStateData.asInstanceOf[DATA_NORMAL].commitments.params.channelFeatures == channelFeatures) + assert(oldStateData.asInstanceOf[DATA_NORMAL].commitments.channelParams.channelFeatures == channelFeatures) // This HTLC will be fulfilled. val (ra1, htlca1) = addHtlc(25_000_000 msat, alice, bob, alice2bob, bob2alice) // These 2 HTLCs should timeout on-chain, but since alice lost data, she won't be able to claim them. @@ -1947,7 +1943,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with import f._ val revokedCloseFixture = prepareRevokedClose(f, channelFeatures) - assert(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.params.channelFeatures == channelFeatures) + assert(alice.commitments.channelParams.channelFeatures == channelFeatures) // bob publishes one of his revoked txs val bobRevokedTx = revokedCloseFixture.bobRevokedTxs(1).commitTx @@ -2098,7 +2094,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with def testRevokedHtlcTxConfirmed(f: FixtureParam, channelFeatures: ChannelFeatures): Unit = { import f._ val revokedCloseFixture = prepareRevokedClose(f, channelFeatures) - assert(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.params.channelFeatures == channelFeatures) + assert(alice.commitments.channelParams.channelFeatures == channelFeatures) // bob publishes one of his revoked txs val bobRevokedCommit = revokedCloseFixture.bobRevokedTxs(2) @@ -2198,7 +2194,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with val bobRevokedCommit = revokedCloseFixture.bobRevokedTxs(2) alice ! WatchFundingSpentTriggered(bobRevokedCommit.commitTx) awaitCond(alice.stateData.isInstanceOf[DATA_CLOSING]) - assert(alice.stateData.asInstanceOf[DATA_CLOSING].commitments.params.commitmentFormat == ZeroFeeHtlcTxAnchorOutputsCommitmentFormat) + assert(alice.commitments.latest.commitmentFormat == ZeroFeeHtlcTxAnchorOutputsCommitmentFormat) awaitCond(alice.stateData.asInstanceOf[DATA_CLOSING].revokedCommitPublished.size == 1) val rvk = alice.stateData.asInstanceOf[DATA_CLOSING].revokedCommitPublished.head assert(rvk.commitTx == bobRevokedCommit.commitTx) @@ -2364,7 +2360,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with private def testRevokedTxConfirmed(f: FixtureParam, channelFeatures: ChannelFeatures): Unit = { import f._ - assert(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.params.channelFeatures == channelFeatures) + assert(alice.commitments.channelParams.channelFeatures == channelFeatures) val initOutputCount = channelFeatures.commitmentFormat match { case _: AnchorOutputsCommitmentFormat | _: SimpleTaprootChannelCommitmentFormat => 4 case DefaultCommitmentFormat => 2 diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/db/ChannelsDbSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/db/ChannelsDbSpec.scala index b64bc10768..7454687e5a 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/db/ChannelsDbSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/db/ChannelsDbSpec.scala @@ -59,7 +59,7 @@ class ChannelsDbSpec extends AnyFunSuite { val db = dbs.channels val channel1 = ChannelCodecsSpec.normal - val channel2a = ChannelCodecsSpec.normal.modify(_.commitments.params.channelId).setTo(randomBytes32()) + val channel2a = ChannelCodecsSpec.normal.modify(_.commitments.channelParams.channelId).setTo(randomBytes32()) val channel2b = channel2a.modify(_.aliases.remoteAlias_opt).setTo(Some(Alias(randomLong()))) val commitNumber = 42 @@ -107,7 +107,7 @@ class ChannelsDbSpec extends AnyFunSuite { val db = dbs.channels val channel1 = ChannelCodecsSpec.normal - val channel2 = ChannelCodecsSpec.normal.modify(_.commitments.params.channelId).setTo(randomBytes32()) + val channel2 = ChannelCodecsSpec.normal.modify(_.commitments.channelParams.channelId).setTo(randomBytes32()) db.addOrUpdateChannel(channel1) db.addOrUpdateChannel(channel2) @@ -169,7 +169,7 @@ class ChannelsDbSpec extends AnyFunSuite { val channelIds = (0 until 10).map(_ => randomBytes32()).toList val futures = for (i <- 0 until 10000) yield { val channelId = channelIds(i % channelIds.size) - Future(db.addOrUpdateChannel(channel.modify(_.commitments.params.channelId).setTo(channelId))) + Future(db.addOrUpdateChannel(channel.modify(_.commitments.channelParams.channelId).setTo(channelId))) Future(db.updateChannelMeta(channelId, ChannelEvent.EventType.PaymentSent)) } val res = Future.sequence(futures) @@ -182,7 +182,7 @@ class ChannelsDbSpec extends AnyFunSuite { val db = dbs.channels val channel1 = ChannelCodecsSpec.normal - val channel2 = channel1.modify(_.commitments.params.channelId).setTo(randomBytes32()) + val channel2 = channel1.modify(_.commitments.channelParams.channelId).setTo(randomBytes32()) // first we add channels db.addOrUpdateChannel(channel1) @@ -431,8 +431,8 @@ object ChannelsDbSpec { val channelId = randomBytes32() val remoteNodeId = randomKey().publicKey val channel = ChannelCodecsSpec.normal - .modify(_.commitments.params.channelId).setTo(channelId) - .modify(_.commitments.params.remoteParams.nodeId).setTo(remoteNodeId) + .modify(_.commitments.channelParams.channelId).setTo(channelId) + .modify(_.commitments.channelParams.remoteParams.nodeId).setTo(remoteNodeId) val data = channelDataCodec.encode(channel).require.bytes TestCase( channelId = channelId, diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/db/RevokedHtlcInfoCleanerSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/db/RevokedHtlcInfoCleanerSpec.scala index 2200e97534..fd3cbaa4f0 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/db/RevokedHtlcInfoCleanerSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/db/RevokedHtlcInfoCleanerSpec.scala @@ -34,7 +34,7 @@ class RevokedHtlcInfoCleanerSpec extends ScalaTestWithActorTestKit(ConfigFactory val channelsDb = TestSqliteDatabases().channels val channelId = randomBytes32() - channelsDb.addOrUpdateChannel(ChannelCodecsSpec.normal.modify(_.commitments.params.channelId).setTo(channelId)) + channelsDb.addOrUpdateChannel(ChannelCodecsSpec.normal.modify(_.commitments.channelParams.channelId).setTo(channelId)) channelsDb.addHtlcInfo(channelId, 17, randomBytes32(), CltvExpiry(561)) channelsDb.addHtlcInfo(channelId, 19, randomBytes32(), CltvExpiry(1105)) channelsDb.addHtlcInfo(channelId, 23, randomBytes32(), CltvExpiry(1729)) @@ -57,7 +57,7 @@ class RevokedHtlcInfoCleanerSpec extends ScalaTestWithActorTestKit(ConfigFactory val channelsDb = TestSqliteDatabases().channels val channelId = randomBytes32() - channelsDb.addOrUpdateChannel(ChannelCodecsSpec.normal.modify(_.commitments.params.channelId).setTo(channelId)) + channelsDb.addOrUpdateChannel(ChannelCodecsSpec.normal.modify(_.commitments.channelParams.channelId).setTo(channelId)) channelsDb.addHtlcInfo(channelId, 1, randomBytes32(), CltvExpiry(561)) channelsDb.addHtlcInfo(channelId, 2, randomBytes32(), CltvExpiry(1105)) channelsDb.addHtlcInfo(channelId, 2, randomBytes32(), CltvExpiry(1105)) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/integration/ChannelIntegrationSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/integration/ChannelIntegrationSpec.scala index efd17ab097..39aed10d17 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/integration/ChannelIntegrationSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/integration/ChannelIntegrationSpec.scala @@ -147,11 +147,11 @@ abstract class ChannelIntegrationSpec extends IntegrationSpec { // now that we have the channel id, we retrieve channels default final addresses sender.send(nodes("C").register, Register.Forward(sender.ref.toTyped[Any], htlc.channelId, CMD_GET_CHANNEL_DATA(ActorRef.noSender))) val dataC = sender.expectMsgType[RES_GET_CHANNEL_DATA[DATA_NORMAL]].data - assert(dataC.commitments.params.commitmentFormat == commitmentFormat) + assert(dataC.commitments.latest.commitmentFormat == commitmentFormat) val Right(finalAddressC) = addressFromPublicKeyScript(Block.RegtestGenesisBlock.hash, nodes("C").wallet.getReceivePublicKeyScript(renew = false)) sender.send(nodes("F").register, Register.Forward(sender.ref.toTyped[Any], htlc.channelId, CMD_GET_CHANNEL_DATA(ActorRef.noSender))) val dataF = sender.expectMsgType[RES_GET_CHANNEL_DATA[DATA_NORMAL]].data - assert(dataF.commitments.params.commitmentFormat == commitmentFormat) + assert(dataF.commitments.latest.commitmentFormat == commitmentFormat) val Right(finalAddressF) = addressFromPublicKeyScript(Block.RegtestGenesisBlock.hash, nodes("F").wallet.getReceivePublicKeyScript(renew = false)) ForceCloseFixture(sender, paymentSender, stateListenerC, stateListenerF, paymentId, htlc, preimage, minerAddress, finalAddressC, finalAddressF) } @@ -400,9 +400,9 @@ abstract class ChannelIntegrationSpec extends IntegrationSpec { forwardHandlerC.forward(buffer.ref) val commitmentsF = sigListener.expectMsgType[ChannelSignatureReceived].commitments sigListener.expectNoMessage(1 second) - assert(commitmentsF.params.commitmentFormat == commitmentFormat) + assert(commitmentsF.latest.commitmentFormat == commitmentFormat) // we prepare the revoked transactions F will publish - val channelKeysF = nodes("F").nodeParams.channelKeyManager.channelKeys(commitmentsF.params.channelConfig, commitmentsF.params.localParams.fundingKeyPath) + val channelKeysF = nodes("F").nodeParams.channelKeyManager.channelKeys(commitmentsF.channelParams.channelConfig, commitmentsF.localChannelParams.fundingKeyPath) val commitmentKeysF = commitmentsF.latest.localKeys(channelKeysF) val revokedCommitTx = commitmentsF.latest.fullySignedLocalCommitTx(channelKeysF) // in this commitment, both parties should have a main output, there are four pending htlcs and anchor outputs if applicable @@ -556,7 +556,7 @@ abstract class AnchorChannelIntegrationSpec extends ChannelIntegrationSpec { val stateEvent = eventListener.expectMsgType[ChannelStateChanged](max = 60 seconds) if (stateEvent.currentState == NORMAL) { assert(stateEvent.commitments_opt.nonEmpty) - assert(stateEvent.commitments_opt.get.params.commitmentFormat == expectedCommitmentFormat) + assert(stateEvent.commitments_opt.get.latest.commitmentFormat == expectedCommitmentFormat) count = count + 1 } } @@ -577,7 +577,7 @@ abstract class AnchorChannelIntegrationSpec extends ChannelIntegrationSpec { sender.send(nodes("F").register, Register.Forward(sender.ref.toTyped[Any], channelId, CMD_GET_CHANNEL_DATA(ActorRef.noSender))) val initialStateDataF = sender.expectMsgType[RES_GET_CHANNEL_DATA[DATA_NORMAL]].data - assert(initialStateDataF.commitments.params.commitmentFormat == expectedCommitmentFormat) + assert(initialStateDataF.commitments.latest.commitmentFormat == expectedCommitmentFormat) val initialCommitmentIndex = initialStateDataF.commitments.localCommitIndex val toRemoteAddress = { @@ -679,7 +679,7 @@ abstract class AnchorChannelIntegrationSpec extends ChannelIntegrationSpec { class AnchorOutputChannelIntegrationSpec extends AnchorChannelIntegrationSpec { - override val commitmentFormat = Transactions.UnsafeLegacyAnchorOutputsCommitmentFormat + override val commitmentFormat: AnchorOutputsCommitmentFormat = Transactions.UnsafeLegacyAnchorOutputsCommitmentFormat test("start eclair nodes") { instantiateEclairNode("A", ConfigFactory.parseMap(Map("eclair.node-alias" -> "A", "eclair.channel.expiry-delta-blocks" -> 40, "eclair.channel.fulfill-safety-before-timeout-blocks" -> 12, "eclair.server.port" -> 29750, "eclair.api.port" -> 28093).asJava).withFallback(withStaticRemoteKey).withFallback(commonConfig)) @@ -719,7 +719,7 @@ class AnchorOutputChannelIntegrationSpec extends AnchorChannelIntegrationSpec { class AnchorOutputZeroFeeHtlcTxsChannelIntegrationSpec extends AnchorChannelIntegrationSpec { - override val commitmentFormat = Transactions.ZeroFeeHtlcTxAnchorOutputsCommitmentFormat + override val commitmentFormat: AnchorOutputsCommitmentFormat = Transactions.ZeroFeeHtlcTxAnchorOutputsCommitmentFormat test("start eclair nodes") { instantiateEclairNode("A", ConfigFactory.parseMap(Map("eclair.node-alias" -> "A", "eclair.channel.expiry-delta-blocks" -> 40, "eclair.channel.fulfill-safety-before-timeout-blocks" -> 12, "eclair.server.port" -> 29760, "eclair.api.port" -> 28096).asJava).withFallback(withStaticRemoteKey).withFallback(commonConfig)) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/integration/basic/zeroconf/ZeroConfActivationSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/integration/basic/zeroconf/ZeroConfActivationSpec.scala index 00041387f8..c626cc5a4a 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/integration/basic/zeroconf/ZeroConfActivationSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/integration/basic/zeroconf/ZeroConfActivationSpec.scala @@ -61,8 +61,8 @@ class ZeroConfActivationSpec extends FixtureSpec with IntegrationPatience { val channelId = createChannel(f) eventually { - assert(!getChannelData(alice, channelId).asInstanceOf[ChannelDataWithCommitments].commitments.params.channelFeatures.hasFeature(ZeroConf)) - assert(!getChannelData(bob, channelId).asInstanceOf[ChannelDataWithCommitments].commitments.params.channelFeatures.hasFeature(ZeroConf)) + assert(!getChannelData(alice, channelId).asInstanceOf[ChannelDataWithCommitments].commitments.channelParams.channelFeatures.hasFeature(ZeroConf)) + assert(!getChannelData(bob, channelId).asInstanceOf[ChannelDataWithCommitments].commitments.channelParams.channelFeatures.hasFeature(ZeroConf)) } } @@ -90,8 +90,8 @@ class ZeroConfActivationSpec extends FixtureSpec with IntegrationPatience { val channelId = createChannel(f, channelType_opt = Some(channelType)) eventually { - assert(getChannelData(alice, channelId).asInstanceOf[DATA_NORMAL].commitments.params.channelFeatures.hasFeature(ZeroConf)) - assert(getChannelData(bob, channelId).asInstanceOf[DATA_NORMAL].commitments.params.channelFeatures.hasFeature(ZeroConf)) + assert(getChannelData(alice, channelId).asInstanceOf[DATA_NORMAL].commitments.channelParams.channelFeatures.hasFeature(ZeroConf)) + assert(getChannelData(bob, channelId).asInstanceOf[DATA_NORMAL].commitments.channelParams.channelFeatures.hasFeature(ZeroConf)) } } @@ -123,8 +123,8 @@ class ZeroConfActivationSpec extends FixtureSpec with IntegrationPatience { val channelId = createChannel(f, channelType_opt = Some(channelType)) eventually { - assert(getChannelData(alice, channelId).asInstanceOf[DATA_NORMAL].commitments.params.channelFeatures.hasFeature(ZeroConf)) - assert(getChannelData(bob, channelId).asInstanceOf[DATA_NORMAL].commitments.params.channelFeatures.hasFeature(ZeroConf)) + assert(getChannelData(alice, channelId).asInstanceOf[DATA_NORMAL].commitments.channelParams.channelFeatures.hasFeature(ZeroConf)) + assert(getChannelData(bob, channelId).asInstanceOf[DATA_NORMAL].commitments.channelParams.channelFeatures.hasFeature(ZeroConf)) } } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/integration/basic/zeroconf/ZeroConfAliasIntegrationSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/integration/basic/zeroconf/ZeroConfAliasIntegrationSpec.scala index 7fd3bdc948..fd1b540cbf 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/integration/basic/zeroconf/ZeroConfAliasIntegrationSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/integration/basic/zeroconf/ZeroConfAliasIntegrationSpec.scala @@ -122,9 +122,9 @@ class ZeroConfAliasIntegrationSpec extends FixtureSpec with IntegrationPatience val (_, channelId_bc) = createChannels(f, confirm) eventually { - assert(getChannelData(bob, channelId_bc).asInstanceOf[DATA_NORMAL].commitments.params.channelFeatures.features.contains(ZeroConf) == bcZeroConf) - assert(getChannelData(bob, channelId_bc).asInstanceOf[DATA_NORMAL].commitments.params.channelFeatures.features.contains(ScidAlias) == bcScidAlias) - assert(getChannelData(bob, channelId_bc).asInstanceOf[DATA_NORMAL].commitments.params.channelFlags.announceChannel == bcPublic) + assert(getChannelData(bob, channelId_bc).asInstanceOf[DATA_NORMAL].commitments.channelParams.channelFeatures.features.contains(ZeroConf) == bcZeroConf) + assert(getChannelData(bob, channelId_bc).asInstanceOf[DATA_NORMAL].commitments.channelParams.channelFeatures.features.contains(ScidAlias) == bcScidAlias) + assert(getChannelData(bob, channelId_bc).asInstanceOf[DATA_NORMAL].commitments.channelParams.channelFlags.announceChannel == bcPublic) if (confirm) { assert(getChannelData(bob, channelId_bc).asInstanceOf[DATA_NORMAL].commitments.latest.localFundingStatus.isInstanceOf[LocalFundingStatus.ConfirmedFundingTx]) } else { @@ -261,8 +261,8 @@ class ZeroConfAliasIntegrationSpec extends FixtureSpec with IntegrationPatience val (_, channelId_bc) = createChannels(f, confirm = false) eventually { - assert(getChannelData(bob, channelId_bc).asInstanceOf[DATA_NORMAL].commitments.params.channelFeatures.features.contains(ZeroConf)) - assert(getChannelData(bob, channelId_bc).asInstanceOf[DATA_NORMAL].commitments.params.channelFeatures.features.contains(ScidAlias)) + assert(getChannelData(bob, channelId_bc).asInstanceOf[DATA_NORMAL].commitments.channelParams.channelFeatures.features.contains(ZeroConf)) + assert(getChannelData(bob, channelId_bc).asInstanceOf[DATA_NORMAL].commitments.channelParams.channelFeatures.features.contains(ScidAlias)) assert(getChannelData(bob, channelId_bc).asInstanceOf[DATA_NORMAL].commitments.latest.shortChannelId_opt.isEmpty) assert(getRouterData(bob).privateChannels.values.exists(_.nodeId2 == carol.nodeParams.nodeId)) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/io/OpenChannelInterceptorSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/io/OpenChannelInterceptorSpec.scala index 9b32f48dcb..c1b644f42a 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/io/OpenChannelInterceptorSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/io/OpenChannelInterceptorSpec.scala @@ -81,8 +81,9 @@ class OpenChannelInterceptorSpec extends ScalaTestWithActorTestKit(ConfigFactory case class FixtureParam(openChannelInterceptor: ActorRef[OpenChannelInterceptor.Command], peer: TestProbe[Any], pluginInterceptor: TestProbe[InterceptOpenChannelCommand], pendingChannelsRateLimiter: TestProbe[PendingChannelsRateLimiter.Command], peerConnection: TestProbe[Any], eventListener: TestProbe[ChannelAborted], wallet: DummyOnChainWallet) private def commitments(isOpener: Boolean = false): Commitments = { - val commitments = CommitmentsSpec.makeCommitments(500_000 msat, 400_000 msat, TestConstants.Alice.nodeParams.nodeId, remoteNodeId, announcement_opt = None) - commitments.copy(params = commitments.params.copy(localParams = commitments.params.localParams.copy(isChannelOpener = isOpener, paysCommitTxFees = isOpener))) + CommitmentsSpec.makeCommitments(500_000 msat, 400_000 msat, TestConstants.Alice.nodeParams.nodeId, remoteNodeId, announcement_opt = None) + .modify(_.channelParams.localParams.isChannelOpener).setTo(isOpener) + .modify(_.channelParams.localParams.paysCommitTxFees).setTo(isOpener) } test("reject channel open if timeout waiting for plugin to respond") { f => 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 4170c94e2b..df207e6924 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 @@ -35,7 +35,6 @@ import fr.acinq.eclair.io.Peer._ import fr.acinq.eclair.message.OnionMessages.{Recipient, buildMessage} import fr.acinq.eclair.testutils.FixtureSpec import fr.acinq.eclair.wire.internal.channel.ChannelCodecsSpec -import fr.acinq.eclair.wire.internal.channel.ChannelCodecsSpec.localParams import fr.acinq.eclair.wire.protocol import fr.acinq.eclair.wire.protocol._ import org.scalatest.Inside.inside @@ -589,8 +588,8 @@ class PeerSpec extends FixtureSpec { val init = channel.expectMsgType[INPUT_INIT_CHANNEL_INITIATOR] assert(init.channelType == ChannelTypes.StaticRemoteKey()) assert(!init.dualFunded) - assert(init.localParams.walletStaticPaymentBasepoint.isDefined) - assert(init.localParams.upfrontShutdownScript_opt.isEmpty) + assert(init.localChannelParams.walletStaticPaymentBasepoint.isDefined) + assert(init.localChannelParams.upfrontShutdownScript_opt.isEmpty) } test("compute max-htlc-value-in-flight based on funding amount", Tag("max-htlc-value-in-flight-percent"), Tag(ChannelStateTestsTags.AnchorOutputsZeroFeeHtlcTxs)) { f => @@ -604,25 +603,25 @@ class PeerSpec extends FixtureSpec { { probe.send(peer, Peer.OpenChannel(remoteNodeId, 200_000 sat, None, None, None, None, None, None, None)) val init = channel.expectMsgType[INPUT_INIT_CHANNEL_INITIATOR] - assert(init.localParams.maxHtlcValueInFlightMsat == UInt64(50_000_000)) // max-htlc-value-in-flight-percent + assert(init.proposedCommitParams.localMaxHtlcValueInFlight == UInt64(50_000_000)) // max-htlc-value-in-flight-percent } { probe.send(peer, Peer.OpenChannel(remoteNodeId, 500_000 sat, None, None, None, None, None, None, None)) val init = channel.expectMsgType[INPUT_INIT_CHANNEL_INITIATOR] - assert(init.localParams.maxHtlcValueInFlightMsat == UInt64(100_000_000)) // max-htlc-value-in-flight-msat + assert(init.proposedCommitParams.localMaxHtlcValueInFlight == UInt64(100_000_000)) // max-htlc-value-in-flight-msat } { val open = createOpenChannelMessage().copy(fundingSatoshis = 200_000 sat) peerConnection.send(peer, open) val init = channel.expectMsgType[INPUT_INIT_CHANNEL_NON_INITIATOR] - assert(init.localParams.maxHtlcValueInFlightMsat == UInt64(50_000_000)) // max-htlc-value-in-flight-percent + assert(init.proposedCommitParams.localMaxHtlcValueInFlight == UInt64(50_000_000)) // max-htlc-value-in-flight-percent channel.expectMsg(open) } { val open = createOpenChannelMessage().copy(fundingSatoshis = 500_000 sat) peerConnection.send(peer, open) val init = channel.expectMsgType[INPUT_INIT_CHANNEL_NON_INITIATOR] - assert(init.localParams.maxHtlcValueInFlightMsat == UInt64(100_000_000)) // max-htlc-value-in-flight-msat + assert(init.proposedCommitParams.localMaxHtlcValueInFlight == UInt64(100_000_000)) // max-htlc-value-in-flight-msat channel.expectMsg(open) } } @@ -714,7 +713,7 @@ class PeerSpec extends FixtureSpec { val open = createOpenChannelMessage() system.eventStream.subscribe(probe.ref, classOf[ChannelAborted]) connect(remoteNodeId, peer, peerConnection, switchboard) - peer ! SpawnChannelNonInitiator(Left(open), ChannelConfig.standard, ChannelTypes.Standard(), None, localParams, ActorRef.noSender) + peer ! SpawnChannelNonInitiator(Left(open), ChannelConfig.standard, ChannelTypes.Standard(), None, ChannelCodecsSpec.localChannelParams, ActorRef.noSender) val channelAborted = probe.expectMsgType[ChannelAborted] assert(channelAborted.remoteNodeId == remoteNodeId) assert(channelAborted.channelId == open.temporaryChannelId) @@ -843,7 +842,7 @@ class PeerSpec extends FixtureSpec { assert(nodeParams.db.peers.getPeer(remoteNodeId).isEmpty) // Our peer wants to open a channel to us, but we disconnect before we have a confirmed channel. - peer ! SpawnChannelNonInitiator(Left(createOpenChannelMessage()), ChannelConfig.standard, ChannelTypes.Standard(), None, localParams, peerConnection.ref) + peer ! SpawnChannelNonInitiator(Left(createOpenChannelMessage()), ChannelConfig.standard, ChannelTypes.Standard(), None, ChannelCodecsSpec.localChannelParams, peerConnection.ref) peer ! Peer.ConnectionDown(peerConnection.ref) probe.send(peer, Peer.GetPeerInfo(Some(probe.ref.toTyped))) assert(probe.expectMsgType[Peer.PeerInfo].state == Peer.DISCONNECTED) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/io/PendingChannelsRateLimiterSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/io/PendingChannelsRateLimiterSpec.scala index 5e9dfc21be..e4ae7b3b8e 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/io/PendingChannelsRateLimiterSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/io/PendingChannelsRateLimiterSpec.scala @@ -18,6 +18,7 @@ package fr.acinq.eclair.io import akka.actor.testkit.typed.scaladsl.{ScalaTestWithActorTestKit, TestProbe} import akka.actor.typed.eventstream.EventStream.Publish +import com.softwaremill.quicklens.ModifyPimp import com.typesafe.config.ConfigFactory import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey import fr.acinq.bitcoin.scalacompat.{Block, ByteVector32, SatoshiLong, Transaction, TxId, TxOut} @@ -50,16 +51,16 @@ class PendingChannelsRateLimiterSpec extends ScalaTestWithActorTestKit(ConfigFac val channelIdAtLimit2: ByteVector32 = ByteVector32(hex"0999999990000000000000000000000000000000000000000000000000000000") // This peer is whitelisted and starts tests with pending channels at the rate-limit (which should be ignored because it is whitelisted). - val peerOnWhitelistAtLimit = randomKey().publicKey + val peerOnWhitelistAtLimit: PublicKey = randomKey().publicKey // The following two peers start tests already at their rate-limit. val peerAtLimit1: PublicKey = randomKey().publicKey val peerAtLimit2: PublicKey = randomKey().publicKey - val peersAtLimit = Seq(peerAtLimit1, peerAtLimit2) + val peersAtLimit: Seq[PublicKey] = Seq(peerAtLimit1, peerAtLimit2) // The following two peers start tests with one available slot before reaching the rate-limit. val peerBelowLimit1: PublicKey = randomKey().publicKey val peerBelowLimit2: PublicKey = randomKey().publicKey - val peersBelowLimit = Seq(peerBelowLimit1, peerBelowLimit2) - val publicPeers = Seq(peerOnWhitelistAtLimit, peerAtLimit1, peerAtLimit2, peerBelowLimit1, peerBelowLimit2) + val peersBelowLimit: Seq[PublicKey] = Seq(peerBelowLimit1, peerBelowLimit2) + val publicPeers: Seq[PublicKey] = Seq(peerOnWhitelistAtLimit, peerAtLimit1, peerAtLimit2, peerBelowLimit1, peerBelowLimit2) // This peer has one pending private channel. val privatePeer1: PublicKey = randomKey().publicKey // This peer has one private channel that isn't pending. @@ -114,8 +115,9 @@ class PendingChannelsRateLimiterSpec extends ScalaTestWithActorTestKit(ConfigFac def commitments(remoteNodeId: PublicKey, channelId: ByteVector32, isOpener: Boolean = false): Commitments = { val ann = Announcements.makeChannelAnnouncement(Block.RegtestGenesisBlock.hash, RealShortChannelId(42), TestConstants.Alice.nodeParams.nodeId, remoteNodeId, randomKey().publicKey, randomKey().publicKey, randomBytes64(), randomBytes64(), randomBytes64(), randomBytes64()) - val commitments = CommitmentsSpec.makeCommitments(500_000 msat, 400_000 msat, TestConstants.Alice.nodeParams.nodeId, remoteNodeId, announcement_opt = Some(ann)) - commitments.copy(params = commitments.params.copy(channelId = channelId, localParams = commitments.params.localParams.copy(isChannelOpener = isOpener))) + CommitmentsSpec.makeCommitments(500_000 msat, 400_000 msat, TestConstants.Alice.nodeParams.nodeId, remoteNodeId, announcement_opt = Some(ann)) + .modify(_.channelParams.channelId).setTo(channelId) + .modify(_.channelParams.localParams.isChannelOpener).setTo(isOpener) } def processRestoredChannels(f: FixtureParam, restoredChannels: Seq[PersistentChannelData]): Unit = { 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 ac2a500ecc..8d704c66c4 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 @@ -164,7 +164,8 @@ class SwitchboardSpec extends TestKitBaseClass with AnyFunSuiteLike { } def dummyDataNormal(remoteNodeId: PublicKey, capacity: Satoshi): DATA_NORMAL = { - val data = ChannelCodecsSpec.normal.modify(_.commitments.params.remoteParams.nodeId).setTo(remoteNodeId) + val data = ChannelCodecsSpec.normal + .modify(_.commitments.channelParams.remoteParams.nodeId).setTo(remoteNodeId) .modify(_.commitments.active).apply(_.map(_.modify(_.localCommit.input.txOut.amount).setTo(capacity))) assert(data.remoteNodeId == remoteNodeId) assert(data.commitments.capacity == capacity) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/json/JsonSerializersSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/json/JsonSerializersSpec.scala index 891a7ef0a6..1db84212f4 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/json/JsonSerializersSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/json/JsonSerializersSpec.scala @@ -122,8 +122,8 @@ class JsonSerializersSpec extends TestKitBaseClass with AnyFunSuiteLike with Mat val probe = TestProbe()(system) val dummyPublicKey = PrivateKey(hex"0101010101010101010101010101010101010101010101010101010101010101").publicKey val dummyBytes32 = ByteVector32(hex"0202020202020202020202020202020202020202020202020202020202020202") - val localParams = LocalParams(dummyPublicKey, DeterministicWallet.KeyPath(Seq(42L)), 546 sat, UInt64(Long.MaxValue), Some(1000 sat), 1 msat, CltvExpiryDelta(144), 50, isChannelOpener = true, paysCommitTxFees = true, None, None, Features.empty) - val remoteParams = RemoteParams(dummyPublicKey, 546 sat, UInt64.MaxValue, Some(1000 sat), 1 msat, CltvExpiryDelta(144), 50, dummyPublicKey, dummyPublicKey, dummyPublicKey, dummyPublicKey, Features.empty, None) + val localChannelParams = LocalChannelParams(dummyPublicKey, DeterministicWallet.KeyPath(Seq(42L)), 546 sat, UInt64(Long.MaxValue), Some(1000 sat), 1 msat, CltvExpiryDelta(144), 50, isChannelOpener = true, paysCommitTxFees = true, None, None, Features.empty) + val remoteChannelParams = RemoteChannelParams(dummyPublicKey, 546 sat, UInt64.MaxValue, Some(1000 sat), 1 msat, CltvExpiryDelta(144), 50, dummyPublicKey, dummyPublicKey, dummyPublicKey, dummyPublicKey, Features.empty, None) val commitmentInput = Funding.makeFundingInputInfo(TxId(dummyBytes32), 0, 150_000 sat, dummyPublicKey, dummyPublicKey, DefaultCommitmentFormat) val localCommit = LocalCommit(0, CommitmentSpec(Set.empty, FeeratePerKw(2500 sat), 100_000_000 msat, 50_000_000 msat), TxId(dummyBytes32), commitmentInput, IndividualSignature(ByteVector64.Zeroes), Nil) val remoteCommit = RemoteCommit(0, CommitmentSpec(Set.empty, FeeratePerKw(2500 sat), 50_000_000 msat, 100_000_000 msat), TxId(dummyBytes32), dummyPublicKey) @@ -134,7 +134,7 @@ class JsonSerializersSpec extends TestKitBaseClass with AnyFunSuiteLike with Mat NORMAL, DATA_NORMAL( Commitments( - ChannelParams(dummyBytes32, ChannelConfig.standard, ChannelFeatures(), localParams, remoteParams, ChannelFlags(announceChannel = true)), + ChannelParams(dummyBytes32, ChannelConfig.standard, ChannelFeatures(), localChannelParams, remoteChannelParams, ChannelFlags(announceChannel = true)), CommitmentChanges(LocalChanges(Nil, Nil, Nil), RemoteChanges(Nil, Nil, Nil), localNextHtlcId = 1, remoteNextHtlcId = 1), List(Commitment(0, 0, dummyPublicKey, LocalFundingStatus.SingleFundedUnconfirmedFundingTx(None), RemoteFundingStatus.Locked, localCommit, remoteCommit, None)), inactive = Nil, @@ -156,7 +156,7 @@ class JsonSerializersSpec extends TestKitBaseClass with AnyFunSuiteLike with Mat | "data": { | "type": "DATA_NORMAL", | "commitments": { - | "params": { + | "channelParams": { | "channelId": "0202020202020202020202020202020202020202020202020202020202020202", | "channelConfig": ["funding_pubkey_based_channel_keypath"], | "channelFeatures": [], @@ -167,7 +167,7 @@ class JsonSerializersSpec extends TestKitBaseClass with AnyFunSuiteLike with Mat | "maxHtlcValueInFlightMsat": 9223372036854775807, | "initialRequestedChannelReserve_opt": 1000, | "htlcMinimum": 1, - | "toSelfDelay": 144, + | "toRemoteDelay": 144, | "maxAcceptedHtlcs": 50, | "isChannelOpener": true, | "paysCommitTxFees" : true, @@ -179,7 +179,7 @@ class JsonSerializersSpec extends TestKitBaseClass with AnyFunSuiteLike with Mat | "maxHtlcValueInFlightMsat": 18446744073709551615, | "initialRequestedChannelReserve_opt": 1000, | "htlcMinimum": 1, - | "toSelfDelay": 144, + | "toRemoteDelay": 144, | "maxAcceptedHtlcs": 50, | "revocationBasepoint": "031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f", | "paymentBasepoint": "031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f", diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/payment/PaymentPacketSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/payment/PaymentPacketSpec.scala index c5ea981e7f..a3f64d86a0 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/payment/PaymentPacketSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/payment/PaymentPacketSpec.scala @@ -744,8 +744,8 @@ object PaymentPacketSpec { def makeCommitments(channelId: ByteVector32, testAvailableBalanceForSend: MilliSatoshi = 50000000 msat, testAvailableBalanceForReceive: MilliSatoshi = 50000000 msat, testCapacity: Satoshi = 100000 sat, channelFeatures: ChannelFeatures = ChannelFeatures(), announcement_opt: Option[ChannelAnnouncement] = None): Commitments = { val channelReserve = testCapacity * 0.01 - val localParams = LocalParams(null, null, null, UInt64.MaxValue, Some(channelReserve), null, null, 0, isChannelOpener = true, paysCommitTxFees = true, None, None, Features.empty) - val remoteParams = RemoteParams(randomKey().publicKey, null, UInt64.MaxValue, Some(channelReserve), null, null, maxAcceptedHtlcs = 0, null, null, null, null, null, None) + val localChannelParams = LocalChannelParams(null, null, null, UInt64.MaxValue, Some(channelReserve), null, null, 0, isChannelOpener = true, paysCommitTxFees = true, None, None, Features.empty) + val remoteChannelParams = RemoteChannelParams(randomKey().publicKey, null, UInt64.MaxValue, Some(channelReserve), null, null, maxAcceptedHtlcs = 0, null, null, null, null, null, None) val fundingTx = Transaction(2, Nil, Seq(TxOut(testCapacity, Nil)), 0) val commitInput = InputInfo(OutPoint(fundingTx, 0), fundingTx.txOut.head, ByteVector.empty) val localCommit = LocalCommit(0, null, randomTxId(), commitInput, IndividualSignature(ByteVector64.Zeroes), Nil) @@ -758,7 +758,7 @@ object PaymentPacketSpec { } val channelFlags = ChannelFlags(announceChannel = announcement_opt.nonEmpty) new Commitments( - ChannelParams(channelId, ChannelConfig.standard, channelFeatures, localParams, remoteParams, channelFlags), + ChannelParams(channelId, ChannelConfig.standard, channelFeatures, localChannelParams, remoteChannelParams, channelFlags), CommitmentChanges(localChanges, remoteChanges, 0, 0), List(Commitment(0, 0, null, localFundingStatus, RemoteFundingStatus.Locked, localCommit, remoteCommit, None)), inactive = Nil, diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/payment/relay/OnTheFlyFundingSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/payment/relay/OnTheFlyFundingSpec.scala index aa4731b2f2..04beb14920 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/payment/relay/OnTheFlyFundingSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/payment/relay/OnTheFlyFundingSpec.scala @@ -165,7 +165,7 @@ class OnTheFlyFundingSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike { def makeChannelData(htlcMinimum: MilliSatoshi = 1 msat, localChanges: LocalChanges = LocalChanges(Nil, Nil, Nil)): DATA_NORMAL = { val commitments = CommitmentsSpec.makeCommitments(500_000_000 msat, 500_000_000 msat, nodeParams.nodeId, remoteNodeId, announcement_opt = None) - .modify(_.params.remoteParams.htlcMinimum).setTo(htlcMinimum) + .modify(_.channelParams.remoteParams.htlcMinimum).setTo(htlcMinimum) .modify(_.changes.localChanges).setTo(localChanges) DATA_NORMAL(commitments, ShortIdAliases(Alias(42), None), None, null, None, None, None, SpliceStatus.NoSplice) } @@ -563,8 +563,8 @@ class OnTheFlyFundingSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike { peerConnection.send(peer, open) rateLimiter.expectMsgType[AddOrRejectChannel].replyTo ! PendingChannelsRateLimiter.AcceptOpenChannel val init = channel.expectMsgType[INPUT_INIT_CHANNEL_NON_INITIATOR] - assert(!init.localParams.isChannelOpener) - assert(init.localParams.paysCommitTxFees) + assert(!init.localChannelParams.isChannelOpener) + assert(init.localChannelParams.paysCommitTxFees) assert(init.fundingContribution_opt.contains(LiquidityAds.AddFunding(requestFunding.requestedAmount, nodeParams.liquidityAdsConfig.rates_opt))) // The preimage was provided, so we fulfill upstream HTLCs. @@ -616,8 +616,8 @@ class OnTheFlyFundingSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike { peerConnection.send(peer, open3) rateLimiter.expectMsgType[AddOrRejectChannel].replyTo ! PendingChannelsRateLimiter.AcceptOpenChannel val init = channel.expectMsgType[INPUT_INIT_CHANNEL_NON_INITIATOR] - assert(!init.localParams.isChannelOpener) - assert(init.localParams.paysCommitTxFees) + assert(!init.localChannelParams.isChannelOpener) + assert(init.localChannelParams.paysCommitTxFees) assert(init.fundingContribution_opt.contains(LiquidityAds.AddFunding(requestFunding.requestedAmount, nodeParams.liquidityAdsConfig.rates_opt))) assert(channel.expectMsgType[OpenDualFundedChannel].useFeeCredit_opt.contains(3_000_000 msat)) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/ChannelCodecsSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/ChannelCodecsSpec.scala index b10bac7a44..ccd1c0f9bf 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/ChannelCodecsSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/ChannelCodecsSpec.scala @@ -251,28 +251,27 @@ object ChannelCodecsSpec { val seed: ByteVector32 = ByteVector32(ByteVector.fill(32)(1)) val nodeKeyManager: NodeKeyManager = LocalNodeKeyManager(seed, Block.RegtestGenesisBlock.hash) val channelKeyManager: ChannelKeyManager = LocalChannelKeyManager(seed, Block.RegtestGenesisBlock.hash) - val localParams: LocalParams = LocalParams( + val localChannelParams: LocalChannelParams = LocalChannelParams( nodeKeyManager.nodeId, fundingKeyPath = DeterministicWallet.KeyPath(Seq(42L)), dustLimit = Satoshi(546), maxHtlcValueInFlightMsat = UInt64(50_000_000), initialRequestedChannelReserve_opt = Some(10000 sat), htlcMinimum = 10000 msat, - toSelfDelay = CltvExpiryDelta(144), + toRemoteDelay = CltvExpiryDelta(144), maxAcceptedHtlcs = 50, upfrontShutdownScript_opt = None, walletStaticPaymentBasepoint = None, isChannelOpener = true, paysCommitTxFees = true, initFeatures = Features.empty) - - val remoteParams: RemoteParams = RemoteParams( + val remoteChannelParams: RemoteChannelParams = RemoteChannelParams( nodeId = randomKey().publicKey, dustLimit = 546 sat, maxHtlcValueInFlightMsat = UInt64(5000000), initialRequestedChannelReserve_opt = Some(10000 sat), htlcMinimum = 5000 msat, - toSelfDelay = CltvExpiryDelta(144), + toRemoteDelay = CltvExpiryDelta(144), maxAcceptedHtlcs = 50, revocationBasepoint = PrivateKey(ByteVector.fill(32)(2)).publicKey, paymentBasepoint = PrivateKey(ByteVector.fill(32)(3)).publicKey, @@ -310,7 +309,7 @@ object ChannelCodecsSpec { val fundingTx = Transaction.read("0200000001adbb20ea41a8423ea937e76e8151636bf6093b70eaff942930d20576600521fd000000006b48304502210090587b6201e166ad6af0227d3036a9454223d49a1f11839c1a362184340ef0240220577f7cd5cca78719405cbf1de7414ac027f0239ef6e214c90fcaab0454d84b3b012103535b32d5eb0a6ed0982a0479bbadc9868d9836f6ba94dd5a63be16d875069184ffffffff028096980000000000220020c015c4a6be010e21657068fc2e6a9d02b27ebe4d490a25846f7237f104d1a3cd20256d29010000001600143ca33c2e4446f4a305f23c80df8ad1afdcf652f900000000") val fundingAmount = fundingTx.txOut.head.amount val fundingTxIndex = 0 - val localFundingPubKey = channelKeyManager.channelKeys(ChannelConfig.standard, localParams.fundingKeyPath).fundingKey(fundingTxIndex = 0).publicKey + val localFundingPubKey = channelKeyManager.channelKeys(ChannelConfig.standard, localChannelParams.fundingKeyPath).fundingKey(fundingTxIndex = 0).publicKey val remoteFundingPubKey = PrivateKey(ByteVector32(ByteVector.fill(32)(1)) :+ 1.toByte).publicKey val commitmentInput = Funding.makeFundingInputInfo(fundingTx.txid, 0, fundingAmount, localFundingPubKey, remoteFundingPubKey, DefaultCommitmentFormat) val remoteSig = ByteVector64(hex"2148d2d4aac8c793eb82d31bcf22d4db707b9fd7eee1b89b4b1444c9e19ab7172bab8c3d997d29163fa0cb255c75afb8ade13617ad1350c1515e9be4a222a04d") @@ -319,7 +318,7 @@ object ChannelCodecsSpec { val channelId = htlcs.headOption.map(_.add.channelId).getOrElse(ByteVector32.Zeroes) val channelFlags = ChannelFlags(announceChannel = true) val commitments = Commitments( - ChannelParams(channelId, ChannelConfig.standard, ChannelFeatures(), localParams, remoteParams, channelFlags), + ChannelParams(channelId, ChannelConfig.standard, ChannelFeatures(), localChannelParams, remoteChannelParams, channelFlags), CommitmentChanges(LocalChanges(Nil, Nil, Nil), RemoteChanges(Nil, Nil, Nil), localNextHtlcId = 32, remoteNextHtlcId = 4), Seq(Commitment(fundingTxIndex, 0, remoteFundingPubKey, LocalFundingStatus.SingleFundedUnconfirmedFundingTx(None), RemoteFundingStatus.NotLocked, localCommit, remoteCommit, None)), remoteNextCommitInfo = Right(randomKey().publicKey), diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/version2/ChannelCodecs2Spec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/version2/ChannelCodecs2Spec.scala index 52f4fea035..a4d9772623 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/version2/ChannelCodecs2Spec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/version2/ChannelCodecs2Spec.scala @@ -28,32 +28,32 @@ class ChannelCodecs2Spec extends AnyFunSuite { { // Standard channel val commitments = channelDataCodec.decode(dataNormal.bits).require.value.asInstanceOf[ChannelDataWithCommitments].commitments - assert(commitments.params.channelConfig == ChannelConfig.standard) - assert(commitments.params.channelFeatures == ChannelFeatures()) + assert(commitments.channelParams.channelConfig == ChannelConfig.standard) + assert(commitments.channelParams.channelFeatures == ChannelFeatures()) } { val staticRemoteKeyChannel = hex"00020000000303af0ed6052cf28d670665549bc86f4b721c9fdb309d40c58f5811f63966e005d000090ef5e61dc12e5215dfcf8a1263f66b998a162fd80ea9aabf4fd1483d63fcd68280000001000000000000044c0000000008f0d1800000000000002710000000000000000000900064ff160014170e6de64a6d55c73f3ff657ef441d43739837ab028feba10d0eafd0fad8fe20e6d9206e6bd30242826de05c63f459a00aced24b120000186b0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000026982039dc0e0b1d25905e44fdf6f8e89755a5e219685840d0bc1d28d3308f9628a358500000000000003e8ffffffffffffffff0000000000004e2000000000000003e80090001e023da0b6ec447fbda75506f743247a7fb6f8e29c1e18cfff53f2f9136801c617a7022dc9905a27397dedf60ef915579f2464c8fa930fae14adb6563e5559905067e5028feba10d0eafd0fad8fe20e6d9206e6bd30242826de05c63f459a00aced24b12032ed22e583b835accc8b4b5bfc94331ce06b07c31952551fd9520e126b1ed43c703da7493b310a19286c452e3d1f8ee66afaf6f1656736f6464d00deedd0b58585b00000003026982000000000000000000000000002710000000002faf0800000000000bebc20024f452ff0b3c6f363530f2a203e8fd6fcd88d177a2dac14b4b045abead090e4f4f000000002b40420f000000000022002065adbae4db91fa9069e2c8dce1f716c65e6dbc302229772d62305bd2e0e6494e475221023da0b6ec447fbda75506f743247a7fb6f8e29c1e18cfff53f2f9136801c617a72103a62130179b4cb0451ddbcd4480c326d5343a691bc01e07bb6eee35fc91a7601752aefd015b02000000000101f452ff0b3c6f363530f2a203e8fd6fcd88d177a2dac14b4b045abead090e4f4f000000000036a2ab8002400d030000000000160014761879f7b274ce995f87150a02e75cc0c037e8e3b8180c00000000002200204b354f6e432cae820a572c8294423f4bc6a5b9a2509d3de22b93c6316b59e14b0400483045022100fe9a0106b51293216f200a5a0b17a783f7ace4edbd71b644dee3e25c2688834802203a1087649b2cba80f5a634c1c67fbce4355f6c5605dd873f12d0399a542e363d01483045022100e71334e385755ab65b7ac6be2709a0be39f98fde6a6c10a895fd6f90ecd3fd7d022036550ecd40ed942f0a4ae3d0e29b6142a3cc4492eb73c3a62ced6d934e48584d01475221023da0b6ec447fbda75506f743247a7fb6f8e29c1e18cfff53f2f9136801c617a72103a62130179b4cb0451ddbcd4480c326d5343a691bc01e07bb6eee35fc91a7601752aeac67892000000000000000000000000000002710000000000bebc200000000002faf080018fa9f3051c52bba85fc20763e8835aed58c763f52a1647c90cc850aeb62ac3d02eada0cd5618069ed848f3975a631f02c87beb9968df8bd99511fa08f75d64529000000000000000000000000000000000000000000000000000000000000ff03b960d87d264cc2c99f71ed6ba6dd1bdb06c03666f76d90a1670a73dc468428e924f452ff0b3c6f363530f2a203e8fd6fcd88d177a2dac14b4b045abead090e4f4f000000002b40420f000000000022002065adbae4db91fa9069e2c8dce1f716c65e6dbc302229772d62305bd2e0e6494e475221023da0b6ec447fbda75506f743247a7fb6f8e29c1e18cfff53f2f9136801c617a72103a62130179b4cb0451ddbcd4480c326d5343a691bc01e07bb6eee35fc91a7601752ae000000f452ff0b3c6f363530f2a203e8fd6fcd88d177a2dac14b4b045abead090e4f4f061a8000002a00000000884a5e841be07f8612321ece5e40b39d715ffe94978c06cf3bb3af1a0cadcefc4b4aaade3deb191662f00b304edeae18ae8c80ed3dc505e8c78876b6fb61682fcb06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f061a8000002a0000629dbe540101009000000000000003e8000854d00000000a000000003b9aca000000" val commitments = channelDataCodec.decode(staticRemoteKeyChannel.bits).require.value.asInstanceOf[ChannelDataWithCommitments].commitments - assert(commitments.params.channelConfig == ChannelConfig.standard) - assert(commitments.params.channelFeatures == ChannelFeatures(Features.StaticRemoteKey)) + assert(commitments.channelParams.channelConfig == ChannelConfig.standard) + assert(commitments.channelParams.channelFeatures == ChannelFeatures(Features.StaticRemoteKey)) } { val anchorOutputsChannel = hex"00020000000703af0ed6052cf28d670665549bc86f4b721c9fdb309d40c58f5811f63966e005d000094b82816a3f15ab3e324ddf6f0f5a116cef8c3200a353240db684337d2dcaa81e80000001000000000000044c000000001dcd65000000000000002710000000000000000000900064ff160014f09f6f93de60c6af417ed31d52c2c883b6113f260000186b0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000225982039dc0e0b1d25905e44fdf6f8e89755a5e219685840d0bc1d28d3308f9628a358500000000000003e8ffffffffffffffff0000000000004e2000000000000003e80090001e02e9cd12509fbc345c10e2b2e10427ae43eabbf0788bda8118b34344e5576d5d5002eb112dd8d61a02bf3434d5417e1020ed2d951e75bd1e14615d473dd5f1991b4402ca8b6891d6a53aea035259fa0d57a1e672d3cc59a2c696a96247d3557ee726cd030f2aa0ca0ae0e00d6da847d897cf7288ae286dd12037f06250937dc7b37fe0b5028d59e68c5799980a98b120acb891dabfd091e80c6596b0c2a7de57a298d48512000000032259820000000000000000000000000009c4000000002faf0800000000000bebc2002432e16e6e875d1f02a9512943ba2eb9309f4715390b52e4965dd6e39a2989ae63000000002b40420f00000000002200204de81ee2e9850dabdb9c364a12cc2dd75dd20c21d4ca0a809a2e6af3caeeaf9647522102e9cd12509fbc345c10e2b2e10427ae43eabbf0788bda8118b34344e5576d5d502103683425bf640d5e4338553ca6f6afea948ff2bf378eed1b3e9497a3f18f477d5352aefd01bc0200000000010132e16e6e875d1f02a9512943ba2eb9309f4715390b52e4965dd6e39a2989ae63000000000089273f80044a010000000000002200202102815a0b14d50a2a8c028cd47413e743f02ad5460151bd4ae5930639cbbd484a010000000000002200204e81bd6470c45c349068c2b0ad544934b718ef49c1615f2a0b0cd8766400b562400d0300000000002200208eadab92c95168438acfb73f2d3d92f56d6fc30d3f79fc4527f4e77df88b8add72270c0000000000220020895c0fef7efb7aa0e4805381434363b30386d31f6cb621abb0ca4a52b269fbc304004830450221009f09a584b1af9ba86f1618aad1ca9817324f97c3d3789b2490c3b9435c7bf1dd02205e4dcca3d7937f6b80a0ed39084e4ea9e9c531b80698ebd0c116fd9319a0db1201473044022001e4104ec25ba9bc43bf3f623d6e98f371434442b134255667ddeedd9cd9cd1b02201f057d2c15ee4e5d62a73f1db262846ca7ad35deaed2496abdb5b16cd91c5cb80147522102e9cd12509fbc345c10e2b2e10427ae43eabbf0788bda8118b34344e5576d5d502103683425bf640d5e4338553ca6f6afea948ff2bf378eed1b3e9497a3f18f477d5352ae25899520000000000000000000000000000009c4000000000bebc200000000002faf0800acdb0bf90ed7350d429c2d70fce66300ac9b27d8dbb3bceb5bd2cc8bd443938f03f54d00601f1b95e82836540d760ab6b38bc6fc1701df5d5e3b410f1936212d54000000000000000000000000000000000000000000000000000000000000ff03658b1e02efd8464688f87a052518691ff4d818a7c36addf4c6520ae07b7e20912432e16e6e875d1f02a9512943ba2eb9309f4715390b52e4965dd6e39a2989ae63000000002b40420f00000000002200204de81ee2e9850dabdb9c364a12cc2dd75dd20c21d4ca0a809a2e6af3caeeaf9647522102e9cd12509fbc345c10e2b2e10427ae43eabbf0788bda8118b34344e5576d5d502103683425bf640d5e4338553ca6f6afea948ff2bf378eed1b3e9497a3f18f477d5352ae00000032e16e6e875d1f02a9512943ba2eb9309f4715390b52e4965dd6e39a2989ae63061a8000002a000000008833a9275befbedbf928e743a71c9476f46528baf6e832ad25478c2607e4108dea67657c51db7344032627c855518179dc7a94b59f306faf9a3b4eef7684d5d73106226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f061a8000002a000060e32a590101009000000000000003e8000854d00000000a000000003b9aca000000" val commitments = channelDataCodec.decode(anchorOutputsChannel.bits).require.value.asInstanceOf[ChannelDataWithCommitments].commitments - assert(commitments.params.channelConfig == ChannelConfig.standard) - assert(commitments.params.channelFeatures == ChannelFeatures(Features.StaticRemoteKey, Features.AnchorOutputs)) + assert(commitments.channelParams.channelConfig == ChannelConfig.standard) + assert(commitments.channelParams.channelFeatures == ChannelFeatures(Features.StaticRemoteKey, Features.AnchorOutputs)) } { val wumboChannel = hex"00000000000103af0ed6052cf28d670665549bc86f4b721c9fdb309d40c58f5811f63966e005d00009b3b6da18b7e5e43405415a43e61abd77edf4d300c131af17a955950837d7db4980000001000000000000044c000000001dcd65000000000000002710000000000000000000900064ff1600142946bdbb3141be9a40ed8133ef159ee0022176e90000186b02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a4982039dc0e0b1d25905e44fdf6f8e89755a5e219685840d0bc1d28d3308f9628a358500000000000003e8ffffffffffffffff0000000000004e2000000000000003e80090001e03a6be2613a9ff761a769b077abb43d76c5f06944fc32010891156179bf8b81607025c24f0c3572631ea09dade913ccbb1cd8a55585fc152cc2165bf4f43af702c8b0306c241c667eefee031639052c4a35c4ae076ab56b49f76f7e12f63dfb7bb32a503fdbff1ca92c99c09a9c0eac3cfe1ca35deb658d5fdb815fe7a240df25da5e20f02c47d9e4e1fb501c81933cfc4d3ba7f0e8203003cda2683569f1f67aac2b6e20d000000030a4982000000000000000000000000002710000000745e66c600000000000bebc2002464fc06b43e94d9ce0a5a0e1ef13f63ba78e56d920e7d606d0c6e7a631c48c32c000000002b0065cd1d00000000220020d1b88cc50b09abce945ce6703f30dae3d71ec626be2201925db9379a3e8b981047522103044d393b0da6bcd92030f3131d0780b0d6fa017a0ff45b7fed708903c2950ced2103a6be2613a9ff761a769b077abb43d76c5f06944fc32010891156179bf8b8160752aefd01590200000000010164fc06b43e94d9ce0a5a0e1ef13f63ba78e56d920e7d606d0c6e7a631c48c32c000000000018e2678002400d030000000000160014cf3c9d08ec27d3ffefbf7e2640d3773e11a60ceb783bca1d00000000220020153e514ade07f347db9ed32cf6b2096d066d48e0cf8c504590cd1155de68be2204004730440220056ac83d5b2eb9eb9714e85294d080a9b64f73916d8206b15533613b4303ed3d022044da40ba433e27ddb8743c75acc0f6b050c346bc9d241ab3a1b65051820ce06a0147304402207683c10f33682e2389e5f02dd34090bbe4d786633d49e1777d5ec2ab71a7924902206d99dceb74ff809237ae8e06c118b38047e2d4a49f9956c538bedca47cb4b1da0147522103044d393b0da6bcd92030f3131d0780b0d6fa017a0ff45b7fed708903c2950ced2103a6be2613a9ff761a769b077abb43d76c5f06944fc32010891156179bf8b8160752aef5c4602000000000000000000000000000002710000000000bebc200000000745e66c6000bdebd6cf39db4c2ce1a675281b0a714e525525149032ba048d75c89e5a9b355021a87b53e12e4b36287635cdf887991a732c2fd56b12f5377d755b8b890795db6000000000000000000000000000000000000000000000000000000000000ff032c5f941f78a00105b995fba7f3c340afe53e287a60361135386ae1448d6f3d632464fc06b43e94d9ce0a5a0e1ef13f63ba78e56d920e7d606d0c6e7a631c48c32c000000002b0065cd1d00000000220020d1b88cc50b09abce945ce6703f30dae3d71ec626be2201925db9379a3e8b981047522103044d393b0da6bcd92030f3131d0780b0d6fa017a0ff45b7fed708903c2950ced2103a6be2613a9ff761a769b077abb43d76c5f06944fc32010891156179bf8b8160752ae00000064fc06b43e94d9ce0a5a0e1ef13f63ba78e56d920e7d606d0c6e7a631c48c32cff5e020000000101010101010101010101010101010101010101010101010101010101010101012a00000000ffffffff010065cd1d00000000220020d1b88cc50b09abce945ce6703f30dae3d71ec626be2201925db9379a3e8b9810000000000000000060e32bf9000082000000000000000000000000000000000000000000000000000000000000000064fc06b43e94d9ce0a5a0e1ef13f63ba78e56d920e7d606d0c6e7a631c48c32c0000f4957823b0a6b76697d7c545bcca66abec8522a0f6350a722e45f3f2830f7f824c84efed8daffa04bb0822ce1a08fb2de77dd20c23a91cced7a3966808956644" val commitments = channelDataCodec.decode(wumboChannel.bits).require.value.asInstanceOf[ChannelDataWithCommitments].commitments - assert(commitments.params.channelConfig == ChannelConfig.standard) - assert(commitments.params.channelFeatures == ChannelFeatures()) + assert(commitments.channelParams.channelConfig == ChannelConfig.standard) + assert(commitments.channelParams.channelFeatures == ChannelFeatures()) } } test("ensure remote shutdown script is not set") { val commitments = channelDataCodec.decode(dataNormal.bits).require.value.asInstanceOf[ChannelDataWithCommitments].commitments - assert(commitments.params.remoteParams.upfrontShutdownScript_opt.isEmpty) + assert(commitments.remoteChannelParams.upfrontShutdownScript_opt.isEmpty) } } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/version4/ChannelCodecs4Spec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/version4/ChannelCodecs4Spec.scala index 5ef9c7ffa7..3ea77fc4fd 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/version4/ChannelCodecs4Spec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/version4/ChannelCodecs4Spec.scala @@ -48,7 +48,7 @@ class ChannelCodecs4Spec extends AnyFunSuite { } test("encode/decode optional channel reserve") { - val localParams = LocalParams( + val localParams = LocalChannelParams( randomKey().publicKey, DeterministicWallet.KeyPath(Seq(42L)), Satoshi(660), @@ -62,7 +62,7 @@ class ChannelCodecs4Spec extends AnyFunSuite { Some(hex"deadbeef"), None, Features().initFeatures()) - val remoteParams = RemoteParams( + val remoteParams = RemoteChannelParams( randomKey().publicKey, Satoshi(500), UInt64(100000), @@ -97,7 +97,7 @@ class ChannelCodecs4Spec extends AnyFunSuite { test("encode/decode optional shutdown script") { val codec = remoteParamsCodec(ChannelFeatures()) - val remoteParams = RemoteParams( + val remoteParams = RemoteChannelParams( randomKey().publicKey, Satoshi(600), UInt64(123456L), @@ -115,10 +115,10 @@ class ChannelCodecs4Spec extends AnyFunSuite { val remoteParams1 = remoteParams.copy(upfrontShutdownScript_opt = Some(ByteVector.fromValidHex("deadbeef"))) assert(codec.decodeValue(codec.encode(remoteParams1).require).require == remoteParams1) - val dataWithoutRemoteShutdownScript = normal.modify(_.commitments.params.remoteParams).setTo(remoteParams) + val dataWithoutRemoteShutdownScript = normal.modify(_.commitments.channelParams.remoteParams).setTo(remoteParams) assert(channelDataCodec.decode(channelDataCodec.encode(dataWithoutRemoteShutdownScript).require).require.value == dataWithoutRemoteShutdownScript) - val dataWithRemoteShutdownScript = normal.modify(_.commitments.params.remoteParams).setTo(remoteParams1) + val dataWithRemoteShutdownScript = normal.modify(_.commitments.channelParams.remoteParams).setTo(remoteParams1) assert(channelDataCodec.decode(channelDataCodec.encode(dataWithRemoteShutdownScript).require).require.value == dataWithRemoteShutdownScript) } @@ -235,12 +235,12 @@ class ChannelCodecs4Spec extends AnyFunSuite { // of two separate booleans (is_channel_opener and pay_commit_tx_fees). val initiator = hex"000e0158e6936235824897192ae96caea018191fd812bc94f8421b65bd476faf9e30d901010002aaaa00ce2f18a967dc4f25f414e671ba6585f8ef0b8c5fb812c21064f55a2eaa0009828b4e829a55e78d7711e93ba9a9502dd7a6d0ef2910258323efe35533ddff0f80000001000000000000044c000000001dcd65000000000000002710000000000000000000900064ff000000186b02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020a498202bbbb671d15145722fb8c28d732cddb249bcc6652ed2b297ff1f77a18371b1e6300000000000003e8000000003b9aca000000000000004e2000000000000003e80090001e02e89c4b89177eb7cd291a21c610e9ac4445a558430e9943767481e29d1d1d790902a10d318e979d1b74de10cb66f716126ca0accd1922a0e3cdae90bdbfe637772802b2b6c791a935a20ce98a0b349e1ffb7a88121478f5dc39d3715b2416878d1d35039c795469e7814b454aee2d36f3c33ef56c34192ab49736c74d02a6697ece8f7b00000004020a498200000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000025b9fd5132058bc95861f228b98d7a6b6ff341ae7492e3f91978ed745470d27a6065e020000000101010101010101010101010101010101010101010101010101010101010101012a00000000ffffffff0140420f00000000002200209997cca7a6aed2533b0014929deeb88341516dcb5d01fbd1071681fa566650960000000000010000000000000000000000002710000000002faf0800000000000bebc2002458e6936235824897192ae96caea018191fd812bc94f8421b65bd476faf9e30d9000000002b40420f00000000002200209997cca7a6aed2533b0014929deeb88341516dcb5d01fbd1071681fa56665096475221025b9fd5132058bc95861f228b98d7a6b6ff341ae7492e3f91978ed745470d27a62102b90d8c2b072181a56fd6fbd5be9e1f723dee869d79ef4278450b01f09c3fa37f52ae7d020000000158e6936235824897192ae96caea018191fd812bc94f8421b65bd476faf9e30d90000000000deefa28002400d030000000000160014b2e9d9708cd135eec2ffc2dce8c4860b4b41e8b4b8180c0000000000220020de29e3b845619436603ee692c2d8a56a116599bf6ec1332e7ec51d09e26f7bc5123a44209c41e27950a3cc928116474ff4c92279124c00919e37174cb6e5011c208ca69807d936ecb290f93c797592d709ae72672e151aad4c15929c5c649e761f5fa05000000000000000000000000000002710000000000bebc200000000002faf0800ce0de659e08f34dda3a8710267d96bb0af73fd78f559efa3cc8f846f2f6dba1f03d64b4a3d14f322bdad603bfb9359cd08d2b9b0efce54aa0fe787b2e3406c26a2000000ff0338f1d042dcb5dcfb7b0b29c58fd3ecb9d9b0957fa03703bf515433854800b1f100000000000001061a8000002a000000010289b8c594531eebff023976e44871e45500885e48c0ebe39357451ff3914d0a6648d576d4d62b8274d38ab1b41691c78d68562764c8771495b2517fe7fff8d75fd7622d54c466ac93baee1d6fac4a53ddef0d06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f0289b8c594531eeb6605b1300300009000000000000003e8000858b800000014000000001dcd650000000001" val initiatorDecoded = channelDataCodec.decode(initiator.bits).require.value.asInstanceOf[DATA_NORMAL] - assert(initiatorDecoded.commitments.params.localParams.isChannelOpener) - assert(initiatorDecoded.commitments.params.localParams.paysCommitTxFees) + assert(initiatorDecoded.commitments.localChannelParams.isChannelOpener) + assert(initiatorDecoded.commitments.localChannelParams.paysCommitTxFees) val nonInitiator = hex"000e0158e6936235824897192ae96caea018191fd812bc94f8421b65bd476faf9e30d901010002bbbb671d15145722fb8c28d732cddb249bcc6652ed2b297ff1f77a18371b1e63000927012067c2958dc0317a439185b5619e15c528726ebb2b75b4e6ae80c89468a28000000000000000000003e8000000003b9aca000000000000004e2000000000000003e80090001e000000000004020a498202aaaa00ce2f18a967dc4f25f414e671ba6585f8ef0b8c5fb812c21064f55a2eaa000000000000044c000000001dcd6500000000000000271000000000000000000090006402a69186cd9e36bcb3dd3e92be5e1224984239175c4e3afdf7d6a14023042dc5bd03c191e410e8545c6fc8aeee9aeb5a10cec30c03e950b9920b2474eb09e1cab70e037ca17e6afb2fab6e03fa4aac50be6d9beffea390761ee2ff6ef336e2783101c0036e0b2571509ce82bd31dfb1e810c1c2c294430a02d58fe997f4a7a2d06508ccc0000186b02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020a49820000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000002b90d8c2b072181a56fd6fbd5be9e1f723dee869d79ef4278450b01f09c3fa37f065e020000000101010101010101010101010101010101010101010101010101010101010101012a00000000ffffffff0140420f00000000002200209997cca7a6aed2533b0014929deeb88341516dcb5d01fbd1071681fa566650960000000000010000000000000000000000002710000000000bebc200000000002faf08002458e6936235824897192ae96caea018191fd812bc94f8421b65bd476faf9e30d9000000002b40420f00000000002200209997cca7a6aed2533b0014929deeb88341516dcb5d01fbd1071681fa56665096475221025b9fd5132058bc95861f228b98d7a6b6ff341ae7492e3f91978ed745470d27a62102b90d8c2b072181a56fd6fbd5be9e1f723dee869d79ef4278450b01f09c3fa37f52ae7d020000000158e6936235824897192ae96caea018191fd812bc94f8421b65bd476faf9e30d90000000000deefa28002400d0300000000002200201f9ecd10ef79baef28367302176824ca2a62bd566e18cb705bf5286d2e667eefb8180c000000000016001490c2a2723c9873ec2931c49515e64a610967039e123a44200cebdab89f4b171f63558d1f30e9416b21907adbb0208e7288dfa61bb6b702852ba3acd0569e913ec5d7ef5b6e350d82bac30cfecb08ffffb0742f1948736bbe00000000000000000000000000002710000000002faf0800000000000bebc200a45281427a62b46937d6209986950c76616f874f3d266cb796ec202d441e314302f05e6396357b0a0dc6467f5324760e66eab5dbc0c0875e183742672ddc47ec0a000000ff032af65d7da1b3c4c61145c759eb36296e1b5608c909e0bcd761d1908ac3c571ce00000000000001061a8000002a00000001023976e44871e455ff0289b8c594531eeb0088cdd6527cef83026f1a2ff2e626bdfd94aa2eddd11450b2ab6dca617af53db0c91c81dafe1bbe47757c62eb4709d5f9fb27c456409dff7d1d610aed6ffad1be9a06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f023976e44871e4556605b12f030100900000000000000000000858b800000014000000001dcd650000000001" val nonInitiatorDecoded = channelDataCodec.decode(nonInitiator.bits).require.value.asInstanceOf[DATA_NORMAL] - assert(!nonInitiatorDecoded.commitments.params.localParams.isChannelOpener) - assert(!nonInitiatorDecoded.commitments.params.localParams.paysCommitTxFees) + assert(!nonInitiatorDecoded.commitments.localChannelParams.isChannelOpener) + assert(!nonInitiatorDecoded.commitments.localChannelParams.paysCommitTxFees) } test("encode/decode cold origins") { From 8fbb68427c06f0dbd3a3a3ee9d13bf671f8e14a7 Mon Sep 17 00:00:00 2001 From: t-bast Date: Fri, 20 Jun 2025 17:46:51 +0200 Subject: [PATCH 3/4] Re-work channel update helper We change our channel update helper to make it more compatible with the future `CommitParams` changes. This is a trivial refactoring without any change in behavior. --- .../scala/fr/acinq/eclair/channel/Helpers.scala | 16 ++++++++++++++++ .../fr/acinq/eclair/channel/fsm/Channel.scala | 14 +++++++------- .../channel/fsm/CommonFundingHandlers.scala | 3 +-- .../fr/acinq/eclair/router/Announcements.scala | 8 +------- 4 files changed, 25 insertions(+), 16 deletions(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala index b5305f3b48..451a58c689 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala @@ -328,6 +328,22 @@ object Helpers { } } + def channelUpdate(nodeParams: NodeParams, shortChannelId: ShortChannelId, commitments: Commitments, relayFees: RelayFees, enable: Boolean): ChannelUpdate = { + Announcements.makeChannelUpdate( + chainHash = nodeParams.chainHash, + nodeSecret = nodeParams.privateKey, + remoteNodeId = commitments.remoteNodeId, + shortChannelId = shortChannelId, + cltvExpiryDelta = nodeParams.channelConf.expiryDelta, + htlcMinimumMsat = commitments.latest.remoteCommitParams.htlcMinimum, + feeBaseMsat = relayFees.feeBase, + feeProportionalMillionths = relayFees.feeProportionalMillionths, + htlcMaximumMsat = maxHtlcAmount(nodeParams, commitments), + isPrivate = !commitments.announceChannel, + enable = enable, + ) + } + /** * Compute the delay until we need to refresh the channel_update for our channel not to be considered stale by * other nodes. diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/Channel.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/Channel.scala index 262fc08763..7d040424eb 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/Channel.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/Channel.scala @@ -874,7 +874,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall log.info("announcing channelId={} on the network with shortChannelId={} for fundingTxIndex={}", d.channelId, localAnnSigs.shortChannelId, c.fundingTxIndex) // We generate a new channel_update because we can now use the scid of the announced funding transaction. val scidForChannelUpdate = Helpers.scidForChannelUpdate(Some(channelAnn), d.aliases.localAlias) - val channelUpdate = Announcements.makeChannelUpdate(nodeParams, remoteNodeId, scidForChannelUpdate, d.commitments.channelParams, d.channelUpdate.relayFees, Helpers.maxHtlcAmount(nodeParams, d.commitments), enable = true) + val channelUpdate = Helpers.channelUpdate(nodeParams, scidForChannelUpdate, d.commitments, d.channelUpdate.relayFees, enable = true) context.system.eventStream.publish(ShortChannelIdAssigned(self, d.channelId, Some(channelAnn), d.aliases, remoteNodeId)) // We use goto() instead of stay() because we want to fire transitions. goto(NORMAL) using d.copy(lastAnnouncement_opt = Some(channelAnn), channelUpdate = channelUpdate) storing() @@ -896,7 +896,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall } case Event(c: CMD_UPDATE_RELAY_FEE, d: DATA_NORMAL) => - val channelUpdate1 = Announcements.makeChannelUpdate(nodeParams, remoteNodeId, scidForChannelUpdate(d), d.commitments.channelParams, Relayer.RelayFees(c.feeBase, c.feeProportionalMillionths), Helpers.maxHtlcAmount(nodeParams, d.commitments), enable = true) + val channelUpdate1 = Helpers.channelUpdate(nodeParams, scidForChannelUpdate(d), d.commitments, Relayer.RelayFees(c.feeBase, c.feeProportionalMillionths), enable = true) log.debug(s"updating relay fees: prev={} next={}", d.channelUpdate.toStringShort, channelUpdate1.toStringShort) val replyTo = if (c.replyTo == ActorRef.noSender) sender() else c.replyTo replyTo ! RES_SUCCESS(c, d.channelId) @@ -905,7 +905,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall case Event(BroadcastChannelUpdate(reason), d: DATA_NORMAL) => val age = TimestampSecond.now() - d.channelUpdate.timestamp - val channelUpdate1 = Announcements.makeChannelUpdate(nodeParams, remoteNodeId, scidForChannelUpdate(d), d.commitments.channelParams, d.channelUpdate.relayFees, Helpers.maxHtlcAmount(nodeParams, d.commitments), enable = true) + val channelUpdate1 = Helpers.channelUpdate(nodeParams, scidForChannelUpdate(d), d.commitments, d.channelUpdate.relayFees, enable = true) reason match { case Reconnected if d.commitments.announceChannel && Announcements.areSame(channelUpdate1, d.channelUpdate) && age < REFRESH_CHANNEL_UPDATE_INTERVAL => // we already sent an identical channel_update not long ago (flapping protection in case we keep being disconnected/reconnected) @@ -1499,7 +1499,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall // if we have pending unsigned htlcs, then we cancel them and generate an update with the disabled flag set, that will be returned to the sender in a temporary channel failure if (d.commitments.changes.localChanges.proposed.collectFirst { case add: UpdateAddHtlc => add }.isDefined) { log.debug("updating channel_update announcement (reason=disabled)") - val channelUpdate1 = Announcements.makeChannelUpdate(nodeParams, remoteNodeId, scidForChannelUpdate(d), d.commitments.channelParams, d.channelUpdate.relayFees, Helpers.maxHtlcAmount(nodeParams, d.commitments), enable = false) + val channelUpdate1 = Helpers.channelUpdate(nodeParams, scidForChannelUpdate(d), d.commitments, d.channelUpdate.relayFees, enable = false) // NB: the htlcs stay in the commitments.localChange, they will be cleaned up after reconnection d.commitments.changes.localChanges.proposed.collect { case add: UpdateAddHtlc => relayer ! RES_ADD_SETTLED(d.commitments.originChannels(add.id), add, HtlcResult.DisconnectedBeforeSigned(channelUpdate1)) @@ -3020,7 +3020,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall log.debug("emitting channel down event") if (d.lastAnnouncement_opt.nonEmpty) { // We tell the rest of the network that this channel shouldn't be used anymore. - val disabledUpdate = Announcements.makeChannelUpdate(nodeParams, remoteNodeId, Helpers.scidForChannelUpdate(d), d.commitments.channelParams, d.channelUpdate.relayFees, Helpers.maxHtlcAmount(nodeParams, d.commitments), enable = false) + val disabledUpdate = Helpers.channelUpdate(nodeParams, scidForChannelUpdate(d), d.commitments, d.channelUpdate.relayFees, enable = false) context.system.eventStream.publish(LocalChannelUpdate(self, d.channelId, d.aliases, remoteNodeId, d.lastAnnouncedCommitment_opt, disabledUpdate, d.commitments)) } val lcd = LocalChannelDown(self, d.channelId, d.commitments.all.flatMap(_.shortChannelId_opt), d.aliases, remoteNodeId) @@ -3200,7 +3200,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall if (d.channelUpdate.channelFlags.isEnabled) { // if the channel isn't disabled we generate a new channel_update log.debug("updating channel_update announcement (reason=disabled)") - val channelUpdate1 = Announcements.makeChannelUpdate(nodeParams, remoteNodeId, scidForChannelUpdate(d), d.commitments.channelParams, d.channelUpdate.relayFees, Helpers.maxHtlcAmount(nodeParams, d.commitments), enable = false) + val channelUpdate1 = Helpers.channelUpdate(nodeParams, scidForChannelUpdate(d), d.commitments, d.channelUpdate.relayFees, enable = false) // then we update the state and replay the request self forward c // we use goto() to fire transitions @@ -3213,7 +3213,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall } private def handleUpdateRelayFeeDisconnected(c: CMD_UPDATE_RELAY_FEE, d: DATA_NORMAL) = { - val channelUpdate1 = Announcements.makeChannelUpdate(nodeParams, remoteNodeId, scidForChannelUpdate(d), d.commitments.channelParams, Relayer.RelayFees(c.feeBase, c.feeProportionalMillionths), Helpers.maxHtlcAmount(nodeParams, d.commitments), enable = false) + val channelUpdate1 = Helpers.channelUpdate(nodeParams, scidForChannelUpdate(d), d.commitments, Relayer.RelayFees(c.feeBase, c.feeProportionalMillionths), enable = false) log.debug(s"updating relay fees: prev={} next={}", d.channelUpdate.toStringShort, channelUpdate1.toStringShort) val replyTo = if (c.replyTo == ActorRef.noSender) sender() else c.replyTo replyTo ! RES_SUCCESS(c, d.channelId) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/CommonFundingHandlers.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/CommonFundingHandlers.scala index 513f7bb859..007bf006ab 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/CommonFundingHandlers.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/CommonFundingHandlers.scala @@ -25,7 +25,6 @@ import fr.acinq.eclair.channel.LocalFundingStatus.{ConfirmedFundingTx, DualFunde import fr.acinq.eclair.channel._ import fr.acinq.eclair.channel.fsm.Channel.{BroadcastChannelUpdate, PeriodicRefresh, REFRESH_CHANNEL_UPDATE_INTERVAL} import fr.acinq.eclair.db.RevokedHtlcInfoCleaner -import fr.acinq.eclair.router.Announcements import fr.acinq.eclair.wire.protocol.{AnnouncementSignatures, ChannelReady, ChannelReadyTlv, TlvStream} import fr.acinq.eclair.{RealShortChannelId, ShortChannelId} @@ -138,7 +137,7 @@ trait CommonFundingHandlers extends CommonHandlers { val scidForChannelUpdate = Helpers.scidForChannelUpdate(channelAnnouncement_opt = None, aliases1.localAlias) log.info("using shortChannelId={} for initial channel_update", scidForChannelUpdate) val relayFees = getRelayFees(nodeParams, remoteNodeId, commitments.announceChannel) - val initialChannelUpdate = Announcements.makeChannelUpdate(nodeParams, remoteNodeId, scidForChannelUpdate, commitments.channelParams, relayFees, Helpers.maxHtlcAmount(nodeParams, commitments), enable = true) + val initialChannelUpdate = Helpers.channelUpdate(nodeParams, scidForChannelUpdate, commitments, relayFees, enable = true) // We need to periodically re-send channel updates, otherwise channel will be considered stale and get pruned by network. context.system.scheduler.scheduleWithFixedDelay(initialDelay = REFRESH_CHANNEL_UPDATE_INTERVAL, delay = REFRESH_CHANNEL_UPDATE_INTERVAL, receiver = self, message = BroadcastChannelUpdate(PeriodicRefresh)) val commitments1 = commitments.copy( diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/router/Announcements.scala b/eclair-core/src/main/scala/fr/acinq/eclair/router/Announcements.scala index 80aee61d55..1809e7263b 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/router/Announcements.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/router/Announcements.scala @@ -18,10 +18,8 @@ package fr.acinq.eclair.router import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, PublicKey, sha256, verifySignature} import fr.acinq.bitcoin.scalacompat.{BlockHash, ByteVector64, Crypto, LexicographicalOrdering} -import fr.acinq.eclair.channel.ChannelParams -import fr.acinq.eclair.payment.relay.Relayer.RelayFees import fr.acinq.eclair.wire.protocol._ -import fr.acinq.eclair.{CltvExpiryDelta, Feature, Features, MilliSatoshi, NodeFeature, NodeParams, RealShortChannelId, ShortChannelId, TimestampSecond, TimestampSecondLong, serializationResult} +import fr.acinq.eclair.{CltvExpiryDelta, Feature, Features, MilliSatoshi, NodeFeature, RealShortChannelId, ShortChannelId, TimestampSecond, TimestampSecondLong, serializationResult} import scodec.bits.ByteVector import shapeless.HNil @@ -122,10 +120,6 @@ object Announcements { u1.htlcMinimumMsat == u2.htlcMinimumMsat && u1.htlcMaximumMsat == u2.htlcMaximumMsat - def makeChannelUpdate(nodeParams: NodeParams, remoteNodeId: PublicKey, scid: ShortChannelId, params: ChannelParams, relayFees: RelayFees, maxHtlcAmount: MilliSatoshi, enable: Boolean): ChannelUpdate = { - makeChannelUpdate(nodeParams.chainHash, nodeParams.privateKey, remoteNodeId, scid, nodeParams.channelConf.expiryDelta, params.remoteParams.htlcMinimum, relayFees.feeBase, relayFees.feeProportionalMillionths, maxHtlcAmount, isPrivate = !params.announceChannel, enable) - } - def makeChannelUpdate(chainHash: BlockHash, nodeSecret: PrivateKey, remoteNodeId: PublicKey, shortChannelId: ShortChannelId, cltvExpiryDelta: CltvExpiryDelta, htlcMinimumMsat: MilliSatoshi, feeBaseMsat: MilliSatoshi, feeProportionalMillionths: Long, htlcMaximumMsat: MilliSatoshi, isPrivate: Boolean = false, enable: Boolean = true, timestamp: TimestampSecond = TimestampSecond.now()): ChannelUpdate = { val messageFlags = ChannelUpdate.MessageFlags(isPrivate) val channelFlags = ChannelUpdate.ChannelFlags(isNode1 = isNode1(nodeSecret.publicKey, remoteNodeId), isEnabled = enable) From bef599939065ff4f4ad60bc1c0a55c6113163ccf Mon Sep 17 00:00:00 2001 From: t-bast Date: Wed, 25 Jun 2025 17:43:57 +0200 Subject: [PATCH 4/4] fixup! Split channel params and commit params --- .../src/main/scala/fr/acinq/eclair/channel/Commitments.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala index b9b2798409..399b92e5c7 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala @@ -26,7 +26,7 @@ case class ChannelParams(channelId: ByteVector32, channelFlags: ChannelFlags) { require(channelFeatures.paysDirectlyToWallet == localParams.walletStaticPaymentBasepoint.isDefined, s"localParams.walletStaticPaymentBasepoint must be defined only for commitments that pay directly to our wallet (channel features: $channelFeatures") require(channelFeatures.hasFeature(Features.DualFunding) == localParams.initialRequestedChannelReserve_opt.isEmpty, "custom local channel reserve is incompatible with dual-funded channels") - require(channelFeatures.hasFeature(Features.DualFunding) == localParams.initialRequestedChannelReserve_opt.isEmpty, "custom remote channel reserve is incompatible with dual-funded channels") + require(channelFeatures.hasFeature(Features.DualFunding) == remoteParams.initialRequestedChannelReserve_opt.isEmpty, "custom remote channel reserve is incompatible with dual-funded channels") val commitmentFormat: CommitmentFormat = channelFeatures.commitmentFormat val announceChannel: Boolean = channelFlags.announceChannel