Skip to content

Commit 6fb7ac1

Browse files
authored
Refactor channel params: extract commitment params (#3116)
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.
1 parent 5e829ac commit 6fb7ac1

81 files changed

Lines changed: 994 additions & 978 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

eclair-core/src/main/scala/fr/acinq/eclair/Features.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ object Features {
259259
val mandatory = 26
260260
}
261261

262+
// Note that this is a permanent channel feature because it permanently affects the channel reserve, which is set at 1%.
262263
case object DualFunding extends Feature with InitFeature with NodeFeature with PermanentChannelFeature {
263264
val rfcName = "option_dual_fund"
264265
val mandatory = 28

eclair-core/src/main/scala/fr/acinq/eclair/PluginParams.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import akka.actor.typed.ActorRef
2020
import akka.event.LoggingAdapter
2121
import fr.acinq.bitcoin.scalacompat.{ByteVector32, Satoshi}
2222
import fr.acinq.eclair.channel.Origin
23-
import fr.acinq.eclair.io.OpenChannelInterceptor.{DefaultParams, OpenChannelNonInitiator}
23+
import fr.acinq.eclair.io.OpenChannelInterceptor.OpenChannelNonInitiator
2424
import fr.acinq.eclair.payment.relay.PostRestartHtlcCleaner.IncomingHtlc
2525
import fr.acinq.eclair.wire.protocol.{Error, LiquidityAds}
2626

@@ -61,13 +61,13 @@ trait CustomCommitmentsPlugin extends PluginParams {
6161

6262
// @formatter:off
6363
trait InterceptOpenChannelCommand
64-
case class InterceptOpenChannelReceived(replyTo: ActorRef[InterceptOpenChannelResponse], openChannelNonInitiator: OpenChannelNonInitiator, defaultParams: DefaultParams) extends InterceptOpenChannelCommand {
64+
case class InterceptOpenChannelReceived(replyTo: ActorRef[InterceptOpenChannelResponse], openChannelNonInitiator: OpenChannelNonInitiator) extends InterceptOpenChannelCommand {
6565
val remoteFundingAmount: Satoshi = openChannelNonInitiator.open.fold(_.fundingSatoshis, _.fundingAmount)
6666
val temporaryChannelId: ByteVector32 = openChannelNonInitiator.open.fold(_.temporaryChannelId, _.temporaryChannelId)
6767
}
6868

6969
sealed trait InterceptOpenChannelResponse
70-
case class AcceptOpenChannel(temporaryChannelId: ByteVector32, defaultParams: DefaultParams, addFunding_opt: Option[LiquidityAds.AddFunding]) extends InterceptOpenChannelResponse
70+
case class AcceptOpenChannel(temporaryChannelId: ByteVector32, addFunding_opt: Option[LiquidityAds.AddFunding]) extends InterceptOpenChannelResponse
7171
case class RejectOpenChannel(temporaryChannelId: ByteVector32, error: Error) extends InterceptOpenChannelResponse
7272
// @formatter:on
7373

eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelData.scala

Lines changed: 60 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,12 @@ case object ERR_INFORMATION_LEAK extends ChannelState
9191
8888888888 Y8P 8888888888 888 Y888 888 "Y8888P"
9292
*/
9393

94+
case class ProposedCommitParams(localDustLimit: Satoshi,
95+
localHtlcMinimum: MilliSatoshi,
96+
localMaxHtlcValueInFlight: UInt64,
97+
localMaxAcceptedHtlcs: Int,
98+
toRemoteDelay: CltvExpiryDelta)
99+
94100
case class INPUT_INIT_CHANNEL_INITIATOR(temporaryChannelId: ByteVector32,
95101
fundingAmount: Satoshi,
96102
dualFunded: Boolean,
@@ -100,7 +106,8 @@ case class INPUT_INIT_CHANNEL_INITIATOR(temporaryChannelId: ByteVector32,
100106
pushAmount_opt: Option[MilliSatoshi],
101107
requireConfirmedInputs: Boolean,
102108
requestFunding_opt: Option[LiquidityAds.RequestFunding],
103-
localParams: LocalParams,
109+
localChannelParams: LocalChannelParams,
110+
proposedCommitParams: ProposedCommitParams,
104111
remote: ActorRef,
105112
remoteInit: Init,
106113
channelFlags: ChannelFlags,
@@ -114,7 +121,8 @@ case class INPUT_INIT_CHANNEL_NON_INITIATOR(temporaryChannelId: ByteVector32,
114121
dualFunded: Boolean,
115122
pushAmount_opt: Option[MilliSatoshi],
116123
requireConfirmedInputs: Boolean,
117-
localParams: LocalParams,
124+
localChannelParams: LocalChannelParams,
125+
proposedCommitParams: ProposedCommitParams,
118126
remote: ActorRef,
119127
remoteInit: Init,
120128
channelConfig: ChannelConfig,
@@ -530,7 +538,7 @@ sealed trait ChannelDataWithoutCommitments extends PersistentChannelData {
530538
sealed trait ChannelDataWithCommitments extends PersistentChannelData {
531539
val channelId: ByteVector32 = commitments.channelId
532540
val remoteNodeId: PublicKey = commitments.remoteNodeId
533-
val channelParams: ChannelParams = commitments.params
541+
val channelParams: ChannelParams = commitments.channelParams
534542
def commitments: Commitments
535543
}
536544

@@ -540,24 +548,24 @@ final case class DATA_WAIT_FOR_OPEN_CHANNEL(initFundee: INPUT_INIT_CHANNEL_NON_I
540548
final case class DATA_WAIT_FOR_ACCEPT_CHANNEL(initFunder: INPUT_INIT_CHANNEL_INITIATOR, lastSent: OpenChannel) extends TransientChannelData {
541549
val channelId: ByteVector32 = initFunder.temporaryChannelId
542550
}
543-
final case class DATA_WAIT_FOR_FUNDING_INTERNAL(params: ChannelParams,
551+
final case class DATA_WAIT_FOR_FUNDING_INTERNAL(channelParams: ChannelParams,
544552
fundingAmount: Satoshi,
545553
pushAmount: MilliSatoshi,
546554
commitTxFeerate: FeeratePerKw,
547555
remoteFundingPubKey: PublicKey,
548556
remoteFirstPerCommitmentPoint: PublicKey,
549557
replyTo: akka.actor.typed.ActorRef[Peer.OpenChannelResponse]) extends TransientChannelData {
550-
val channelId: ByteVector32 = params.channelId
558+
val channelId: ByteVector32 = channelParams.channelId
551559
}
552-
final case class DATA_WAIT_FOR_FUNDING_CREATED(params: ChannelParams,
560+
final case class DATA_WAIT_FOR_FUNDING_CREATED(channelParams: ChannelParams,
553561
fundingAmount: Satoshi,
554562
pushAmount: MilliSatoshi,
555563
commitTxFeerate: FeeratePerKw,
556564
remoteFundingPubKey: PublicKey,
557565
remoteFirstPerCommitmentPoint: PublicKey) extends TransientChannelData {
558-
val channelId: ByteVector32 = params.channelId
566+
val channelId: ByteVector32 = channelParams.channelId
559567
}
560-
final case class DATA_WAIT_FOR_FUNDING_SIGNED(params: ChannelParams,
568+
final case class DATA_WAIT_FOR_FUNDING_SIGNED(channelParams: ChannelParams,
561569
remoteFundingPubKey: PublicKey,
562570
fundingTx: Transaction,
563571
fundingTxFee: Satoshi,
@@ -566,7 +574,7 @@ final case class DATA_WAIT_FOR_FUNDING_SIGNED(params: ChannelParams,
566574
remoteCommit: RemoteCommit,
567575
lastSent: FundingCreated,
568576
replyTo: akka.actor.typed.ActorRef[Peer.OpenChannelResponse]) extends TransientChannelData {
569-
val channelId: ByteVector32 = params.channelId
577+
val channelId: ByteVector32 = channelParams.channelId
570578
}
571579
final case class DATA_WAIT_FOR_FUNDING_CONFIRMED(commitments: Commitments,
572580
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,
628636
closingTxProposed: List[List[ClosingTxProposed]], // one list for every negotiation (there can be several in case of disconnection)
629637
bestUnpublishedClosingTx_opt: Option[ClosingTx]) extends ChannelDataWithCommitments {
630638
require(closingTxProposed.nonEmpty, "there must always be a list for the current negotiation")
631-
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")
639+
require(!commitments.localChannelParams.paysClosingFees || closingTxProposed.forall(_.nonEmpty), "initiator must have at least one closing signature for every negotiation attempt because it initiates the closing")
632640
}
633641
final case class DATA_NEGOTIATING_SIMPLE(commitments: Commitments,
634642
lastClosingFeerate: FeeratePerKw,
@@ -656,45 +664,54 @@ final case class DATA_CLOSING(commitments: Commitments,
656664

657665
final case class DATA_WAIT_FOR_REMOTE_PUBLISH_FUTURE_COMMITMENT(commitments: Commitments, remoteChannelReestablish: ChannelReestablish) extends ChannelDataWithCommitments
658666

659-
/**
660-
* @param initFeatures current connection features, or last features used if the channel is disconnected. Note that these
661-
* features are updated at each reconnection and may be different from the channel permanent features
662-
* (see [[ChannelFeatures]]).
663-
*/
664-
case class LocalParams(nodeId: PublicKey,
665-
fundingKeyPath: DeterministicWallet.KeyPath,
666-
dustLimit: Satoshi,
667-
maxHtlcValueInFlightMsat: UInt64,
668-
initialRequestedChannelReserve_opt: Option[Satoshi],
669-
htlcMinimum: MilliSatoshi,
670-
toSelfDelay: CltvExpiryDelta,
671-
maxAcceptedHtlcs: Int,
672-
isChannelOpener: Boolean,
673-
paysCommitTxFees: Boolean,
674-
upfrontShutdownScript_opt: Option[ByteVector],
675-
walletStaticPaymentBasepoint: Option[PublicKey],
676-
initFeatures: Features[InitFeature]) {
667+
case class LocalChannelParams(nodeId: PublicKey,
668+
fundingKeyPath: DeterministicWallet.KeyPath,
669+
dustLimit: Satoshi,
670+
maxHtlcValueInFlightMsat: UInt64,
671+
// Channel reserve applied to the remote peer, if we're not using [[Features.DualFunding]] (in
672+
// which case the reserve is set to 1%). If the channel is spliced, this initial value will be
673+
// ignored in favor of a 1% reserve of the resulting capacity.
674+
initialRequestedChannelReserve_opt: Option[Satoshi],
675+
htlcMinimum: MilliSatoshi,
676+
toRemoteDelay: CltvExpiryDelta,
677+
maxAcceptedHtlcs: Int,
678+
isChannelOpener: Boolean,
679+
paysCommitTxFees: Boolean,
680+
upfrontShutdownScript_opt: Option[ByteVector],
681+
walletStaticPaymentBasepoint: Option[PublicKey],
682+
// Current connection features, or last features used if the channel is disconnected. Note that
683+
// these features are updated at each reconnection and may be different from the channel permanent
684+
// features (see [[ChannelFeatures]]).
685+
initFeatures: Features[InitFeature]) {
677686
// The node responsible for the commit tx fees is also the node paying the mutual close fees.
678687
// The other node's balance may be empty, which wouldn't allow them to pay the closing fees.
679688
val paysClosingFees: Boolean = paysCommitTxFees
680-
}
681689

682-
/**
683-
* @param initFeatures see [[LocalParams.initFeatures]]
684-
*/
685-
case class RemoteParams(nodeId: PublicKey,
686-
dustLimit: Satoshi,
687-
maxHtlcValueInFlightMsat: UInt64,
688-
initialRequestedChannelReserve_opt: Option[Satoshi],
690+
val proposedCommitParams: ProposedCommitParams = ProposedCommitParams(dustLimit, htlcMinimum, maxHtlcValueInFlightMsat, maxAcceptedHtlcs, toRemoteDelay)
691+
}
692+
693+
case class RemoteChannelParams(nodeId: PublicKey,
694+
dustLimit: Satoshi,
695+
maxHtlcValueInFlightMsat: UInt64,
696+
// See comment in LocalChannelParams for details.
697+
initialRequestedChannelReserve_opt: Option[Satoshi],
698+
htlcMinimum: MilliSatoshi,
699+
toRemoteDelay: CltvExpiryDelta,
700+
maxAcceptedHtlcs: Int,
701+
revocationBasepoint: PublicKey,
702+
paymentBasepoint: PublicKey,
703+
delayedPaymentBasepoint: PublicKey,
704+
htlcBasepoint: PublicKey,
705+
// See comment in LocalChannelParams for details.
706+
initFeatures: Features[InitFeature],
707+
upfrontShutdownScript_opt: Option[ByteVector])
708+
709+
/** Configuration parameters that apply to local or remote commitment transactions, and may be updated dynamically. */
710+
case class CommitParams(dustLimit: Satoshi,
689711
htlcMinimum: MilliSatoshi,
690-
toSelfDelay: CltvExpiryDelta,
712+
maxHtlcValueInFlight: UInt64,
691713
maxAcceptedHtlcs: Int,
692-
revocationBasepoint: PublicKey,
693-
paymentBasepoint: PublicKey,
694-
delayedPaymentBasepoint: PublicKey,
695-
htlcBasepoint: PublicKey,
696-
initFeatures: Features[InitFeature],
697-
upfrontShutdownScript_opt: Option[ByteVector])
714+
toSelfDelay: CltvExpiryDelta)
698715

699716
/**
700717
* The [[nonInitiatorPaysCommitFees]] parameter is set to true when the sender wants the receiver to pay the commitment transaction fees.

eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelEvents.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ case class LocalChannelUpdate(channel: ActorRef, channelId: ByteVector32, aliase
6262
* However we only include the real scid if option_scid_alias is disabled, because we otherwise want to hide it.
6363
*/
6464
def scidsForRouting: Seq[ShortChannelId] = {
65-
val canUseRealScid = !commitments.params.channelFeatures.hasFeature(Features.ScidAlias)
65+
val canUseRealScid = !commitments.channelParams.channelFeatures.hasFeature(Features.ScidAlias)
6666
if (canUseRealScid) {
6767
announcement_opt.map(_.shortChannelId).toSeq :+ aliases.localAlias
6868
} else {

0 commit comments

Comments
 (0)