From f0e3985d109785ae4173dbce12780a8157f561ce Mon Sep 17 00:00:00 2001 From: Bastien Teinturier <31281497+t-bast@users.noreply.github.com> Date: Wed, 12 Jun 2024 10:33:35 +0200 Subject: [PATCH] Add `paysCommitTxFees` flag to `LocalParams` (#2845) The channel initiator traditionally pays the commit tx fees, but we may want to override that when providing services to wallet users. We thus split the current `isInitiator` flag into two flags: - `isChannelOpener` - `paysCommitTxFees` We always set `paysCommitTxFees` to the same value as `isChannelOpener`. Custom feature bits may override that behavior if necessary. Note that backwards compatibility is preserved since our previous `bool8` codec encodes `true` as `0xff` and `false` as `0x00`. --- .../fr/acinq/eclair/channel/ChannelData.scala | 15 ++--- .../acinq/eclair/channel/ChannelEvents.scala | 2 +- .../fr/acinq/eclair/channel/Commitments.scala | 32 +++++----- .../fr/acinq/eclair/channel/Helpers.scala | 22 +++---- .../fr/acinq/eclair/channel/fsm/Channel.scala | 46 +++++++------- .../channel/fsm/ChannelOpenDualFunded.scala | 6 +- .../channel/fsm/ChannelOpenSingleFunded.scala | 4 +- .../eclair/channel/fsm/ErrorHandlers.scala | 20 +++---- .../channel/fsm/SingleFundingHandlers.scala | 2 +- .../crypto/keymanager/ChannelKeyManager.scala | 4 +- .../fr/acinq/eclair/db/DbEventHandler.scala | 6 +- .../fr/acinq/eclair/db/pg/PgAuditDb.scala | 2 +- .../eclair/db/sqlite/SqliteAuditDb.scala | 2 +- .../eclair/io/OpenChannelInterceptor.scala | 15 ++--- .../io/PendingChannelsRateLimiter.scala | 10 ++-- .../acinq/eclair/json/JsonSerializers.scala | 2 +- .../eclair/transactions/Transactions.scala | 24 ++++---- .../channel/version0/ChannelCodecs0.scala | 7 ++- .../channel/version1/ChannelCodecs1.scala | 2 +- .../channel/version2/ChannelCodecs2.scala | 2 +- .../channel/version3/ChannelCodecs3.scala | 2 +- .../channel/version4/ChannelCodecs4.scala | 3 +- .../eclair/wire/protocol/CommonCodecs.scala | 2 +- .../fundee-announced/data.json | 3 +- .../000003-DATA_NORMAL/funder/data.json | 3 +- .../funder-announced/data.json | 3 +- .../funder/data.json | 3 +- .../funder/data.json | 3 +- .../funder/data.json | 3 +- .../scala/fr/acinq/eclair/TestConstants.scala | 8 +-- .../eclair/channel/CommitmentsSpec.scala | 6 +- .../fr/acinq/eclair/channel/FuzzySpec.scala | 5 +- .../channel/InteractiveTxBuilderSpec.scala | 8 +-- .../a/WaitForAcceptChannelStateSpec.scala | 5 +- ...tForAcceptDualFundedChannelStateSpec.scala | 4 +- .../a/WaitForOpenChannelStateSpec.scala | 14 ++--- ...aitForOpenDualFundedChannelStateSpec.scala | 10 ++-- .../WaitForDualFundingCreatedStateSpec.scala | 2 +- .../b/WaitForDualFundingSignedStateSpec.scala | 2 +- .../b/WaitForFundingCreatedStateSpec.scala | 2 +- .../b/WaitForFundingInternalStateSpec.scala | 2 +- .../b/WaitForFundingSignedStateSpec.scala | 2 +- ...WaitForDualFundingConfirmedStateSpec.scala | 2 +- .../c/WaitForFundingConfirmedStateSpec.scala | 2 +- .../channel/states/h/ClosingStateSpec.scala | 2 +- .../fr/acinq/eclair/db/AuditDbSpec.scala | 2 +- .../interop/rustytests/RustyTestsSpec.scala | 2 +- .../scala/fr/acinq/eclair/io/PeerSpec.scala | 4 +- .../io/PendingChannelsRateLimiterSpec.scala | 12 ++-- .../eclair/json/JsonSerializersSpec.scala | 5 +- .../eclair/payment/PaymentPacketSpec.scala | 4 +- .../eclair/transactions/TestVectorsSpec.scala | 8 +-- .../transactions/TransactionsSpec.scala | 60 +++++++++---------- .../internal/channel/ChannelCodecsSpec.scala | 5 +- .../channel/version4/ChannelCodecs4Spec.scala | 15 +++++ .../protocol/LightningMessageCodecsSpec.scala | 4 +- .../fr/acinq/eclair/api/ApiServiceSpec.scala | 4 +- 57 files changed, 242 insertions(+), 209 deletions(-) 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 ebc8c7aa5d..0f89da3c8e 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 @@ -601,7 +601,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.isInitiator || closingTxProposed.forall(_.nonEmpty), "initiator must have at least one closing signature for every negotiation attempt because it initiates the closing") + 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") } final case class DATA_CLOSING(commitments: Commitments, waitingSince: BlockHeight, // how long since we initiated the closing @@ -632,10 +632,15 @@ case class LocalParams(nodeId: PublicKey, htlcMinimum: MilliSatoshi, toSelfDelay: CltvExpiryDelta, maxAcceptedHtlcs: Int, - isInitiator: Boolean, + isChannelOpener: Boolean, + paysCommitTxFees: Boolean, upfrontShutdownScript_opt: Option[ByteVector], walletStaticPaymentBasepoint: Option[PublicKey], - initFeatures: Features[InitFeature]) + 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]] @@ -657,10 +662,6 @@ case class RemoteParams(nodeId: PublicKey, case class ChannelFlags(announceChannel: Boolean) { override def toString: String = s"ChannelFlags(announceChannel=$announceChannel)" } -object ChannelFlags { - val Private: ChannelFlags = ChannelFlags(announceChannel = false) - val Public: ChannelFlags = ChannelFlags(announceChannel = true) -} /** Information about what triggered the opening of the channel */ sealed trait ChannelOrigin 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 d106914e32..ff36bd5fb1 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 @@ -31,7 +31,7 @@ import fr.acinq.eclair.{BlockHeight, Features, ShortChannelId} trait ChannelEvent -case class ChannelCreated(channel: ActorRef, peer: ActorRef, remoteNodeId: PublicKey, isInitiator: Boolean, temporaryChannelId: ByteVector32, commitTxFeerate: FeeratePerKw, fundingTxFeerate: Option[FeeratePerKw]) extends ChannelEvent +case class ChannelCreated(channel: ActorRef, peer: ActorRef, remoteNodeId: PublicKey, isOpener: Boolean, temporaryChannelId: ByteVector32, commitTxFeerate: FeeratePerKw, fundingTxFeerate: Option[FeeratePerKw]) extends ChannelEvent // This trait can be used by non-standard channels to inject themselves into Register actor and thus make them usable for routing trait AbstractChannelRestored extends ChannelEvent { 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 f9c8b3db58..0d5aa595e5 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 @@ -320,7 +320,7 @@ case class Commitment(fundingTxIndex: Long, val remoteCommit1 = nextRemoteCommit_opt.map(_.commit).getOrElse(remoteCommit) val reduced = CommitmentSpec.reduce(remoteCommit1.spec, changes.remoteChanges.acked, changes.localChanges.proposed) val balanceNoFees = (reduced.toRemote - localChannelReserve(params)).max(0 msat) - if (localParams.isInitiator) { + 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) // the initiator needs to keep a "funder fee buffer" (see explanation above) @@ -347,7 +347,7 @@ case class Commitment(fundingTxIndex: Long, import params._ val reduced = CommitmentSpec.reduce(localCommit.spec, changes.localChanges.acked, changes.remoteChanges.proposed) val balanceNoFees = (reduced.toRemote - remoteChannelReserve(params)).max(0 msat) - if (localParams.isInitiator) { + if (localParams.paysCommitTxFees) { // The non-initiator doesn't pay on-chain fees so we don't take those into account when receiving. balanceNoFees } else { @@ -456,12 +456,12 @@ case class Commitment(fundingTxIndex: Long, val funderFeeBuffer = commitTxTotalCostMsat(params.remoteParams.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.isInitiator) fees.max(funderFeeBuffer.truncateToSatoshi) else 0.sat) - val missingForReceiver = reduced.toLocal - remoteChannelReserve(params) - (if (params.localParams.isInitiator) 0.sat else fees) + val missingForSender = reduced.toRemote - localChannelReserve(params) - (if (params.localParams.paysCommitTxFees) fees.max(funderFeeBuffer.truncateToSatoshi) else 0.sat) + val missingForReceiver = reduced.toLocal - remoteChannelReserve(params) - (if (params.localParams.paysCommitTxFees) 0.sat else fees) if (missingForSender < 0.msat) { - return Left(InsufficientFunds(params.channelId, amount = amount, missing = -missingForSender.truncateToSatoshi, reserve = localChannelReserve(params), fees = if (params.localParams.isInitiator) fees else 0.sat)) + return Left(InsufficientFunds(params.channelId, amount = amount, missing = -missingForSender.truncateToSatoshi, reserve = localChannelReserve(params), fees = if (params.localParams.paysCommitTxFees) fees else 0.sat)) } else if (missingForReceiver < 0.msat) { - if (params.localParams.isInitiator) { + if (params.localParams.paysCommitTxFees) { // receiver is not the channel initiator; it is ok if it can't maintain its channel_reserve for now, as long as its balance is increasing, which is the case if it is receiving a payment } else if (reduced.toLocal > fees && reduced.htlcs.size < 5 && fundingTxIndex > 0) { // Receiver is the channel initiator; we usually don't want to let them dip into their channel reserve, because @@ -527,15 +527,15 @@ case class Commitment(fundingTxIndex: Long, val fees = commitTxTotalCost(params.localParams.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.isInitiator) 0.sat else fees) + val missingForSender = reduced.toRemote - remoteChannelReserve(params) - (if (params.localParams.paysCommitTxFees) 0.sat else fees) // Note that Bolt 2 requires to also meet our channel reserve requirement, but we're more lenient than that because // as long as we're able to pay the commit tx fee, it's ok if we dip into our channel reserve: we're receiving an // HTLC, which means our balance will increase and meet the channel reserve again. - val missingForReceiver = reduced.toLocal - (if (params.localParams.isInitiator) fees else 0.sat) + val missingForReceiver = reduced.toLocal - (if (params.localParams.paysCommitTxFees) fees else 0.sat) if (missingForSender < 0.sat) { - return Left(InsufficientFunds(params.channelId, amount = amount, missing = -missingForSender.truncateToSatoshi, reserve = remoteChannelReserve(params), fees = if (params.localParams.isInitiator) 0.sat else fees)) + return Left(InsufficientFunds(params.channelId, amount = amount, missing = -missingForSender.truncateToSatoshi, reserve = remoteChannelReserve(params), fees = if (params.localParams.paysCommitTxFees) 0.sat else fees)) } else if (missingForReceiver < 0.sat) { - if (params.localParams.isInitiator) { + if (params.localParams.paysCommitTxFees) { return Left(CannotAffordFees(params.channelId, missing = -missingForReceiver.truncateToSatoshi, reserve = localChannelReserve(params), fees = fees)) } else { // receiver is not the channel initiator; it is ok if it can't maintain its channel_reserve for now, as long as its balance is increasing, which is the case if it is receiving a payment @@ -699,8 +699,8 @@ object Commitment { val remoteHtlcPubkey = Generators.derivePubKey(remoteParams.htlcBasepoint, localPerCommitmentPoint) val localRevocationPubkey = Generators.revocationPubKey(remoteParams.revocationBasepoint, localPerCommitmentPoint) val localPaymentBasepoint = localParams.walletStaticPaymentBasepoint.getOrElse(keyManager.paymentPoint(channelKeyPath).publicKey) - val outputs = makeCommitTxOutputs(localParams.isInitiator, localParams.dustLimit, localRevocationPubkey, remoteParams.toSelfDelay, localDelayedPaymentPubkey, remotePaymentPubkey, localHtlcPubkey, remoteHtlcPubkey, localFundingPubkey, remoteFundingPubKey, spec, channelFeatures.commitmentFormat) - val commitTx = makeCommitTx(commitmentInput, commitTxNumber, localPaymentBasepoint, remoteParams.paymentBasepoint, localParams.isInitiator, outputs) + val outputs = makeCommitTxOutputs(localParams.paysCommitTxFees, localParams.dustLimit, localRevocationPubkey, remoteParams.toSelfDelay, localDelayedPaymentPubkey, remotePaymentPubkey, localHtlcPubkey, remoteHtlcPubkey, localFundingPubkey, remoteFundingPubKey, spec, channelFeatures.commitmentFormat) + val commitTx = makeCommitTx(commitmentInput, commitTxNumber, localPaymentBasepoint, remoteParams.paymentBasepoint, localParams.isChannelOpener, outputs) val htlcTxs = makeHtlcTxs(commitTx.tx, localParams.dustLimit, localRevocationPubkey, remoteParams.toSelfDelay, localDelayedPaymentPubkey, spec.htlcTxFeerate(channelFeatures.commitmentFormat), outputs, channelFeatures.commitmentFormat) (commitTx, htlcTxs) } @@ -728,8 +728,8 @@ object Commitment { val remoteDelayedPaymentPubkey = Generators.derivePubKey(remoteParams.delayedPaymentBasepoint, remotePerCommitmentPoint) val remoteHtlcPubkey = Generators.derivePubKey(remoteParams.htlcBasepoint, remotePerCommitmentPoint) val remoteRevocationPubkey = Generators.revocationPubKey(keyManager.revocationPoint(channelKeyPath).publicKey, remotePerCommitmentPoint) - val outputs = makeCommitTxOutputs(!localParams.isInitiator, remoteParams.dustLimit, remoteRevocationPubkey, localParams.toSelfDelay, remoteDelayedPaymentPubkey, localPaymentPubkey, remoteHtlcPubkey, localHtlcPubkey, remoteFundingPubKey, localFundingPubkey, spec, channelFeatures.commitmentFormat) - val commitTx = makeCommitTx(commitmentInput, commitTxNumber, remoteParams.paymentBasepoint, localPaymentBasepoint, !localParams.isInitiator, outputs) + val outputs = makeCommitTxOutputs(!localParams.paysCommitTxFees, remoteParams.dustLimit, remoteRevocationPubkey, localParams.toSelfDelay, remoteDelayedPaymentPubkey, localPaymentPubkey, remoteHtlcPubkey, localHtlcPubkey, remoteFundingPubKey, localFundingPubkey, spec, channelFeatures.commitmentFormat) + val commitTx = makeCommitTx(commitmentInput, commitTxNumber, remoteParams.paymentBasepoint, localPaymentBasepoint, !localParams.isChannelOpener, outputs) val htlcTxs = makeHtlcTxs(commitTx.tx, remoteParams.dustLimit, remoteRevocationPubkey, localParams.toSelfDelay, remoteDelayedPaymentPubkey, spec.htlcTxFeerate(channelFeatures.commitmentFormat), outputs, channelFeatures.commitmentFormat) (commitTx, htlcTxs) } @@ -960,7 +960,7 @@ case class Commitments(params: ChannelParams, } def sendFee(cmd: CMD_UPDATE_FEE, feeConf: OnChainFeeConf): Either[ChannelException, (Commitments, UpdateFee)] = { - if (!params.localParams.isInitiator) { + if (!params.localParams.paysCommitTxFees) { Left(NonInitiatorCannotSendUpdateFee(channelId)) } else { val fee = UpdateFee(channelId, cmd.feeratePerKw) @@ -976,7 +976,7 @@ case class Commitments(params: ChannelParams, } def receiveFee(fee: UpdateFee, feerates: FeeratesPerKw, feeConf: OnChainFeeConf)(implicit log: LoggingAdapter): Either[ChannelException, Commitments] = { - if (params.localParams.isInitiator) { + if (params.localParams.paysCommitTxFees) { Left(NonInitiatorCannotSendUpdateFee(channelId)) } else if (fee.feeratePerKw < FeeratePerKw.MinimumFeeratePerKw) { Left(FeerateTooSmall(channelId, remoteFeeratePerKw = fee.feeratePerKw)) 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 e84f82f308..d2a55d7f6f 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 @@ -88,7 +88,7 @@ object Helpers { if (nodeParams.chainHash != open.chainHash) return Left(InvalidChainHash(open.temporaryChannelId, local = nodeParams.chainHash, remote = open.chainHash)) // BOLT #2: Channel funding limits - if (open.fundingSatoshis < nodeParams.channelConf.minFundingSatoshis(open.channelFlags.announceChannel)) return Left(FundingAmountTooLow(open.temporaryChannelId, open.fundingSatoshis, nodeParams.channelConf.minFundingSatoshis(open.channelFlags.announceChannel))) + if (open.fundingSatoshis < nodeParams.channelConf.minFundingSatoshis(open.channelFlags)) return Left(FundingAmountTooLow(open.temporaryChannelId, open.fundingSatoshis, nodeParams.channelConf.minFundingSatoshis(open.channelFlags))) if (open.fundingSatoshis >= Channel.MAX_FUNDING_WITHOUT_WUMBO && !localFeatures.hasFeature(Features.Wumbo)) return Left(FundingAmountTooHigh(open.temporaryChannelId, open.fundingSatoshis, Channel.MAX_FUNDING_WITHOUT_WUMBO)) // BOLT #2: The receiving node MUST fail the channel if: push_msat is greater than funding_satoshis * 1000. @@ -138,7 +138,7 @@ object Helpers { if (nodeParams.chainHash != open.chainHash) return Left(InvalidChainHash(open.temporaryChannelId, local = nodeParams.chainHash, remote = open.chainHash)) // BOLT #2: Channel funding limits - if (open.fundingAmount < nodeParams.channelConf.minFundingSatoshis(open.channelFlags.announceChannel)) return Left(FundingAmountTooLow(open.temporaryChannelId, open.fundingAmount, nodeParams.channelConf.minFundingSatoshis(open.channelFlags.announceChannel))) + if (open.fundingAmount < nodeParams.channelConf.minFundingSatoshis(open.channelFlags)) return Left(FundingAmountTooLow(open.temporaryChannelId, open.fundingAmount, nodeParams.channelConf.minFundingSatoshis(open.channelFlags))) if (open.fundingAmount >= Channel.MAX_FUNDING_WITHOUT_WUMBO && !localFeatures.hasFeature(Features.Wumbo)) return Left(FundingAmountTooHigh(open.temporaryChannelId, open.fundingAmount, Channel.MAX_FUNDING_WITHOUT_WUMBO)) // BOLT #2: The receiving node MUST fail the channel if: push_msat is greater than funding_satoshis * 1000. @@ -404,8 +404,8 @@ object Helpers { val localSpec = CommitmentSpec(localHtlcs, commitTxFeerate, toLocal = toLocal, toRemote = toRemote) val remoteSpec = CommitmentSpec(localHtlcs.map(_.opposite), commitTxFeerate, toLocal = toRemote, toRemote = toLocal) - if (!localParams.isInitiator) { - // They initiated the channel open, therefore they pay the fee: we need to make sure they can afford it! + if (!localParams.paysCommitTxFees) { + // They are responsible for paying the commitment transaction fee: we need to make sure they can afford it! // 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. @@ -629,7 +629,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 = Transactions.makeClosingTx(commitment.commitInput, localScriptPubkey, remoteScriptPubkey, commitment.localParams.isInitiator, Satoshi(0), Satoshi(0), commitment.localCommit.spec) + val dummyClosingTx = Transactions.makeClosingTx(commitment.commitInput, localScriptPubkey, remoteScriptPubkey, commitment.localParams.paysClosingFees, Satoshi(0), Satoshi(0), commitment.localCommit.spec) val closingWeight = Transaction.weight(Transactions.addSigs(dummyClosingTx, Transactions.PlaceHolderPubKey, commitment.remoteFundingPubKey, Transactions.PlaceHolderSig, Transactions.PlaceHolderSig).tx) log.info(s"using feerates=$feerates for initial closing tx") feerates.computeFees(closingWeight) @@ -662,7 +662,7 @@ object Helpers { def makeClosingTx(keyManager: ChannelKeyManager, 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 = Transactions.makeClosingTx(commitment.commitInput, localScriptPubkey, remoteScriptPubkey, commitment.localParams.isInitiator, dustLimit, closingFees.preferred, commitment.localCommit.spec) + val closingTx = Transactions.makeClosingTx(commitment.commitInput, localScriptPubkey, remoteScriptPubkey, commitment.localParams.paysClosingFees, dustLimit, closingFees.preferred, commitment.localCommit.spec) val localClosingSig = keyManager.sign(closingTx, keyManager.fundingPublicKey(commitment.localParams.fundingKeyPath, commitment.fundingTxIndex), TxOwner.Local, commitment.params.commitmentFormat) 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}") @@ -720,10 +720,10 @@ object Helpers { } /** Compute the fee paid by a commitment transaction. */ - def commitTxFee(commitInput: InputInfo, commitTx: Transaction, isInitiator: Boolean): Satoshi = { + def commitTxFee(commitInput: InputInfo, commitTx: Transaction, localPaysCommitTxFees: Boolean): Satoshi = { require(commitTx.txIn.size == 1, "transaction must have only one input") require(commitTx.txIn.exists(txIn => txIn.outPoint == commitInput.outPoint), "transaction must spend the funding output") - if (isInitiator) commitInput.txOut.amount - commitTx.txOut.map(_.amount).sum else 0 sat + if (localPaysCommitTxFees) commitInput.txOut.amount - commitTx.txOut.map(_.amount).sum else 0 sat } /** @@ -974,7 +974,7 @@ object Helpers { val remoteRevocationPubkey = Generators.revocationPubKey(keyManager.revocationPoint(channelKeyPath).publicKey, remoteCommit.remotePerCommitmentPoint) val remoteDelayedPaymentPubkey = Generators.derivePubKey(commitment.remoteParams.delayedPaymentBasepoint, remoteCommit.remotePerCommitmentPoint) val localPaymentPubkey = Generators.derivePubKey(keyManager.paymentPoint(channelKeyPath).publicKey, remoteCommit.remotePerCommitmentPoint) - val outputs = makeCommitTxOutputs(!commitment.localParams.isInitiator, commitment.remoteParams.dustLimit, remoteRevocationPubkey, commitment.localParams.toSelfDelay, remoteDelayedPaymentPubkey, localPaymentPubkey, remoteHtlcPubkey, localHtlcPubkey, commitment.remoteFundingPubKey, localFundingPubkey, remoteCommit.spec, commitment.params.commitmentFormat) + val outputs = makeCommitTxOutputs(!commitment.localParams.paysCommitTxFees, commitment.remoteParams.dustLimit, remoteRevocationPubkey, commitment.localParams.toSelfDelay, remoteDelayedPaymentPubkey, localPaymentPubkey, remoteHtlcPubkey, localHtlcPubkey, commitment.remoteFundingPubKey, localFundingPubkey, remoteCommit.spec, commitment.params.commitmentFormat) // we need to use a rather high fee for htlc-claim because we compete with the counterparty val feeratePerKwHtlc = feerates.fast @@ -1043,7 +1043,7 @@ object Helpers { val channelKeyPath = keyManager.keyPath(localParams, channelConfig) val localPaymentPoint = localParams.walletStaticPaymentBasepoint.getOrElse(keyManager.paymentPoint(channelKeyPath).publicKey) // this tx has been published by remote, so we need to invert local/remote params - val txNumber = Transactions.obscuredCommitTxNumber(obscuredTxNumber, !localParams.isInitiator, remoteParams.paymentBasepoint, localPaymentPoint) + val txNumber = Transactions.obscuredCommitTxNumber(obscuredTxNumber, !localParams.isChannelOpener, remoteParams.paymentBasepoint, localPaymentPoint) if (txNumber > 0xffffffffffffL) { // txNumber must be lesser than 48 bits long None @@ -1159,7 +1159,7 @@ object Helpers { val channelKeyPath = keyManager.keyPath(localParams, channelConfig) val localPaymentPoint = localParams.walletStaticPaymentBasepoint.getOrElse(keyManager.paymentPoint(channelKeyPath).publicKey) // this tx has been published by remote, so we need to invert local/remote params - val txNumber = Transactions.obscuredCommitTxNumber(obscuredTxNumber, !localParams.isInitiator, remoteParams.paymentBasepoint, localPaymentPoint) + val txNumber = Transactions.obscuredCommitTxNumber(obscuredTxNumber, !localParams.isChannelOpener, remoteParams.paymentBasepoint, localPaymentPoint) // now we know what commit number this tx is referring to, we can derive the commitment point from the shachain remotePerCommitmentSecrets.getHash(0xFFFFFFFFFFFFL - txNumber) .map(d => PrivateKey(d)) 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 bc9344e808..a890c68541 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 @@ -107,7 +107,7 @@ object Channel { require(0 <= maxHtlcValueInFlightPercent && maxHtlcValueInFlightPercent <= 100, "max-htlc-value-in-flight-percent must be between 0 and 100") require(balanceThresholds.sortBy(_.available) == balanceThresholds, "channel-update.balance-thresholds must be sorted by available-sat") - def minFundingSatoshis(announceChannel: Boolean): Satoshi = if (announceChannel) minFundingPublicSatoshis else minFundingPrivateSatoshis + def minFundingSatoshis(flags: ChannelFlags): Satoshi = if (flags.announceChannel) minFundingPublicSatoshis else minFundingPrivateSatoshis } trait TxPublisherFactory { @@ -239,7 +239,7 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with when(WAIT_FOR_INIT_INTERNAL)(handleExceptions { case Event(input: INPUT_INIT_CHANNEL_INITIATOR, Nothing) => - context.system.eventStream.publish(ChannelCreated(self, peer, remoteNodeId, isInitiator = true, input.temporaryChannelId, input.commitTxFeerate, Some(input.fundingTxFeerate))) + context.system.eventStream.publish(ChannelCreated(self, peer, remoteNodeId, isOpener = true, input.temporaryChannelId, input.commitTxFeerate, Some(input.fundingTxFeerate))) activeConnection = input.remote txPublisher ! SetChannelId(remoteNodeId, input.temporaryChannelId) // We will process the input in the next state differently depending on whether we use dual-funding or not. @@ -250,7 +250,7 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with goto(WAIT_FOR_INIT_SINGLE_FUNDED_CHANNEL) } - case Event(input: INPUT_INIT_CHANNEL_NON_INITIATOR, Nothing) if !input.localParams.isInitiator => + case Event(input: INPUT_INIT_CHANNEL_NON_INITIATOR, Nothing) if !input.localParams.isChannelOpener => activeConnection = input.remote txPublisher ! SetChannelId(remoteNodeId, input.temporaryChannelId) if (input.dualFunded) { @@ -321,7 +321,7 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with context.system.eventStream.publish(ChannelAborted(self, remoteNodeId, closing.channelId)) goto(CLOSED) using closing case closing: DATA_CLOSING => - val isInitiator = closing.commitments.params.localParams.isInitiator + val localPaysClosingFees = closing.commitments.params.localParams.paysClosingFees // we don't put back the WatchSpent if the commitment tx has already been published and the spending tx already reached mindepth val closingType_opt = Closing.isClosingTypeAlreadyKnown(closing) log.info(s"channel is closing (closingType=${closingType_opt.map(c => EventType.Closed(c).label).getOrElse("UnknownYet")})") @@ -331,7 +331,7 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with // - there is a single commitment, the others have all been invalidated closingType_opt match { case Some(c: Closing.MutualClose) => - doPublish(c.tx, isInitiator) + doPublish(c.tx, localPaysClosingFees) case Some(c: Closing.LocalClose) => doPublish(c.localCommitPublished, closing.commitments.latest) case Some(c: Closing.RemoteClose) => @@ -341,7 +341,7 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with case Some(c: Closing.RevokedClose) => doPublish(c.revokedCommitPublished) case None => - closing.mutualClosePublished.foreach(mcp => doPublish(mcp, isInitiator)) + closing.mutualClosePublished.foreach(mcp => doPublish(mcp, localPaysClosingFees)) closing.localCommitPublished.foreach(lcp => doPublish(lcp, closing.commitments.latest)) closing.remoteCommitPublished.foreach(rcp => doPublish(rcp, closing.commitments.latest)) closing.nextRemoteCommitPublished.foreach(rcp => doPublish(rcp, closing.commitments.latest)) @@ -732,8 +732,8 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with // 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 go directly to NEGOTIATING - if (d.commitments.params.localParams.isInitiator) { - // we are the channel initiator, need to initiate the negotiation by sending the first closing_signed + if (d.commitments.params.localParams.paysClosingFees) { + // we pay the closing fees, so we initiate the negotiation by sending the first closing_signed val (closingTx, closingSigned) = Closing.MutualClose.makeFirstClosingTx(keyManager, d.commitments.latest, localShutdown.scriptPubKey, remoteShutdownScript, nodeParams.currentFeerates, nodeParams.onChainFeeConf, d.closingFeerates) goto(NEGOTIATING) using DATA_NEGOTIATING(d.commitments, localShutdown, remoteShutdown, List(List(ClosingTxProposed(closingTx, closingSigned))), bestUnpublishedClosingTx_opt = None) storing() sending sendList :+ closingSigned } else { @@ -901,8 +901,8 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with cmd.replyTo ! RES_FAILURE(cmd, ConcurrentRemoteSplice(d.channelId)) stay() using d.copy(spliceStatus = SpliceStatus.ReceivedStfu(msg)) case SpliceStatus.InitiatorQuiescent(cmd) => - // if both sides send stfu at the same time, the quiescence initiator is the channel initiator - if (!msg.initiator || d.commitments.params.localParams.isInitiator) { + // if both sides send stfu at the same time, the quiescence initiator is the channel opener + if (!msg.initiator || d.commitments.params.localParams.isChannelOpener) { initiateSplice(cmd, d) match { case Left(f) => cmd.replyTo ! RES_FAILURE(cmd, f) @@ -1319,8 +1319,8 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with log.debug("received a new sig:\n{}", commitments1.latest.specs2String) context.system.eventStream.publish(ChannelSignatureReceived(self, commitments1)) if (commitments1.hasNoPendingHtlcsOrFeeUpdate) { - if (d.commitments.params.localParams.isInitiator) { - // we are the channel initiator, need to initiate the negotiation by sending the first closing_signed + if (d.commitments.params.localParams.paysClosingFees) { + // we pay the closing fees, so we initiate the negotiation by sending the first closing_signed val (closingTx, closingSigned) = Closing.MutualClose.makeFirstClosingTx(keyManager, commitments1.latest, localShutdown.scriptPubKey, remoteShutdown.scriptPubKey, nodeParams.currentFeerates, nodeParams.onChainFeeConf, closingFeerates) goto(NEGOTIATING) using DATA_NEGOTIATING(commitments1, localShutdown, remoteShutdown, List(List(ClosingTxProposed(closingTx, closingSigned))), bestUnpublishedClosingTx_opt = None) storing() sending revocation :: closingSigned :: Nil } else { @@ -1361,8 +1361,8 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with } if (commitments1.hasNoPendingHtlcsOrFeeUpdate) { log.debug("switching to NEGOTIATING spec:\n{}", commitments1.latest.specs2String) - if (d.commitments.params.localParams.isInitiator) { - // we are the channel initiator, need to initiate the negotiation by sending the first closing_signed + if (d.commitments.params.localParams.paysClosingFees) { + // we pay the closing fees, so we initiate the negotiation by sending the first closing_signed val (closingTx, closingSigned) = Closing.MutualClose.makeFirstClosingTx(keyManager, commitments1.latest, localShutdown.scriptPubKey, remoteShutdown.scriptPubKey, nodeParams.currentFeerates, nodeParams.onChainFeeConf, closingFeerates) goto(NEGOTIATING) using DATA_NEGOTIATING(commitments1, localShutdown, remoteShutdown, List(List(ClosingTxProposed(closingTx, closingSigned))), bestUnpublishedClosingTx_opt = None) storing() sending closingSigned } else { @@ -1433,8 +1433,8 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with 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.isInitiator => - // if we are not the channel initiator and they proposed a fee range, we pick a value in that range and they should accept it without further negotiation + case Some(ClosingSignedTlv.FeeRange(minFee, maxFee)) if !d.commitments.params.localParams.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 = Closing.MutualClose.firstClosingFee(d.commitments.latest, d.localShutdown.scriptPubKey, d.remoteShutdown.scriptPubKey, nodeParams.currentFeerates, nodeParams.onChainFeeConf) if (maxFee < localClosingFees.min) { @@ -2110,7 +2110,7 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with // 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.isInitiator && !shutdownInProgress) { + if (d.commitments.params.localParams.paysCommitTxFees && !shutdownInProgress) { // TODO: all active commitments use the same feerate, but may have a different channel capacity: how should we compute networkFeeratePerKw? val currentFeeratePerKw = d.commitments.latest.localCommit.spec.commitTxFeerate val networkFeeratePerKw = nodeParams.onChainFeeConf.getCommitmentFeerate(nodeParams.currentFeerates, remoteNodeId, d.commitments.params.commitmentFormat, d.commitments.latest.capacity) @@ -2141,7 +2141,7 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with // 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.isInitiator) { + if (d.commitments.params.localParams.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(keyManager, d.commitments.latest, d.localShutdown.scriptPubKey, d.remoteShutdown.scriptPubKey, nodeParams.currentFeerates, nodeParams.onChainFeeConf, None) val closingTxProposed1 = d.closingTxProposed :+ List(ClosingTxProposed(closingTx, closingSigned)) @@ -2540,8 +2540,8 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with val commitments = d.commitments.latest val networkFeeratePerKw = nodeParams.onChainFeeConf.getCommitmentFeerate(nodeParams.currentFeerates, remoteNodeId, d.commitments.params.commitmentFormat, commitments.capacity) val currentFeeratePerKw = commitments.localCommit.spec.commitTxFeerate - val shouldUpdateFee = d.commitments.params.localParams.isInitiator && nodeParams.onChainFeeConf.shouldUpdateFee(currentFeeratePerKw, networkFeeratePerKw) - val shouldClose = !d.commitments.params.localParams.isInitiator && + 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) && d.commitments.hasPendingOrProposedHtlcs // we close only if we have HTLCs potentially at risk if (shouldUpdateFee) { @@ -2756,9 +2756,11 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with spliceInAmount = cmd.additionalLocalFunding, spliceOut = cmd.spliceOutputs, targetFeerate = targetFeerate) - val commitTxFees = if (d.commitments.params.localParams.isInitiator) { + val commitTxFees = if (d.commitments.params.localParams.paysCommitTxFees) { Transactions.commitTxTotalCost(d.commitments.params.remoteParams.dustLimit, parentCommitment.remoteCommit.spec, d.commitments.params.commitmentFormat) - } else 0.sat + } 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)})") Left(InvalidSpliceRequest(d.channelId)) 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 08651e269b..a13ba920ef 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 @@ -143,7 +143,7 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers { Helpers.validateParamsDualFundedNonInitiator(nodeParams, d.init.channelType, open, remoteNodeId, localParams.initFeatures, remoteInit.features) match { case Left(t) => handleLocalError(t, d, Some(open)) case Right((channelFeatures, remoteShutdownScript)) => - context.system.eventStream.publish(ChannelCreated(self, peer, remoteNodeId, isInitiator = false, open.temporaryChannelId, open.commitmentFeerate, Some(open.fundingFeerate))) + context.system.eventStream.publish(ChannelCreated(self, peer, remoteNodeId, isOpener = false, open.temporaryChannelId, open.commitmentFeerate, Some(open.fundingFeerate))) val remoteParams = RemoteParams( nodeId = remoteNodeId, dustLimit = open.dustLimit, @@ -201,7 +201,7 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers { // We start the interactive-tx funding protocol. val fundingParams = InteractiveTxParams( channelId = channelId, - isInitiator = localParams.isInitiator, + isInitiator = localParams.isChannelOpener, localContribution = accept.fundingAmount, remoteContribution = open.fundingAmount, sharedInput_opt = None, @@ -264,7 +264,7 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers { val remoteAmount = accept.fundingAmount val fundingParams = InteractiveTxParams( channelId = channelId, - isInitiator = localParams.isInitiator, + isInitiator = localParams.isChannelOpener, localContribution = localAmount, remoteContribution = remoteAmount, sharedInput_opt = None, 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 024738c32c..4eaf218f91 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 @@ -109,7 +109,7 @@ trait ChannelOpenSingleFunded extends SingleFundingHandlers with ErrorHandlers { Helpers.validateParamsSingleFundedFundee(nodeParams, d.initFundee.channelType, d.initFundee.localParams.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, isInitiator = false, open.temporaryChannelId, open.feeratePerKw, None)) + context.system.eventStream.publish(ChannelCreated(self, peer, remoteNodeId, isOpener = false, open.temporaryChannelId, open.feeratePerKw, None)) val remoteParams = RemoteParams( nodeId = remoteNodeId, dustLimit = open.dustLimitSatoshis, @@ -380,7 +380,7 @@ 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.isInitiator && + val switchToZeroConf = d.commitments.params.localParams.isChannelOpener && remoteChannelReady.alias_opt.isDefined && !d.commitments.params.localParams.initFeatures.hasFeature(Features.ZeroConf) if (switchToZeroConf) { 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 f8f0687df0..728d3cfa40 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 @@ -55,12 +55,12 @@ 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.isInitiator) + goto(CLOSING) using nextData storing() calling doPublish(closingTx, nextData.commitments.params.localParams.paysClosingFees) } - def doPublish(closingTx: ClosingTx, isInitiator: Boolean): Unit = { + def doPublish(closingTx: ClosingTx, localPaysClosingFees: Boolean): Unit = { // the initiator pays the fee - val fee = if (isInitiator) closingTx.fee else 0.sat + val fee = if (localPaysClosingFees) closingTx.fee else 0.sat txPublisher ! PublishFinalTx(closingTx, fee, None) blockchain ! WatchTxConfirmed(self, closingTx.tx.txid, nodeParams.channelConf.minDepthBlocks) } @@ -212,15 +212,15 @@ trait ErrorHandlers extends CommonHandlers { def doPublish(localCommitPublished: LocalCommitPublished, commitment: FullCommitment): Unit = { import localCommitPublished._ - val isInitiator = commitment.localParams.isInitiator + val localPaysCommitTxFees = commitment.localParams.paysCommitTxFees val publishQueue = commitment.params.commitmentFormat match { case Transactions.DefaultCommitmentFormat => val redeemableHtlcTxs = htlcTxs.values.flatten.map(tx => PublishFinalTx(tx, tx.fee, Some(commitTx.txid))) - List(PublishFinalTx(commitTx, commitment.commitInput.outPoint, "commit-tx", Closing.commitTxFee(commitment.commitInput, commitTx, isInitiator), None)) ++ (claimMainDelayedOutputTx.map(tx => PublishFinalTx(tx, tx.fee, None)) ++ redeemableHtlcTxs ++ claimHtlcDelayedTxs.map(tx => PublishFinalTx(tx, tx.fee, None))) + List(PublishFinalTx(commitTx, commitment.commitInput.outPoint, "commit-tx", Closing.commitTxFee(commitment.commitInput, commitTx, localPaysCommitTxFees), None)) ++ (claimMainDelayedOutputTx.map(tx => PublishFinalTx(tx, tx.fee, None)) ++ redeemableHtlcTxs ++ claimHtlcDelayedTxs.map(tx => PublishFinalTx(tx, tx.fee, None))) case _: Transactions.AnchorOutputsCommitmentFormat => val redeemableHtlcTxs = htlcTxs.values.flatten.map(tx => PublishReplaceableTx(tx, commitment)) val claimLocalAnchor = claimAnchorTxs.collect { case tx: Transactions.ClaimLocalAnchorOutputTx => PublishReplaceableTx(tx, commitment) } - List(PublishFinalTx(commitTx, commitment.commitInput.outPoint, "commit-tx", Closing.commitTxFee(commitment.commitInput, commitTx, isInitiator), None)) ++ claimLocalAnchor ++ claimMainDelayedOutputTx.map(tx => PublishFinalTx(tx, tx.fee, None)) ++ redeemableHtlcTxs ++ claimHtlcDelayedTxs.map(tx => PublishFinalTx(tx, tx.fee, None)) + List(PublishFinalTx(commitTx, commitment.commitInput.outPoint, "commit-tx", Closing.commitTxFee(commitment.commitInput, commitTx, localPaysCommitTxFees), None)) ++ claimLocalAnchor ++ claimMainDelayedOutputTx.map(tx => PublishFinalTx(tx, tx.fee, None)) ++ redeemableHtlcTxs ++ claimHtlcDelayedTxs.map(tx => PublishFinalTx(tx, tx.fee, None)) } publishIfNeeded(publishQueue, irrevocablySpent) @@ -242,7 +242,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.isInitiator), "remote-commit")) + context.system.eventStream.publish(TransactionPublished(d.channelId, remoteNodeId, commitTx, Closing.commitTxFee(commitments.commitInput, commitTx, d.commitments.params.localParams.paysCommitTxFees), "remote-commit")) val remoteCommitPublished = Closing.RemoteClose.claimCommitTxOutputs(keyManager, commitments, commitments.remoteCommit, commitTx, nodeParams.currentFeerates, nodeParams.onChainFeeConf, finalScriptPubKey) val nextData = d match { case closing: DATA_CLOSING => closing.copy(remoteCommitPublished = Some(remoteCommitPublished)) @@ -260,7 +260,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.isInitiator), "next-remote-commit")) + context.system.eventStream.publish(TransactionPublished(d.channelId, remoteNodeId, commitTx, Closing.commitTxFee(commitment.commitInput, commitTx, d.commitments.params.localParams.paysCommitTxFees), "next-remote-commit")) val remoteCommitPublished = Closing.RemoteClose.claimCommitTxOutputs(keyManager, commitment, remoteCommit, commitTx, nodeParams.currentFeerates, nodeParams.onChainFeeConf, finalScriptPubKey) val nextData = d match { case closing: DATA_CLOSING => closing.copy(nextRemoteCommitPublished = Some(remoteCommitPublished)) @@ -298,7 +298,7 @@ trait ErrorHandlers extends CommonHandlers { case Some((commitmentNumber, remotePerCommitmentSecret)) => val revokedCommitPublished = Closing.RevokedClose.claimCommitTxOutputs(keyManager, d.commitments.params, tx, commitmentNumber, remotePerCommitmentSecret, nodeParams.db.channels, nodeParams.currentFeerates, nodeParams.onChainFeeConf, finalScriptPubKey) log.warning(s"txid=${tx.txid} was a revoked commitment, publishing the penalty tx") - context.system.eventStream.publish(TransactionPublished(d.channelId, remoteNodeId, tx, Closing.commitTxFee(commitment.commitInput, tx, d.commitments.params.localParams.isInitiator), "revoked-commit")) + context.system.eventStream.publish(TransactionPublished(d.channelId, remoteNodeId, tx, Closing.commitTxFee(commitment.commitInput, tx, d.commitments.params.localParams.paysCommitTxFees), "revoked-commit")) val exc = FundingTxSpent(d.channelId, tx.txid) val error = Error(d.channelId, exc.getMessage) val nextData = d match { @@ -311,7 +311,7 @@ trait ErrorHandlers extends CommonHandlers { case None => d match { case d: DATA_WAIT_FOR_REMOTE_PUBLISH_FUTURE_COMMITMENT => log.warning(s"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.isInitiator), "future-remote-commit")) + context.system.eventStream.publish(TransactionPublished(d.channelId, remoteNodeId, tx, Closing.commitTxFee(d.commitments.latest.commitInput, tx, d.commitments.latest.localParams.paysCommitTxFees), "future-remote-commit")) val remotePerCommitmentPoint = d.remoteChannelReestablish.myCurrentPerCommitmentPoint val remoteCommitPublished = RemoteCommitPublished( commitTx = tx, diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/SingleFundingHandlers.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/SingleFundingHandlers.scala index 5e174b57a4..9cb594ca8a 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/SingleFundingHandlers.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/SingleFundingHandlers.scala @@ -115,7 +115,7 @@ trait SingleFundingHandlers extends CommonFundingHandlers { } def singleFundingMinDepth(d: ChannelDataWithCommitments): Long = { - val minDepth_opt = if (d.commitments.params.localParams.isInitiator) { + val minDepth_opt = if (d.commitments.params.localParams.isChannelOpener) { d.commitments.params.minDepthFunder } else { // when we're not the channel initiator we scale the min_depth confirmations depending on the funding amount diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/crypto/keymanager/ChannelKeyManager.scala b/eclair-core/src/main/scala/fr/acinq/eclair/crypto/keymanager/ChannelKeyManager.scala index 451d82269f..c0f1e7c725 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/crypto/keymanager/ChannelKeyManager.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/crypto/keymanager/ChannelKeyManager.scala @@ -52,12 +52,12 @@ trait ChannelKeyManager { } /** - * @param isInitiator true if we initiated the channel open + * @param isChannelOpener true if we initiated the channel open * @return a partial key path for a new funding public key. This key path will be extended: * - with a specific "chain" prefix * - with a specific "funding pubkey" suffix */ - def newFundingKeyPath(isInitiator: Boolean): DeterministicWallet.KeyPath + def newFundingKeyPath(isChannelOpener: Boolean): DeterministicWallet.KeyPath /** * @param tx input transaction 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 e241db7a47..0a66c56b43 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 @@ -116,7 +116,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.isInitiator, !commitments.announceChannel, event)) + auditDb.add(ChannelEvent(channelId, remoteNodeId, commitments.latest.capacity, commitments.params.localParams.isChannelOpener, !commitments.announceChannel, event)) channelsDb.updateChannelMeta(channelId, event) case ChannelStateChanged(_, _, _, _, WAIT_FOR_INIT_INTERNAL, _, _) => case ChannelStateChanged(_, channelId, _, _, OFFLINE, SYNCING, _) => @@ -130,7 +130,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.isInitiator, !e.commitments.announceChannel, event)) + auditDb.add(ChannelEvent(e.channelId, e.commitments.params.remoteParams.nodeId, capacity, e.commitments.params.localParams.isChannelOpener, !e.commitments.announceChannel, event)) channelsDb.updateChannelMeta(e.channelId, event) case u: ChannelUpdateParametersChanged => @@ -158,7 +158,7 @@ object DbEventHandler { def props(nodeParams: NodeParams): Props = Props(new DbEventHandler(nodeParams)) // @formatter:off - case class ChannelEvent(channelId: ByteVector32, remoteNodeId: PublicKey, capacity: Satoshi, isInitiator: Boolean, isPrivate: Boolean, event: ChannelEvent.EventType) + case class ChannelEvent(channelId: ByteVector32, remoteNodeId: PublicKey, capacity: Satoshi, isChannelOpener: Boolean, isPrivate: Boolean, event: ChannelEvent.EventType) object ChannelEvent { sealed trait EventType { def label: String } object EventType { diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/db/pg/PgAuditDb.scala b/eclair-core/src/main/scala/fr/acinq/eclair/db/pg/PgAuditDb.scala index 0b62cb7af3..b7af1fa566 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/db/pg/PgAuditDb.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/db/pg/PgAuditDb.scala @@ -188,7 +188,7 @@ class PgAuditDb(implicit ds: DataSource) extends AuditDb with Logging { statement.setString(1, e.channelId.toHex) statement.setString(2, e.remoteNodeId.value.toHex) statement.setLong(3, e.capacity.toLong) - statement.setBoolean(4, e.isInitiator) + statement.setBoolean(4, e.isChannelOpener) statement.setBoolean(5, e.isPrivate) statement.setString(6, e.event.label) statement.setTimestamp(7, Timestamp.from(Instant.now())) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqliteAuditDb.scala b/eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqliteAuditDb.scala index 81c0da3e77..9b418451bc 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqliteAuditDb.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqliteAuditDb.scala @@ -182,7 +182,7 @@ class SqliteAuditDb(val sqlite: Connection) extends AuditDb with Logging { statement.setBytes(1, e.channelId.toArray) statement.setBytes(2, e.remoteNodeId.value.toArray) statement.setLong(3, e.capacity.toLong) - statement.setBoolean(4, e.isInitiator) + statement.setBoolean(4, e.isChannelOpener) statement.setBoolean(5, e.isPrivate) statement.setString(6, e.event.label) statement.setLong(7, TimestampMilli.now().toLong) 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 2a2d379164..f7b8a32a0c 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 @@ -82,7 +82,7 @@ object OpenChannelInterceptor { } } - def makeChannelParams(nodeParams: NodeParams, initFeatures: Features[InitFeature], upfrontShutdownScript_opt: Option[ByteVector], walletStaticPaymentBasepoint_opt: Option[PublicKey], isInitiator: Boolean, dualFunded: Boolean, fundingAmount: Satoshi, unlimitedMaxHtlcValueInFlight: Boolean): LocalParams = { + def makeChannelParams(nodeParams: NodeParams, initFeatures: Features[InitFeature], upfrontShutdownScript_opt: Option[ByteVector], walletStaticPaymentBasepoint_opt: Option[PublicKey], isChannelOpener: Boolean, dualFunded: Boolean, fundingAmount: Satoshi, unlimitedMaxHtlcValueInFlight: Boolean): LocalParams = { val maxHtlcValueInFlightMsat = if (unlimitedMaxHtlcValueInFlight) { // We don't want to impose limits on the amount in flight, typically to allow fully emptying the channel. 21e6.btc.toMilliSatoshi @@ -94,14 +94,15 @@ object OpenChannelInterceptor { } LocalParams( nodeParams.nodeId, - nodeParams.channelKeyManager.newFundingKeyPath(isInitiator), // we make sure that initiator and non-initiator key paths end differently + nodeParams.channelKeyManager.newFundingKeyPath(isChannelOpener), // we make sure that opener and non-opener key paths end differently dustLimit = nodeParams.channelConf.dustLimit, maxHtlcValueInFlightMsat = maxHtlcValueInFlightMsat, 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 maxAcceptedHtlcs = nodeParams.channelConf.maxAcceptedHtlcs, - isInitiator = isInitiator, + isChannelOpener = isChannelOpener, + paysCommitTxFees = isChannelOpener, upfrontShutdownScript_opt = upfrontShutdownScript_opt, walletStaticPaymentBasepoint = walletStaticPaymentBasepoint_opt, initFeatures = initFeatures @@ -139,7 +140,7 @@ private class OpenChannelInterceptor(peer: ActorRef[Any], val channelType = request.open.channelType_opt.getOrElse(ChannelTypes.defaultFromFeatures(request.localFeatures, request.remoteFeatures, channelFlags.announceChannel)) val dualFunded = Features.canUseFeature(request.localFeatures, request.remoteFeatures, Features.DualFunding) val upfrontShutdownScript = Features.canUseFeature(request.localFeatures, request.remoteFeatures, Features.UpfrontShutdownScript) - val localParams = createLocalParams(nodeParams, request.localFeatures, upfrontShutdownScript, channelType, isInitiator = true, dualFunded = dualFunded, request.open.fundingAmount, request.open.disableMaxHtlcValueInFlight) + val localParams = createLocalParams(nodeParams, request.localFeatures, upfrontShutdownScript, channelType, isChannelOpener = true, dualFunded = dualFunded, request.open.fundingAmount, request.open.disableMaxHtlcValueInFlight) peer ! Peer.SpawnChannelInitiator(request.replyTo, request.open, ChannelConfig.standard, channelType, localParams) waitForRequest() } @@ -150,7 +151,7 @@ private class OpenChannelInterceptor(peer: ActorRef[Any], case Right(channelType) => val dualFunded = Features.canUseFeature(request.localFeatures, request.remoteFeatures, Features.DualFunding) val upfrontShutdownScript = Features.canUseFeature(request.localFeatures, request.remoteFeatures, Features.UpfrontShutdownScript) - val localParams = createLocalParams(nodeParams, request.localFeatures, upfrontShutdownScript, channelType, isInitiator = false, dualFunded = dualFunded, request.fundingAmount, disableMaxHtlcValueInFlight = false) + val localParams = createLocalParams(nodeParams, request.localFeatures, upfrontShutdownScript, channelType, isChannelOpener = false, dualFunded = dualFunded, request.fundingAmount, disableMaxHtlcValueInFlight = false) checkRateLimits(request, channelType, localParams) case Left(ex) => context.log.warn(s"ignoring remote channel open: ${ex.getMessage}") @@ -236,13 +237,13 @@ private class OpenChannelInterceptor(peer: ActorRef[Any], } } - private def createLocalParams(nodeParams: NodeParams, initFeatures: Features[InitFeature], upfrontShutdownScript: Boolean, channelType: SupportedChannelType, isInitiator: Boolean, dualFunded: Boolean, fundingAmount: Satoshi, disableMaxHtlcValueInFlight: Boolean): LocalParams = { + private def createLocalParams(nodeParams: NodeParams, initFeatures: Features[InitFeature], upfrontShutdownScript: Boolean, channelType: SupportedChannelType, isChannelOpener: Boolean, dualFunded: Boolean, fundingAmount: Satoshi, disableMaxHtlcValueInFlight: Boolean): LocalParams = { val pubkey_opt = if (upfrontShutdownScript || channelType.paysDirectlyToWallet) Some(wallet.getP2wpkhPubkey()) else None makeChannelParams( nodeParams, initFeatures, if (upfrontShutdownScript) Some(Script.write(Script.pay2wpkh(pubkey_opt.get))) else None, if (channelType.paysDirectlyToWallet) Some(pubkey_opt.get) else None, - isInitiator = isInitiator, + isChannelOpener = isChannelOpener, dualFunded = dualFunded, fundingAmount, disableMaxHtlcValueInFlight 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 61df2fdd23..a480cec083 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.isInitiator => true - case d: DATA_WAIT_FOR_DUAL_FUNDING_SIGNED if !d.channelParams.localParams.isInitiator => true - case d: DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED if !d.commitments.params.localParams.isInitiator => true - case d: DATA_WAIT_FOR_CHANNEL_READY if !d.commitments.params.localParams.isInitiator => true - case d: DATA_WAIT_FOR_DUAL_FUNDING_READY if !d.commitments.params.localParams.isInitiator => true + case d: DATA_WAIT_FOR_FUNDING_CONFIRMED if !d.commitments.params.localParams.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 _ => false }.groupBy(_.remoteNodeId) } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/json/JsonSerializers.scala b/eclair-core/src/main/scala/fr/acinq/eclair/json/JsonSerializers.scala index 1b03f65614..68599be5ac 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/json/JsonSerializers.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/json/JsonSerializers.scala @@ -489,7 +489,7 @@ object ChannelEventSerializer extends MinimalSerializer({ case e: ChannelCreated => JObject( JField("type", JString("channel-created")), JField("remoteNodeId", JString(e.remoteNodeId.toString())), - JField("isInitiator", JBool(e.isInitiator)), + JField("isOpener", JBool(e.isOpener)), JField("temporaryChannelId", JString(e.temporaryChannelId.toHex)), JField("commitTxFeeratePerKw", JLong(e.commitTxFeerate.toLong)), JField("fundingTxFeeratePerKw", e.fundingTxFeerate.map(f => JLong(f.toLong)).getOrElse(JNothing)) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/transactions/Transactions.scala b/eclair-core/src/main/scala/fr/acinq/eclair/transactions/Transactions.scala index 764648ebd1..286a93dafe 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/transactions/Transactions.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/transactions/Transactions.scala @@ -300,14 +300,14 @@ object Transactions { /** * @param commitTxNumber commit tx number - * @param isInitiator true if local node initiated the channel open + * @param localIsChannelOpener true if local node initiated the channel open * @param localPaymentBasePoint local payment base point * @param remotePaymentBasePoint remote payment base point * @return the obscured tx number as defined in BOLT #3 (a 48 bits integer) */ - def obscuredCommitTxNumber(commitTxNumber: Long, isInitiator: Boolean, localPaymentBasePoint: PublicKey, remotePaymentBasePoint: PublicKey): Long = { + def obscuredCommitTxNumber(commitTxNumber: Long, localIsChannelOpener: Boolean, localPaymentBasePoint: PublicKey, remotePaymentBasePoint: PublicKey): Long = { // from BOLT 3: SHA256(payment-basepoint from open_channel || payment-basepoint from accept_channel) - val h = if (isInitiator) { + val h = if (localIsChannelOpener) { Crypto.sha256(localPaymentBasePoint.value ++ remotePaymentBasePoint.value) } else { Crypto.sha256(remotePaymentBasePoint.value ++ localPaymentBasePoint.value) @@ -318,14 +318,14 @@ object Transactions { /** * @param commitTx commit tx - * @param isInitiator true if local node initiated the channel open + * @param localIsChannelOpener true if local node initiated the channel open * @param localPaymentBasePoint local payment base point * @param remotePaymentBasePoint remote payment base point * @return the actual commit tx number that was blinded and stored in locktime and sequence fields */ - def getCommitTxNumber(commitTx: Transaction, isInitiator: Boolean, localPaymentBasePoint: PublicKey, remotePaymentBasePoint: PublicKey): Long = { + def getCommitTxNumber(commitTx: Transaction, localIsChannelOpener: Boolean, localPaymentBasePoint: PublicKey, remotePaymentBasePoint: PublicKey): Long = { require(commitTx.txIn.size == 1, "commitment tx should have 1 input") - val blind = obscuredCommitTxNumber(0, isInitiator, localPaymentBasePoint, remotePaymentBasePoint) + val blind = obscuredCommitTxNumber(0, localIsChannelOpener, localPaymentBasePoint, remotePaymentBasePoint) val obscured = decodeTxNumber(commitTx.txIn.head.sequence, commitTx.lockTime) obscured ^ blind } @@ -373,7 +373,7 @@ object Transactions { } } - def makeCommitTxOutputs(localIsInitiator: Boolean, + def makeCommitTxOutputs(localPaysCommitTxFees: Boolean, localDustLimit: Satoshi, localRevocationPubkey: PublicKey, toLocalDelay: CltvExpiryDelta, @@ -399,7 +399,7 @@ object Transactions { val hasHtlcs = outputs.nonEmpty - val (toLocalAmount: Satoshi, toRemoteAmount: Satoshi) = if (localIsInitiator) { + val (toLocalAmount: Satoshi, toRemoteAmount: Satoshi) = if (localPaysCommitTxFees) { (spec.toLocal.truncateToSatoshi - commitTxTotalCost(localDustLimit, spec, commitmentFormat), spec.toRemote.truncateToSatoshi) } else { (spec.toLocal.truncateToSatoshi, spec.toRemote.truncateToSatoshi - commitTxTotalCost(localDustLimit, spec, commitmentFormat)) @@ -443,9 +443,9 @@ object Transactions { commitTxNumber: Long, localPaymentBasePoint: PublicKey, remotePaymentBasePoint: PublicKey, - localIsInitiator: Boolean, + localIsChannelOpener: Boolean, outputs: CommitmentOutputs): CommitTx = { - val txNumber = obscuredCommitTxNumber(commitTxNumber, localIsInitiator, localPaymentBasePoint, remotePaymentBasePoint) + val txNumber = obscuredCommitTxNumber(commitTxNumber, localIsChannelOpener, localPaymentBasePoint, remotePaymentBasePoint) val (sequence, lockTime) = encodeTxNumber(txNumber) val tx = Transaction( @@ -793,10 +793,10 @@ object Transactions { } } - def makeClosingTx(commitTxInput: InputInfo, localScriptPubKey: ByteVector, remoteScriptPubKey: ByteVector, localIsInitiator: Boolean, dustLimit: Satoshi, closingFee: Satoshi, spec: CommitmentSpec): ClosingTx = { + def makeClosingTx(commitTxInput: InputInfo, localScriptPubKey: ByteVector, remoteScriptPubKey: ByteVector, localPaysClosingFees: Boolean, dustLimit: Satoshi, closingFee: Satoshi, spec: CommitmentSpec): ClosingTx = { require(spec.htlcs.isEmpty, "there shouldn't be any pending htlcs") - val (toLocalAmount: Satoshi, toRemoteAmount: Satoshi) = if (localIsInitiator) { + val (toLocalAmount: Satoshi, toRemoteAmount: Satoshi) = if (localPaysClosingFees) { (spec.toLocal.truncateToSatoshi - closingFee, spec.toRemote.truncateToSatoshi) } else { (spec.toLocal.truncateToSatoshi, spec.toRemote.truncateToSatoshi - closingFee) 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 ddf1ededb5..76590c63ba 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 @@ -18,7 +18,7 @@ package fr.acinq.eclair.wire.internal.channel.version0 import com.softwaremill.quicklens.{ModifyPimp, QuicklensAt} import fr.acinq.bitcoin.scalacompat.DeterministicWallet.KeyPath -import fr.acinq.bitcoin.scalacompat.{ByteVector32, ByteVector64, Crypto, OutPoint, Transaction, TxId, TxOut} +import fr.acinq.bitcoin.scalacompat.{ByteVector64, Crypto, OutPoint, Transaction, TxId, TxOut} import fr.acinq.eclair.blockchain.fee.ConfirmationTarget import fr.acinq.eclair.channel.LocalFundingStatus.SingleFundedUnconfirmedFundingTx import fr.acinq.eclair.channel._ @@ -69,7 +69,10 @@ private[channel] object ChannelCodecs0 { ("isInitiator" | bool) :: ("upfrontShutdownScript_opt" | varsizebinarydata.map(Option(_)).decodeOnly) :: ("walletStaticPaymentBasepoint" | optional(provide(channelVersion.paysDirectlyToWallet), publicKey)) :: - ("features" | combinedFeaturesCodec)).as[LocalParams].decodeOnly + ("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) + }.decodeOnly val remoteParamsCodec: Codec[ChannelTypes0.RemoteParams] = ( ("nodeId" | publicKey) :: 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 9525aa4d7e..2a4f010859 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 @@ -53,7 +53,7 @@ private[channel] object ChannelCodecs1 { ("htlcMinimum" | millisatoshi) :: ("toSelfDelay" | cltvExpiryDelta) :: ("maxAcceptedHtlcs" | uint16) :: - ("isInitiator" | bool8) :: + ("isChannelOpener" | bool) :: ("paysCommitTxFees" | bool) :: ignore(6) :: ("upfrontShutdownScript_opt" | lengthDelimited(bytes).map(Option(_)).decodeOnly) :: ("walletStaticPaymentBasepoint" | optional(provide(channelVersion.paysDirectlyToWallet), publicKey)) :: ("features" | combinedFeaturesCodec)).as[LocalParams].decodeOnly 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 f26c0adf76..1a1bfd72bf 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 @@ -62,7 +62,7 @@ private[channel] object ChannelCodecs2 { ("htlcMinimum" | millisatoshi) :: ("toSelfDelay" | cltvExpiryDelta) :: ("maxAcceptedHtlcs" | uint16) :: - ("isInitiator" | bool8) :: + ("isChannelOpener" | bool) :: ("paysCommitTxFees" | bool) :: ignore(6) :: ("upfrontShutdownScript_opt" | lengthDelimited(bytes).map(Option(_)).decodeOnly) :: ("walletStaticPaymentBasepoint" | optional(provide(channelVersion.paysDirectlyToWallet), publicKey)) :: ("features" | combinedFeaturesCodec)).as[LocalParams] 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 f9f2309839..5bb90acdf8 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 @@ -74,7 +74,7 @@ private[channel] object ChannelCodecs3 { ("htlcMinimum" | millisatoshi) :: ("toSelfDelay" | cltvExpiryDelta) :: ("maxAcceptedHtlcs" | uint16) :: - ("isInitiator" | bool8) :: + ("isChannelOpener" | bool) :: ("paysCommitTxFees" | bool) :: ignore(6) :: ("upfrontShutdownScript_opt" | lengthDelimited(bytes).map(Option(_)).decodeOnly) :: ("walletStaticPaymentBasepoint" | optional(provide(channelFeatures.paysDirectlyToWallet), publicKey)) :: ("features" | combinedFeaturesCodec)).as[LocalParams] 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 e8be2ded6e..c698821995 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 @@ -58,7 +58,8 @@ private[channel] object ChannelCodecs4 { ("htlcMinimum" | millisatoshi) :: ("toSelfDelay" | cltvExpiryDelta) :: ("maxAcceptedHtlcs" | uint16) :: - ("isInitiator" | bool8) :: + // We pad to keep codecs byte-aligned. + ("isChannelOpener" | bool) :: ("paysCommitTxFees" | bool) :: ignore(6) :: ("upfrontShutdownScript_opt" | optional(bool8, lengthDelimited(bytes))) :: ("walletStaticPaymentBasepoint" | optional(provide(channelFeatures.paysDirectlyToWallet), publicKey)) :: ("features" | combinedFeaturesCodec)).as[LocalParams] diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/CommonCodecs.scala b/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/CommonCodecs.scala index e86e8da2bc..812cf0f8a6 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/CommonCodecs.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/CommonCodecs.scala @@ -118,7 +118,7 @@ object CommonCodecs { val listofsignatures: Codec[List[ByteVector64]] = listOfN(uint16, bytes64) - val channelflags: Codec[ChannelFlags] = (ignore(7) dropLeft bool).as[ChannelFlags] + val channelflags: Codec[ChannelFlags] = (ignore(7) :: bool).as[ChannelFlags] val ipv4address: Codec[Inet4Address] = bytes(4).xmap(b => InetAddress.getByAddress(b.toArray).asInstanceOf[Inet4Address], a => ByteVector(a.getAddress)) diff --git a/eclair-core/src/test/resources/nonreg/codecs/000003-DATA_NORMAL/fundee-announced/data.json b/eclair-core/src/test/resources/nonreg/codecs/000003-DATA_NORMAL/fundee-announced/data.json index 00d875c4ee..210eb3a609 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/000003-DATA_NORMAL/fundee-announced/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/000003-DATA_NORMAL/fundee-announced/data.json @@ -14,7 +14,8 @@ "htlcMinimum" : 1, "toSelfDelay" : 720, "maxAcceptedHtlcs" : 30, - "isInitiator" : false, + "isChannelOpener" : false, + "paysCommitTxFees" : false, "upfrontShutdownScript_opt" : "a9144805d016e47885dc7c852710cdd8cd0d576f57ec87", "initFeatures" : { "activated" : { 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 3c90ba13fb..23be54ff36 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 @@ -14,7 +14,8 @@ "htlcMinimum" : 1, "toSelfDelay" : 144, "maxAcceptedHtlcs" : 30, - "isInitiator" : true, + "isChannelOpener" : true, + "paysCommitTxFees" : true, "upfrontShutdownScript_opt" : "a91445e990148599176534ec9b75df92ace9263f7d3487", "initFeatures" : { "activated" : { diff --git a/eclair-core/src/test/resources/nonreg/codecs/020002-DATA_NORMAL/funder-announced/data.json b/eclair-core/src/test/resources/nonreg/codecs/020002-DATA_NORMAL/funder-announced/data.json index 4ba8767fc9..e8c2b8d4cc 100644 --- a/eclair-core/src/test/resources/nonreg/codecs/020002-DATA_NORMAL/funder-announced/data.json +++ b/eclair-core/src/test/resources/nonreg/codecs/020002-DATA_NORMAL/funder-announced/data.json @@ -14,7 +14,8 @@ "htlcMinimum" : 1, "toSelfDelay" : 720, "maxAcceptedHtlcs" : 30, - "isInitiator" : true, + "isChannelOpener" : true, + "paysCommitTxFees" : true, "upfrontShutdownScript_opt" : "00148061b7fbd2d84ed1884177ea785faecb2080b103", "walletStaticPaymentBasepoint" : "02e56c8eca8d4f00df84ac34c23f49c006d57d316b7ada5c346e9d4211e11604b3", "initFeatures" : { 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 7b02159dde..523ee80d57 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 @@ -14,7 +14,8 @@ "htlcMinimum" : 0, "toSelfDelay" : 144, "maxAcceptedHtlcs" : 100, - "isInitiator" : true, + "isChannelOpener" : true, + "paysCommitTxFees" : true, "upfrontShutdownScript_opt" : "0014fec406ef7a0258cb503fe1f1803787d971eeb4d1", "initFeatures" : { "activated" : { 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 9840ceaf33..eed458f18f 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 @@ -14,7 +14,8 @@ "htlcMinimum" : 0, "toSelfDelay" : 144, "maxAcceptedHtlcs" : 100, - "isInitiator" : true, + "isChannelOpener" : true, + "paysCommitTxFees" : true, "upfrontShutdownScript_opt" : "0014c59265957886e166f37c863dca15b49aa42d75b4", "initFeatures" : { "activated" : { 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 81883099b2..7b5295286e 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 @@ -13,7 +13,8 @@ "htlcMinimum" : 0, "toSelfDelay" : 144, "maxAcceptedHtlcs" : 100, - "isInitiator" : true, + "isChannelOpener" : true, + "paysCommitTxFees" : true, "upfrontShutdownScript_opt" : "0014fe2baa428e1f6b4b4134d444b3de42a86cffbabc", "initFeatures" : { "activated" : { 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 4389229109..421bc31e30 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala @@ -128,7 +128,7 @@ object TestConstants { maxReserveToFundingRatio = 0.05, unhandledExceptionStrategy = UnhandledExceptionStrategy.LocalClose, revocationTimeout = 20 seconds, - channelFlags = ChannelFlags.Public, + channelFlags = ChannelFlags(announceChannel = true), minFundingPublicSatoshis = 1000 sat, minFundingPrivateSatoshis = 900 sat, requireConfirmedInputsForDualFunding = false, @@ -235,7 +235,7 @@ object TestConstants { nodeParams.features.initFeatures(), None, None, - isInitiator = true, + isChannelOpener = true, dualFunded = false, fundingSatoshis, unlimitedMaxHtlcValueInFlight = false, @@ -295,7 +295,7 @@ object TestConstants { maxReserveToFundingRatio = 0.05, unhandledExceptionStrategy = UnhandledExceptionStrategy.LocalClose, revocationTimeout = 20 seconds, - channelFlags = ChannelFlags.Public, + channelFlags = ChannelFlags(announceChannel = true), minFundingPublicSatoshis = 1000 sat, minFundingPrivateSatoshis = 900 sat, requireConfirmedInputsForDualFunding = false, @@ -402,7 +402,7 @@ object TestConstants { nodeParams.features.initFeatures(), None, None, - isInitiator = false, + isChannelOpener = false, dualFunded = false, fundingSatoshis, unlimitedMaxHtlcValueInFlight = false, 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 467b0f5f96..33d8f0ece9 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 @@ -485,9 +485,9 @@ class CommitmentsSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with object CommitmentsSpec { - def makeCommitments(toLocal: MilliSatoshi, toRemote: MilliSatoshi, feeRatePerKw: FeeratePerKw = FeeratePerKw(0 sat), dustLimit: Satoshi = 0 sat, isInitiator: Boolean = true, announceChannel: Boolean = true): Commitments = { + def makeCommitments(toLocal: MilliSatoshi, toRemote: MilliSatoshi, feeRatePerKw: FeeratePerKw = FeeratePerKw(0 sat), dustLimit: Satoshi = 0 sat, isOpener: Boolean = true, announceChannel: Boolean = true): Commitments = { val channelReserve = (toLocal + toRemote).truncateToSatoshi * 0.01 - val localParams = LocalParams(randomKey().publicKey, DeterministicWallet.KeyPath(Seq(42L)), dustLimit, Long.MaxValue.msat, Some(channelReserve), 1 msat, CltvExpiryDelta(144), 50, isInitiator, None, None, Features.empty) + val localParams = LocalParams(randomKey().publicKey, DeterministicWallet.KeyPath(Seq(42L)), dustLimit, Long.MaxValue.msat, 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 remoteFundingPubKey = randomKey().publicKey val commitmentInput = Funding.makeFundingInputInfo(randomTxId(), 0, (toLocal + toRemote).truncateToSatoshi, randomKey().publicKey, remoteFundingPubKey) @@ -506,7 +506,7 @@ object CommitmentsSpec { def makeCommitments(toLocal: MilliSatoshi, toRemote: MilliSatoshi, localNodeId: PublicKey, remoteNodeId: PublicKey, announceChannel: Boolean): Commitments = { val channelReserve = (toLocal + toRemote).truncateToSatoshi * 0.01 - val localParams = LocalParams(localNodeId, DeterministicWallet.KeyPath(Seq(42L)), 0 sat, Long.MaxValue.msat, Some(channelReserve), 1 msat, CltvExpiryDelta(144), 50, isInitiator = true, None, None, Features.empty) + val localParams = LocalParams(localNodeId, DeterministicWallet.KeyPath(Seq(42L)), 0 sat, Long.MaxValue.msat, 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 remoteFundingPubKey = randomKey().publicKey val commitmentInput = Funding.makeFundingInputInfo(randomTxId(), 0, (toLocal + toRemote).truncateToSatoshi, randomKey().publicKey, remoteFundingPubKey) 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 5c105c225e..d174f1daac 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 @@ -42,7 +42,7 @@ import org.scalatest.{Outcome, Tag} import java.util.UUID import java.util.concurrent.CountDownLatch import scala.concurrent.duration._ -import scala.util.{Random, Success} +import scala.util.Random /** * Created by PM on 05/07/2016. @@ -57,6 +57,7 @@ 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 channelFlags = ChannelFlags(announceChannel = false) val alicePeer = TestProbe() val bobPeer = TestProbe() TestUtils.forwardOutgoingToPipe(alicePeer, pipe) @@ -78,7 +79,7 @@ class FuzzySpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with Channe 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, Alice.channelParams, pipe, bobInit, channelFlags = ChannelFlags.Private, 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, Alice.channelParams, 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, Bob.channelParams, pipe, aliceInit, ChannelConfig.standard, ChannelTypes.Standard()) bob2blockchain.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 6eee56bb21..4a146d0094 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 @@ -214,8 +214,8 @@ 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)): 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, isInitiator = true, dualFunded = true, fundingAmountA, unlimitedMaxHtlcValueInFlight = false) - val localParamsB = makeChannelParams(nodeParamsB, nodeParamsB.features.initFeatures(), None, None, isInitiator = false, dualFunded = true, fundingAmountB, unlimitedMaxHtlcValueInFlight = false) + val localParamsA = makeChannelParams(nodeParamsA, nodeParamsA.features.initFeatures(), None, None, isChannelOpener = true, dualFunded = true, fundingAmountA, unlimitedMaxHtlcValueInFlight = false) + val localParamsB = makeChannelParams(nodeParamsB, nodeParamsB.features.initFeatures(), None, None, isChannelOpener = false, dualFunded = true, fundingAmountB, unlimitedMaxHtlcValueInFlight = false) val Seq(remoteParamsA, remoteParamsB) = Seq((nodeParamsA, localParamsA), (nodeParamsB, localParamsB)).map { case (nodeParams, localParams) => @@ -236,8 +236,8 @@ class InteractiveTxBuilderSpec extends TestKitBaseClass with AnyFunSuiteLike wit val fundingPubKeyB = nodeParamsB.channelKeyManager.fundingPublicKey(localParamsB.fundingKeyPath, 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.Public) - val channelParamsB = ChannelParams(channelId, ChannelConfig.standard, channelFeatures, localParamsB, remoteParamsA, ChannelFlags.Public) + val channelParamsA = ChannelParams(channelId, ChannelConfig.standard, channelFeatures, localParamsA, remoteParamsB, ChannelFlags(announceChannel = true)) + val channelParamsB = ChannelParams(channelId, ChannelConfig.standard, channelFeatures, localParamsB, remoteParamsA, ChannelFlags(announceChannel = true)) FixtureParams(fundingParamsA, nodeParamsA, channelParamsA, fundingParamsB, nodeParamsB, channelParamsB, channelFeatures) } 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 9421473ea6..cf9732014a 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 @@ -56,7 +56,7 @@ class WaitForAcceptChannelStateSpec extends TestKitBaseClass with FixtureAnyFunS import setup._ val channelConfig = ChannelConfig.standard - val channelFlags = ChannelFlags.Private + 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 @@ -168,10 +168,11 @@ class WaitForAcceptChannelStateSpec extends TestKitBaseClass with FixtureAnyFunS 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)) - alice ! INPUT_INIT_CHANNEL_INITIATOR(ByteVector32.Zeroes, TestConstants.fundingSatoshis, dualFunded = false, TestConstants.anchorOutputsFeeratePerKw, TestConstants.feeratePerKw, fundingTxFeeBudget_opt = None, Some(TestConstants.initiatorPushAmount), requireConfirmedInputs = false, aliceParams, alice2bob.ref, Init(bobParams.initFeatures), ChannelFlags.Private, channelConfig, ChannelTypes.AnchorOutputs(), replyTo = aliceOpenReplyTo.ref.toTyped) + alice ! INPUT_INIT_CHANNEL_INITIATOR(ByteVector32.Zeroes, TestConstants.fundingSatoshis, dualFunded = false, TestConstants.anchorOutputsFeeratePerKw, TestConstants.feeratePerKw, fundingTxFeeBudget_opt = None, Some(TestConstants.initiatorPushAmount), requireConfirmedInputs = false, 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, bobParams, bob2alice.ref, Init(bobParams.initFeatures), channelConfig, ChannelTypes.AnchorOutputs()) val open = alice2bob.expectMsgType[OpenChannel] assert(open.channelType_opt.contains(ChannelTypes.AnchorOutputs())) 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 dc89dcfe0b..34c505afb3 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 @@ -50,7 +50,7 @@ class WaitForAcceptDualFundedChannelStateSpec extends TestKitBaseClass with Fixt import setup._ val channelConfig = ChannelConfig.standard - val channelFlags = ChannelFlags.Private + val channelFlags = ChannelFlags(announceChannel = false) val (aliceParams, bobParams, channelType) = computeFeatures(setup, test.tags, channelFlags) val aliceInit = Init(aliceParams.initFeatures) val bobInit = Init(bobParams.initFeatures) @@ -59,7 +59,7 @@ 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, aliceParams, alice2bob.ref, bobInit, ChannelFlags.Private, channelConfig, channelType, replyTo = aliceOpenReplyTo.ref.toTyped) + alice ! INPUT_INIT_CHANNEL_INITIATOR(ByteVector32.Zeroes, TestConstants.fundingSatoshis, dualFunded = true, TestConstants.anchorOutputsFeeratePerKw, TestConstants.feeratePerKw, fundingTxFeeBudget_opt = None, None, requireConfirmedInputs = false, aliceParams, alice2bob.ref, bobInit, channelFlags, channelConfig, channelType, replyTo = aliceOpenReplyTo.ref.toTyped) bob ! INPUT_INIT_CHANNEL_NON_INITIATOR(ByteVector32.Zeroes, nonInitiatorContribution, dualFunded = true, nonInitiatorPushAmount, bobParams, bob2alice.ref, aliceInit, channelConfig, channelType) val open = alice2bob.expectMsgType[OpenDualFundedChannel] alice2bob.forward(bob, open) 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 3d20ac58e0..80d2612242 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 @@ -48,7 +48,7 @@ class WaitForOpenChannelStateSpec extends TestKitBaseClass with FixtureAnyFunSui import setup._ val channelConfig = ChannelConfig.standard - val channelFlags = ChannelFlags.Private + 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 @@ -128,10 +128,10 @@ class WaitForOpenChannelStateSpec extends TestKitBaseClass with FixtureAnyFunSui import f._ val open = alice2bob.expectMsgType[OpenChannel] val lowFunding = 100.sat - val announceChannel = true - bob ! open.copy(fundingSatoshis = lowFunding, channelFlags = ChannelFlags(announceChannel)) + val flags = ChannelFlags(announceChannel = true) + bob ! open.copy(fundingSatoshis = lowFunding, channelFlags = flags) val error = bob2alice.expectMsgType[Error] - assert(error == Error(open.temporaryChannelId, FundingAmountTooLow(open.temporaryChannelId, lowFunding, Bob.nodeParams.channelConf.minFundingSatoshis(announceChannel)).getMessage)) + assert(error == Error(open.temporaryChannelId, FundingAmountTooLow(open.temporaryChannelId, lowFunding, Bob.nodeParams.channelConf.minFundingSatoshis(flags)).getMessage)) listener.expectMsgType[ChannelAborted] awaitCond(bob.stateName == CLOSED) } @@ -140,10 +140,10 @@ class WaitForOpenChannelStateSpec extends TestKitBaseClass with FixtureAnyFunSui import f._ val open = alice2bob.expectMsgType[OpenChannel] val lowFunding = 100.sat - val announceChannel = false - bob ! open.copy(fundingSatoshis = lowFunding, channelFlags = ChannelFlags(announceChannel)) + val flags = ChannelFlags(announceChannel = false) + bob ! open.copy(fundingSatoshis = lowFunding, channelFlags = flags) val error = bob2alice.expectMsgType[Error] - assert(error == Error(open.temporaryChannelId, FundingAmountTooLow(open.temporaryChannelId, lowFunding, Bob.nodeParams.channelConf.minFundingSatoshis(announceChannel)).getMessage)) + assert(error == Error(open.temporaryChannelId, FundingAmountTooLow(open.temporaryChannelId, lowFunding, Bob.nodeParams.channelConf.minFundingSatoshis(flags)).getMessage)) listener.expectMsgType[ChannelAborted] awaitCond(bob.stateName == CLOSED) } 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 1aaeb9a997..fc1cec79b2 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 @@ -50,14 +50,14 @@ class WaitForOpenDualFundedChannelStateSpec extends TestKitBaseClass with Fixtur bob.underlyingActor.context.system.eventStream.subscribe(bobListener.ref, classOf[ChannelAborted]) val channelConfig = ChannelConfig.standard - val channelFlags = ChannelFlags.Private + val channelFlags = ChannelFlags(announceChannel = false) val pushAmount = if (test.tags.contains(ChannelStateTestsTags.NoPushAmount)) None else Some(TestConstants.initiatorPushAmount) val (aliceParams, bobParams, channelType) = computeFeatures(setup, test.tags, channelFlags) val aliceInit = Init(aliceParams.initFeatures) val bobInit = Init(bobParams.initFeatures) 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, aliceParams, alice2bob.ref, bobInit, ChannelFlags.Private, channelConfig, channelType, replyTo = aliceOpenReplyTo.ref.toTyped) + alice ! INPUT_INIT_CHANNEL_INITIATOR(ByteVector32.Zeroes, TestConstants.fundingSatoshis, dualFunded = true, TestConstants.anchorOutputsFeeratePerKw, TestConstants.feeratePerKw, fundingTxFeeBudget_opt = None, pushAmount, requireConfirmedInputs, aliceParams, alice2bob.ref, bobInit, channelFlags, channelConfig, channelType, replyTo = aliceOpenReplyTo.ref.toTyped) bob ! INPUT_INIT_CHANNEL_NON_INITIATOR(ByteVector32.Zeroes, None, dualFunded = true, None, bobParams, bob2alice.ref, aliceInit, channelConfig, channelType) awaitCond(bob.stateName == WAIT_FOR_OPEN_DUAL_FUNDED_CHANNEL) withFixture(test.toNoArgTest(FixtureParam(alice, bob, alice2bob, bob2alice, aliceListener, bobListener))) @@ -77,13 +77,13 @@ class WaitForOpenDualFundedChannelStateSpec extends TestKitBaseClass with Fixtur assert(open.lockTime == TestConstants.defaultBlockHeight) val initiatorEvent = aliceListener.expectMsgType[ChannelCreated] - assert(initiatorEvent.isInitiator) + assert(initiatorEvent.isOpener) assert(initiatorEvent.temporaryChannelId == ByteVector32.Zeroes) alice2bob.forward(bob) val nonInitiatorEvent = bobListener.expectMsgType[ChannelCreated] - assert(!nonInitiatorEvent.isInitiator) + assert(!nonInitiatorEvent.isOpener) assert(nonInitiatorEvent.temporaryChannelId == ByteVector32.Zeroes) val accept = bob2alice.expectMsgType[AcceptDualFundedChannel] @@ -133,7 +133,7 @@ class WaitForOpenDualFundedChannelStateSpec extends TestKitBaseClass with Fixtur val open = alice2bob.expectMsgType[OpenDualFundedChannel] bob ! open.copy(fundingAmount = 100 sat) val error = bob2alice.expectMsgType[Error] - assert(error == Error(open.temporaryChannelId, FundingAmountTooLow(open.temporaryChannelId, 100 sat, Bob.nodeParams.channelConf.minFundingSatoshis(false)).getMessage)) + assert(error == Error(open.temporaryChannelId, FundingAmountTooLow(open.temporaryChannelId, 100 sat, Bob.nodeParams.channelConf.minFundingSatoshis(ChannelFlags(announceChannel = false))).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 d51fbb9d82..9458661e32 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 @@ -44,7 +44,7 @@ class WaitForDualFundingCreatedStateSpec extends TestKitBaseClass with FixtureAn val setup = init(wallet_opt = Some(wallet), tags = test.tags) import setup._ val channelConfig = ChannelConfig.standard - val channelFlags = ChannelFlags.Private + val channelFlags = ChannelFlags(announceChannel = false) val (aliceParams, bobParams, channelType) = computeFeatures(setup, test.tags, channelFlags) val aliceInit = Init(aliceParams.initFeatures) val bobInit = Init(bobParams.initFeatures) 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 0f97469eb9..75e26ecfd9 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 @@ -46,7 +46,7 @@ class WaitForDualFundingSignedStateSpec extends TestKitBaseClass with FixtureAny val setup = init(wallet_opt = Some(wallet), tags = test.tags) import setup._ val channelConfig = ChannelConfig.standard - val channelFlags = ChannelFlags.Private + val channelFlags = ChannelFlags(announceChannel = false) val (aliceParams, bobParams, channelType) = computeFeatures(setup, test.tags, channelFlags) val aliceInit = Init(aliceParams.initFeatures) val bobInit = Init(bobParams.initFeatures) 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 53f7392589..9ee675f56e 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 @@ -58,7 +58,7 @@ class WaitForFundingCreatedStateSpec extends TestKitBaseClass with FixtureAnyFun } val channelConfig = ChannelConfig.standard - val channelFlags = ChannelFlags.Private + val channelFlags = ChannelFlags(announceChannel = false) val (aliceParams, bobParams, channelType) = computeFeatures(setup, test.tags, channelFlags) val aliceInit = Init(aliceParams.initFeatures) val bobInit = Init(bobParams.initFeatures) 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 1b8006ab48..301609f613 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 @@ -45,7 +45,7 @@ class WaitForFundingInternalStateSpec extends TestKitBaseClass with FixtureAnyFu val setup = init(wallet_opt = Some(new NoOpOnChainWallet()), tags = test.tags) import setup._ val channelConfig = ChannelConfig.standard - val channelFlags = ChannelFlags.Private + val channelFlags = ChannelFlags(announceChannel = false) val (aliceParams, bobParams, channelType) = computeFeatures(setup, test.tags, channelFlags) val aliceInit = Init(aliceParams.initFeatures) val bobInit = Init(bobParams.initFeatures) 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 78089a5452..6abc907f0a 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 @@ -57,7 +57,7 @@ class WaitForFundingSignedStateSpec extends TestKitBaseClass with FixtureAnyFunS } val channelConfig = ChannelConfig.standard - val channelFlags = ChannelFlags.Private + val channelFlags = ChannelFlags(announceChannel = false) val (aliceParams, bobParams, channelType) = computeFeatures(setup, test.tags, channelFlags) val commitFeerate = channelType.commitmentFormat match { case Transactions.DefaultCommitmentFormat => TestConstants.feeratePerKw 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 d2f7edb5e0..1b1367d24c 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 @@ -61,7 +61,7 @@ class WaitForDualFundingConfirmedStateSpec extends TestKitBaseClass with Fixture bob.underlying.system.eventStream.subscribe(bobListener.ref, classOf[ChannelClosed]) val channelConfig = ChannelConfig.standard - val channelFlags = ChannelFlags.Private + val channelFlags = ChannelFlags(announceChannel = false) val (aliceParams, bobParams, channelType) = computeFeatures(setup, test.tags, channelFlags) val commitFeerate = channelType.commitmentFormat match { case Transactions.DefaultCommitmentFormat => TestConstants.feeratePerKw 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 a604be4711..c665bedd75 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 @@ -47,7 +47,7 @@ class WaitForFundingConfirmedStateSpec extends TestKitBaseClass with FixtureAnyF val setup = init(tags = test.tags) import setup._ val channelConfig = ChannelConfig.standard - val channelFlags = ChannelFlags.Private + 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) 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 8d3b5772b9..808840c034 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 @@ -69,7 +69,7 @@ class ClosingStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with if (unconfirmedFundingTx) { within(30 seconds) { val channelConfig = ChannelConfig.standard - val channelFlags = ChannelFlags.Private + val channelFlags = ChannelFlags(announceChannel = false) val (aliceParams, bobParams, channelType) = computeFeatures(setup, test.tags, channelFlags) val aliceInit = Init(aliceParams.initFeatures) val bobInit = Init(bobParams.initFeatures) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/db/AuditDbSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/db/AuditDbSpec.scala index a66d344b1e..d7be3479f3 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/db/AuditDbSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/db/AuditDbSpec.scala @@ -78,7 +78,7 @@ class AuditDbSpec extends AnyFunSuite { val e5 = PaymentSent(UUID.randomUUID(), randomBytes32(), randomBytes32(), 84100 msat, randomKey().publicKey, pp5a :: pp5b :: Nil) val pp6 = PaymentSent.PartialPayment(UUID.randomUUID(), 42000 msat, 1000 msat, randomBytes32(), None, timestamp = now + 10.minutes) val e6 = PaymentSent(UUID.randomUUID(), randomBytes32(), randomBytes32(), 42000 msat, randomKey().publicKey, pp6 :: Nil) - val e7 = ChannelEvent(randomBytes32(), randomKey().publicKey, 456123000 sat, isInitiator = true, isPrivate = false, ChannelEvent.EventType.Closed(MutualClose(null))) + val e7 = ChannelEvent(randomBytes32(), randomKey().publicKey, 456123000 sat, isChannelOpener = true, isPrivate = false, ChannelEvent.EventType.Closed(MutualClose(null))) val e8 = ChannelErrorOccurred(null, randomBytes32(), randomKey().publicKey, LocalError(new RuntimeException("oops")), isFatal = true) val e9 = ChannelErrorOccurred(null, randomBytes32(), randomKey().publicKey, RemoteError(Error(randomBytes32(), "remote oops")), isFatal = true) val e10 = TrampolinePaymentRelayed(randomBytes32(), diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/interop/rustytests/RustyTestsSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/interop/rustytests/RustyTestsSpec.scala index 8d511c634c..69ae7dfedc 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/interop/rustytests/RustyTestsSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/interop/rustytests/RustyTestsSpec.scala @@ -72,7 +72,7 @@ class RustyTestsSpec extends TestKitBaseClass with Matchers with FixtureAnyFunSu val aliceInit = Init(Alice.channelParams.initFeatures) val bobInit = Init(Bob.channelParams.initFeatures) // alice and bob will both have 1 000 000 sat - alice ! INPUT_INIT_CHANNEL_INITIATOR(ByteVector32.Zeroes, 2000000 sat, dualFunded = false, commitTxFeerate = feeratePerKw, fundingTxFeerate = feeratePerKw, fundingTxFeeBudget_opt = None, Some(1000000000 msat), requireConfirmedInputs = false, Alice.channelParams, pipe, bobInit, ChannelFlags.Private, channelConfig, channelType, replyTo = system.deadLetters) + alice ! INPUT_INIT_CHANNEL_INITIATOR(ByteVector32.Zeroes, 2000000 sat, dualFunded = false, commitTxFeerate = feeratePerKw, fundingTxFeerate = feeratePerKw, fundingTxFeeBudget_opt = None, Some(1000000000 msat), requireConfirmedInputs = false, Alice.channelParams, pipe, bobInit, ChannelFlags(announceChannel = false), channelConfig, channelType, replyTo = system.deadLetters) alice2blockchain.expectMsgType[TxPublisher.SetChannelId] bob ! INPUT_INIT_CHANNEL_NON_INITIATOR(ByteVector32.Zeroes, None, dualFunded = false, None, Bob.channelParams, pipe, aliceInit, channelConfig, channelType) bob2blockchain.expectMsgType[TxPublisher.SetChannelId] 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 df59c76220..4302bd01b8 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 @@ -664,11 +664,11 @@ object PeerSpec { } def createOpenChannelMessage(openTlv: TlvStream[OpenChannelTlv] = TlvStream.empty): protocol.OpenChannel = { - protocol.OpenChannel(Block.RegtestGenesisBlock.hash, randomBytes32(), 25000 sat, 0 msat, 483 sat, UInt64(100), 1000 sat, 1 msat, TestConstants.feeratePerKw, CltvExpiryDelta(144), 10, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, ChannelFlags.Private, openTlv) + protocol.OpenChannel(Block.RegtestGenesisBlock.hash, randomBytes32(), 25000 sat, 0 msat, 483 sat, UInt64(100), 1000 sat, 1 msat, TestConstants.feeratePerKw, CltvExpiryDelta(144), 10, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, ChannelFlags(announceChannel = false), openTlv) } def createOpenDualFundedChannelMessage(): protocol.OpenDualFundedChannel = { - protocol.OpenDualFundedChannel(Block.RegtestGenesisBlock.hash, randomBytes32(), TestConstants.feeratePerKw, TestConstants.anchorOutputsFeeratePerKw, 25000 sat, 483 sat, UInt64(100), 1 msat, CltvExpiryDelta(144), 10, 0, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, ChannelFlags.Private) + protocol.OpenDualFundedChannel(Block.RegtestGenesisBlock.hash, randomBytes32(), TestConstants.feeratePerKw, TestConstants.anchorOutputsFeeratePerKw, 25000 sat, 483 sat, UInt64(100), 1 msat, CltvExpiryDelta(144), 10, 0, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, randomKey().publicKey, ChannelFlags(announceChannel = false)) } } \ No newline at end of file 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 4647913fa2..0512401433 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 @@ -99,10 +99,10 @@ class PendingChannelsRateLimiterSpec extends ScalaTestWithActorTestKit(ConfigFac DATA_NORMAL(commitments(privatePeer2, randomBytes32()), ShortIds(RealScidStatus.Unknown, ShortChannelId.generateLocalAlias(), None), None, null, None, None, None, SpliceStatus.NoSplice), ) val initiatorChannels = Seq( - DATA_WAIT_FOR_FUNDING_CONFIRMED(commitments(peerBelowLimit1, randomBytes32(), isInitiator = true), BlockHeight(0), None, Left(FundingCreated(channelIdAtLimit1, TxId(ByteVector32.Zeroes), 3, randomBytes64()))), - DATA_WAIT_FOR_CHANNEL_READY(commitments(peerBelowLimit1, randomBytes32(), isInitiator = true), ShortIds(RealScidStatus.Unknown, ShortChannelId.generateLocalAlias(), None)), - DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED(commitments(peerAtLimit1, randomBytes32(), isInitiator = true), 0 msat, 0 msat, BlockHeight(0), BlockHeight(0), RbfStatus.NoRbf, None), - DATA_WAIT_FOR_DUAL_FUNDING_READY(commitments(peerAtLimit1, randomBytes32(), isInitiator = true), ShortIds(RealScidStatus.Unknown, ShortChannelId.generateLocalAlias(), None)), + DATA_WAIT_FOR_FUNDING_CONFIRMED(commitments(peerBelowLimit1, randomBytes32(), isOpener = true), BlockHeight(0), None, Left(FundingCreated(channelIdAtLimit1, TxId(ByteVector32.Zeroes), 3, randomBytes64()))), + DATA_WAIT_FOR_CHANNEL_READY(commitments(peerBelowLimit1, randomBytes32(), isOpener = true), ShortIds(RealScidStatus.Unknown, ShortChannelId.generateLocalAlias(), None)), + DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED(commitments(peerAtLimit1, randomBytes32(), isOpener = true), 0 msat, 0 msat, BlockHeight(0), BlockHeight(0), RbfStatus.NoRbf, None), + DATA_WAIT_FOR_DUAL_FUNDING_READY(commitments(peerAtLimit1, randomBytes32(), isOpener = true), ShortIds(RealScidStatus.Unknown, ShortChannelId.generateLocalAlias(), None)), ) val publicChannels = channelsOnWhitelistAtLimit ++ channelsAtLimit1 ++ channelsAtLimit2 ++ channelsBelowLimit1 ++ channelsBelowLimit2 val allChannels = publicChannels ++ privateChannels ++ initiatorChannels @@ -112,9 +112,9 @@ class PendingChannelsRateLimiterSpec extends ScalaTestWithActorTestKit(ConfigFac def announcement(nodeId: PublicKey): NodeAnnouncement = NodeAnnouncement(randomBytes64(), Features.empty, 1 unixsec, nodeId, Color(100.toByte, 200.toByte, 300.toByte), "node-alias", NodeAddress.fromParts("1.2.3.4", 42000).get :: Nil) - def commitments(remoteNodeId: PublicKey, channelId: ByteVector32, isInitiator: Boolean = false): Commitments = { + def commitments(remoteNodeId: PublicKey, channelId: ByteVector32, isOpener: Boolean = false): Commitments = { val commitments = CommitmentsSpec.makeCommitments(500_000 msat, 400_000 msat, TestConstants.Alice.nodeParams.nodeId, remoteNodeId, announceChannel = true) - commitments.copy(params = commitments.params.copy(channelId = channelId, localParams = commitments.params.localParams.copy(isInitiator = isInitiator))) + commitments.copy(params = commitments.params.copy(channelId = channelId, localParams = commitments.params.localParams.copy(isChannelOpener = isOpener))) } def processRestoredChannels(f: FixtureParam, restoredChannels: Seq[PersistentChannelData]): Unit = { 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 39562b7c8a..1ed1931702 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 @@ -119,7 +119,7 @@ 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, Long.MaxValue.msat, Some(1000 sat), 1 msat, CltvExpiryDelta(144), 50, isInitiator = true, None, None, Features.empty) + val localParams = LocalParams(dummyPublicKey, DeterministicWallet.KeyPath(Seq(42L)), 546 sat, Long.MaxValue.msat, 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 commitmentInput = Funding.makeFundingInputInfo(TxId(dummyBytes32), 0, 150_000 sat, dummyPublicKey, dummyPublicKey) val localCommit = LocalCommit(0, CommitmentSpec(Set.empty, FeeratePerKw(2500 sat), 100_000_000 msat, 50_000_000 msat), CommitTxAndRemoteSig(CommitTx(commitmentInput, Transaction(2, Nil, Nil, 0)), ByteVector64.Zeroes), Nil) @@ -166,7 +166,8 @@ class JsonSerializersSpec extends TestKitBaseClass with AnyFunSuiteLike with Mat | "htlcMinimum": 1, | "toSelfDelay": 144, | "maxAcceptedHtlcs": 50, - | "isInitiator": true, + | "isChannelOpener": true, + | "paysCommitTxFees" : true, | "initFeatures": { "activated": {}, "unknown": [] } | }, | "remoteParams": { 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 59c1895ee0..7139da06c9 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 @@ -729,14 +729,14 @@ object PaymentPacketSpec { def makeCommitments(channelId: ByteVector32, testAvailableBalanceForSend: MilliSatoshi = 50000000 msat, testAvailableBalanceForReceive: MilliSatoshi = 50000000 msat, testCapacity: Satoshi = 100000 sat, channelFeatures: ChannelFeatures = ChannelFeatures()): Commitments = { val channelReserve = testCapacity * 0.01 - val localParams = LocalParams(null, null, null, Long.MaxValue.msat, Some(channelReserve), null, null, 0, isInitiator = true, None, None, null) + val localParams = LocalParams(null, null, null, Long.MaxValue.msat, Some(channelReserve), null, null, 0, isChannelOpener = true, paysCommitTxFees = true, None, None, null) val remoteParams = RemoteParams(randomKey().publicKey, null, UInt64.MaxValue, Some(channelReserve), null, null, maxAcceptedHtlcs = 0, null, null, null, null, null, None) val commitInput = InputInfo(OutPoint(randomTxId(), 1), TxOut(testCapacity, Nil), Nil) val localCommit = LocalCommit(0, null, CommitTxAndRemoteSig(Transactions.CommitTx(commitInput, null), null), Nil) val remoteCommit = RemoteCommit(0, null, null, randomKey().publicKey) val localChanges = LocalChanges(Nil, Nil, Nil) val remoteChanges = RemoteChanges(Nil, Nil, Nil) - val channelFlags = ChannelFlags.Private + val channelFlags = ChannelFlags(announceChannel = false) new Commitments( ChannelParams(channelId, ChannelConfig.standard, channelFeatures, localParams, remoteParams, channelFlags), CommitmentChanges(localChanges, remoteChanges, 0, 0), diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/transactions/TestVectorsSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/transactions/TestVectorsSpec.scala index 8f05b07488..f87fd3a87a 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/transactions/TestVectorsSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/transactions/TestVectorsSpec.scala @@ -126,7 +126,7 @@ trait TestVectorsSpec extends AnyFunSuite with Logging { val commitmentInput = Funding.makeFundingInputInfo(fundingTx.txid, 0, fundingAmount, Local.funding_pubkey, Remote.funding_pubkey) - val obscured_tx_number = Transactions.obscuredCommitTxNumber(42, isInitiator = true, Local.payment_basepoint, Remote.payment_basepoint) + val obscured_tx_number = Transactions.obscuredCommitTxNumber(42, localIsChannelOpener = true, Local.payment_basepoint, Remote.payment_basepoint) assert(obscured_tx_number == (0x2bb038521914L ^ 42L)) logger.info(s"local_payment_basepoint: ${Local.payment_basepoint}") @@ -188,7 +188,7 @@ trait TestVectorsSpec extends AnyFunSuite with Logging { logger.info(s"local_feerate_per_kw: ${spec.commitTxFeerate}") val outputs = Transactions.makeCommitTxOutputs( - localIsInitiator = true, + localPaysCommitTxFees = true, localDustLimit = dustLimit, localRevocationPubkey = Local.revocation_pubkey, toLocalDelay = Local.toSelfDelay, @@ -207,7 +207,7 @@ trait TestVectorsSpec extends AnyFunSuite with Logging { commitTxNumber = Local.commitTxNumber, localPaymentBasePoint = Local.payment_basepoint, remotePaymentBasePoint = Remote.payment_basepoint, - localIsInitiator = true, + localIsChannelOpener = true, outputs = outputs) val local_sig = Transactions.sign(tx, Local.funding_privkey, TxOwner.Local, commitmentFormat) logger.info(s"# local_signature = ${Scripts.der(local_sig).dropRight(1).toHex}") @@ -230,7 +230,7 @@ trait TestVectorsSpec extends AnyFunSuite with Logging { } }) - assert(Transactions.getCommitTxNumber(commitTx.tx, isInitiator = true, Local.payment_basepoint, Remote.payment_basepoint) == Local.commitTxNumber) + assert(Transactions.getCommitTxNumber(commitTx.tx, localIsChannelOpener = true, Local.payment_basepoint, Remote.payment_basepoint) == Local.commitTxNumber) Transaction.correctlySpends(commitTx.tx, Seq(fundingTx), ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS) logger.info(s"output commit_tx: ${commitTx.tx}") diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/transactions/TransactionsSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/transactions/TransactionsSpec.scala index 331668ed6a..82d2561576 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/transactions/TransactionsSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/transactions/TransactionsSpec.scala @@ -19,7 +19,7 @@ package fr.acinq.eclair.transactions import fr.acinq.bitcoin.SigHash._ import fr.acinq.bitcoin.scalacompat.Crypto.{PrivateKey, ripemd160, sha256} import fr.acinq.bitcoin.scalacompat.Script.{pay2wpkh, pay2wsh, write} -import fr.acinq.bitcoin.scalacompat.{Block, Btc, ByteVector32, Crypto, MilliBtc, MilliBtcDouble, OutPoint, Protocol, Satoshi, SatoshiLong, Script, ScriptWitness, Transaction, TxId, TxIn, TxOut, millibtc2satoshi} +import fr.acinq.bitcoin.scalacompat.{Btc, ByteVector32, Crypto, MilliBtc, MilliBtcDouble, OutPoint, Protocol, Satoshi, SatoshiLong, Script, ScriptWitness, Transaction, TxId, TxIn, TxOut, millibtc2satoshi} import fr.acinq.eclair.TestUtils.randomTxId import fr.acinq.eclair._ import fr.acinq.eclair.blockchain.fee.{ConfirmationTarget, FeeratePerKw} @@ -170,7 +170,7 @@ class TransactionsSpec extends AnyFunSuite with Logging { val paymentPreimage = randomBytes32() val htlc = UpdateAddHtlc(ByteVector32.Zeroes, 0, (20000 * 1000) msat, sha256(paymentPreimage), CltvExpiryDelta(144).toCltvExpiry(blockHeight), TestConstants.emptyOnionPacket, None) val spec = CommitmentSpec(Set(OutgoingHtlc(htlc)), feeratePerKw, toLocal = 0 msat, toRemote = 0 msat) - val outputs = makeCommitTxOutputs(localIsInitiator = true, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, spec, DefaultCommitmentFormat) + val outputs = makeCommitTxOutputs(localPaysCommitTxFees = true, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, spec, DefaultCommitmentFormat) val pubKeyScript = write(pay2wsh(htlcOffered(localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localRevocationPriv.publicKey, ripemd160(htlc.paymentHash), DefaultCommitmentFormat))) val commitTx = Transaction(version = 2, txIn = Nil, txOut = TxOut(htlc.amountMsat.truncateToSatoshi, pubKeyScript) :: Nil, lockTime = 0) val Right(claimHtlcSuccessTx) = makeClaimHtlcSuccessTx(commitTx, outputs, localDustLimit, remoteHtlcPriv.publicKey, localHtlcPriv.publicKey, localRevocationPriv.publicKey, finalPubKeyScript, htlc, feeratePerKw, DefaultCommitmentFormat) @@ -185,7 +185,7 @@ class TransactionsSpec extends AnyFunSuite with Logging { val paymentPreimage = randomBytes32() val htlc = UpdateAddHtlc(ByteVector32.Zeroes, 0, (20000 * 1000) msat, sha256(paymentPreimage), toLocalDelay.toCltvExpiry(blockHeight), TestConstants.emptyOnionPacket, None) val spec = CommitmentSpec(Set(IncomingHtlc(htlc)), feeratePerKw, toLocal = 0 msat, toRemote = 0 msat) - val outputs = makeCommitTxOutputs(localIsInitiator = true, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, spec, DefaultCommitmentFormat) + val outputs = makeCommitTxOutputs(localPaysCommitTxFees = true, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, spec, DefaultCommitmentFormat) val pubKeyScript = write(pay2wsh(htlcReceived(localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localRevocationPriv.publicKey, ripemd160(htlc.paymentHash), htlc.cltvExpiry, DefaultCommitmentFormat))) val commitTx = Transaction(version = 2, txIn = Nil, txOut = TxOut(htlc.amountMsat.truncateToSatoshi, pubKeyScript) :: Nil, lockTime = 0) val Right(claimClaimHtlcTimeoutTx) = makeClaimHtlcTimeoutTx(commitTx, outputs, localDustLimit, remoteHtlcPriv.publicKey, localHtlcPriv.publicKey, localRevocationPriv.publicKey, finalPubKeyScript, htlc, feeratePerKw, DefaultCommitmentFormat) @@ -226,31 +226,31 @@ class TransactionsSpec extends AnyFunSuite with Logging { { val toRemoteFundeeBelowDust = spec.copy(toRemote = belowDust) - val outputs = makeCommitTxOutputs(localIsInitiator = true, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, toRemoteFundeeBelowDust, DefaultCommitmentFormat) + val outputs = makeCommitTxOutputs(localPaysCommitTxFees = true, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, toRemoteFundeeBelowDust, DefaultCommitmentFormat) assert(outputs.map(_.commitmentOutput) == Seq(CommitmentOutput.ToLocal)) assert(outputs.head.output.amount.toMilliSatoshi == toRemoteFundeeBelowDust.toLocal - commitFee) } { val toLocalFunderBelowDust = spec.copy(toLocal = belowDustWithFee) - val outputs = makeCommitTxOutputs(localIsInitiator = true, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, toLocalFunderBelowDust, DefaultCommitmentFormat) + val outputs = makeCommitTxOutputs(localPaysCommitTxFees = true, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, toLocalFunderBelowDust, DefaultCommitmentFormat) assert(outputs.map(_.commitmentOutput) == Seq(CommitmentOutput.ToRemote)) assert(outputs.head.output.amount.toMilliSatoshi == toLocalFunderBelowDust.toRemote) } { val toRemoteFunderBelowDust = spec.copy(toRemote = belowDustWithFee) - val outputs = makeCommitTxOutputs(localIsInitiator = false, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, toRemoteFunderBelowDust, DefaultCommitmentFormat) + val outputs = makeCommitTxOutputs(localPaysCommitTxFees = false, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, toRemoteFunderBelowDust, DefaultCommitmentFormat) assert(outputs.map(_.commitmentOutput) == Seq(CommitmentOutput.ToLocal)) assert(outputs.head.output.amount.toMilliSatoshi == toRemoteFunderBelowDust.toLocal) } { val toLocalFundeeBelowDust = spec.copy(toLocal = belowDust) - val outputs = makeCommitTxOutputs(localIsInitiator = false, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, toLocalFundeeBelowDust, DefaultCommitmentFormat) + val outputs = makeCommitTxOutputs(localPaysCommitTxFees = false, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, toLocalFundeeBelowDust, DefaultCommitmentFormat) assert(outputs.map(_.commitmentOutput) == Seq(CommitmentOutput.ToRemote)) assert(outputs.head.output.amount.toMilliSatoshi == toLocalFundeeBelowDust.toRemote - commitFee) } { val allBelowDust = spec.copy(toLocal = belowDust, toRemote = belowDust) - val outputs = makeCommitTxOutputs(localIsInitiator = true, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, allBelowDust, DefaultCommitmentFormat) + val outputs = makeCommitTxOutputs(localPaysCommitTxFees = true, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, allBelowDust, DefaultCommitmentFormat) assert(outputs.isEmpty) } } @@ -285,18 +285,18 @@ class TransactionsSpec extends AnyFunSuite with Logging { toLocal = 400.millibtc.toMilliSatoshi, toRemote = 300.millibtc.toMilliSatoshi) - val outputs = makeCommitTxOutputs(localIsInitiator = true, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, spec, DefaultCommitmentFormat) + val outputs = makeCommitTxOutputs(localPaysCommitTxFees = true, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, spec, DefaultCommitmentFormat) val commitTxNumber = 0x404142434445L val commitTx = { - val txInfo = makeCommitTx(commitInput, commitTxNumber, localPaymentPriv.publicKey, remotePaymentPriv.publicKey, localIsInitiator = true, outputs) + val txInfo = makeCommitTx(commitInput, commitTxNumber, localPaymentPriv.publicKey, remotePaymentPriv.publicKey, localIsChannelOpener = true, outputs) val localSig = Transactions.sign(txInfo, localPaymentPriv, TxOwner.Local, DefaultCommitmentFormat) val remoteSig = Transactions.sign(txInfo, remotePaymentPriv, TxOwner.Remote, DefaultCommitmentFormat) Transactions.addSigs(txInfo, localFundingPriv.publicKey, remoteFundingPriv.publicKey, localSig, remoteSig) } { - assert(getCommitTxNumber(commitTx.tx, isInitiator = true, localPaymentPriv.publicKey, remotePaymentPriv.publicKey) == commitTxNumber) + assert(getCommitTxNumber(commitTx.tx, localIsChannelOpener = true, localPaymentPriv.publicKey, remotePaymentPriv.publicKey) == commitTxNumber) val hash = Crypto.sha256(localPaymentPriv.publicKey.value ++ remotePaymentPriv.publicKey.value) val num = Protocol.uint64(hash.takeRight(8).toArray, ByteOrder.BIG_ENDIAN) & 0xffffffffffffL val check = ((commitTx.tx.txIn.head.sequence & 0xffffff) << 24) | (commitTx.tx.lockTime & 0xffffff) @@ -444,7 +444,7 @@ class TransactionsSpec extends AnyFunSuite with Logging { val belowDustWithFeeAndAnchors = (localDustLimit + commitFeeAndAnchorCost * 0.9).toMilliSatoshi { - val outputs = makeCommitTxOutputs(localIsInitiator = true, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, spec, UnsafeLegacyAnchorOutputsCommitmentFormat) + val outputs = makeCommitTxOutputs(localPaysCommitTxFees = true, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, spec, UnsafeLegacyAnchorOutputsCommitmentFormat) assert(outputs.map(_.commitmentOutput).toSet == Set(CommitmentOutput.ToLocal, CommitmentOutput.ToRemote, CommitmentOutput.ToLocalAnchor, CommitmentOutput.ToRemoteAnchor)) assert(outputs.find(_.commitmentOutput == CommitmentOutput.ToLocalAnchor).get.output.amount == anchorAmount) assert(outputs.find(_.commitmentOutput == CommitmentOutput.ToRemoteAnchor).get.output.amount == anchorAmount) @@ -453,35 +453,35 @@ class TransactionsSpec extends AnyFunSuite with Logging { } { val toRemoteFundeeBelowDust = spec.copy(toRemote = belowDust) - val outputs = makeCommitTxOutputs(localIsInitiator = true, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, toRemoteFundeeBelowDust, UnsafeLegacyAnchorOutputsCommitmentFormat) + val outputs = makeCommitTxOutputs(localPaysCommitTxFees = true, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, toRemoteFundeeBelowDust, UnsafeLegacyAnchorOutputsCommitmentFormat) assert(outputs.map(_.commitmentOutput).toSet == Set(CommitmentOutput.ToLocal, CommitmentOutput.ToLocalAnchor)) assert(outputs.find(_.commitmentOutput == CommitmentOutput.ToLocalAnchor).get.output.amount == anchorAmount) assert(outputs.find(_.commitmentOutput == CommitmentOutput.ToLocal).get.output.amount.toMilliSatoshi == spec.toLocal - commitFeeAndAnchorCost) } { val toLocalFunderBelowDust = spec.copy(toLocal = belowDustWithFeeAndAnchors) - val outputs = makeCommitTxOutputs(localIsInitiator = true, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, toLocalFunderBelowDust, UnsafeLegacyAnchorOutputsCommitmentFormat) + val outputs = makeCommitTxOutputs(localPaysCommitTxFees = true, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, toLocalFunderBelowDust, UnsafeLegacyAnchorOutputsCommitmentFormat) assert(outputs.map(_.commitmentOutput).toSet == Set(CommitmentOutput.ToRemote, CommitmentOutput.ToRemoteAnchor)) assert(outputs.find(_.commitmentOutput == CommitmentOutput.ToRemoteAnchor).get.output.amount == anchorAmount) assert(outputs.find(_.commitmentOutput == CommitmentOutput.ToRemote).get.output.amount.toMilliSatoshi == spec.toRemote) } { val toRemoteFunderBelowDust = spec.copy(toRemote = belowDustWithFeeAndAnchors) - val outputs = makeCommitTxOutputs(localIsInitiator = false, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, toRemoteFunderBelowDust, UnsafeLegacyAnchorOutputsCommitmentFormat) + val outputs = makeCommitTxOutputs(localPaysCommitTxFees = false, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, toRemoteFunderBelowDust, UnsafeLegacyAnchorOutputsCommitmentFormat) assert(outputs.map(_.commitmentOutput).toSet == Set(CommitmentOutput.ToLocal, CommitmentOutput.ToLocalAnchor)) assert(outputs.find(_.commitmentOutput == CommitmentOutput.ToLocalAnchor).get.output.amount == anchorAmount) assert(outputs.find(_.commitmentOutput == CommitmentOutput.ToLocal).get.output.amount.toMilliSatoshi == spec.toLocal) } { val toLocalFundeeBelowDust = spec.copy(toLocal = belowDust) - val outputs = makeCommitTxOutputs(localIsInitiator = false, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, toLocalFundeeBelowDust, UnsafeLegacyAnchorOutputsCommitmentFormat) + val outputs = makeCommitTxOutputs(localPaysCommitTxFees = false, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, toLocalFundeeBelowDust, UnsafeLegacyAnchorOutputsCommitmentFormat) assert(outputs.map(_.commitmentOutput).toSet == Set(CommitmentOutput.ToRemote, CommitmentOutput.ToRemoteAnchor)) assert(outputs.find(_.commitmentOutput == CommitmentOutput.ToRemoteAnchor).get.output.amount == anchorAmount) assert(outputs.find(_.commitmentOutput == CommitmentOutput.ToRemote).get.output.amount.toMilliSatoshi == spec.toRemote - commitFeeAndAnchorCost) } { val allBelowDust = spec.copy(toLocal = belowDust, toRemote = belowDust) - val outputs = makeCommitTxOutputs(localIsInitiator = true, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, allBelowDust, UnsafeLegacyAnchorOutputsCommitmentFormat) + val outputs = makeCommitTxOutputs(localPaysCommitTxFees = true, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, allBelowDust, UnsafeLegacyAnchorOutputsCommitmentFormat) assert(outputs.isEmpty) } } @@ -525,8 +525,8 @@ class TransactionsSpec extends AnyFunSuite with Logging { val (commitTx, commitTxOutputs, htlcTimeoutTxs, htlcSuccessTxs) = { val commitTxNumber = 0x404142434445L - val outputs = makeCommitTxOutputs(localIsInitiator = true, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, spec, UnsafeLegacyAnchorOutputsCommitmentFormat) - val txInfo = makeCommitTx(commitInput, commitTxNumber, localPaymentPriv.publicKey, remotePaymentPriv.publicKey, localIsInitiator = true, outputs) + val outputs = makeCommitTxOutputs(localPaysCommitTxFees = true, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, spec, UnsafeLegacyAnchorOutputsCommitmentFormat) + val txInfo = makeCommitTx(commitInput, commitTxNumber, localPaymentPriv.publicKey, remotePaymentPriv.publicKey, localIsChannelOpener = true, outputs) val localSig = Transactions.sign(txInfo, localPaymentPriv, TxOwner.Local, UnsafeLegacyAnchorOutputsCommitmentFormat) val remoteSig = Transactions.sign(txInfo, remotePaymentPriv, TxOwner.Remote, UnsafeLegacyAnchorOutputsCommitmentFormat) val commitTx = Transactions.addSigs(txInfo, localFundingPriv.publicKey, remoteFundingPriv.publicKey, localSig, remoteSig) @@ -542,8 +542,8 @@ class TransactionsSpec extends AnyFunSuite with Logging { assert(htlcSuccessTxs.size == 3) // htlc2a, htlc2b and htlc4 assert(htlcSuccessTxs.map(_.htlcId).toSet == Set(1, 2, 4)) - val zeroFeeOutputs = makeCommitTxOutputs(localIsInitiator = true, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, spec, ZeroFeeHtlcTxAnchorOutputsCommitmentFormat) - val zeroFeeCommitTx = makeCommitTx(commitInput, commitTxNumber, localPaymentPriv.publicKey, remotePaymentPriv.publicKey, localIsInitiator = true, zeroFeeOutputs) + val zeroFeeOutputs = makeCommitTxOutputs(localPaysCommitTxFees = true, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, spec, ZeroFeeHtlcTxAnchorOutputsCommitmentFormat) + val zeroFeeCommitTx = makeCommitTx(commitInput, commitTxNumber, localPaymentPriv.publicKey, remotePaymentPriv.publicKey, localIsChannelOpener = true, zeroFeeOutputs) val zeroFeeHtlcTxs = makeHtlcTxs(zeroFeeCommitTx.tx, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, spec.htlcTxFeerate(ZeroFeeHtlcTxAnchorOutputsCommitmentFormat), zeroFeeOutputs, ZeroFeeHtlcTxAnchorOutputsCommitmentFormat) assert(zeroFeeHtlcTxs.length == 7) val zeroFeeConfirmationTargets = zeroFeeHtlcTxs.map(tx => tx.htlcId -> tx.confirmationTarget.confirmBefore.toLong).toMap @@ -780,8 +780,8 @@ class TransactionsSpec extends AnyFunSuite with Logging { val commitTxNumber = 0x404142434446L val (commitTx, outputs, htlcTxs) = { - val outputs = makeCommitTxOutputs(localIsInitiator = true, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, spec, DefaultCommitmentFormat) - val txInfo = makeCommitTx(commitInput, commitTxNumber, localPaymentPriv.publicKey, remotePaymentPriv.publicKey, localIsInitiator = true, outputs) + val outputs = makeCommitTxOutputs(localPaysCommitTxFees = true, localDustLimit, localRevocationPriv.publicKey, toLocalDelay, localDelayedPaymentPriv.publicKey, remotePaymentPriv.publicKey, localHtlcPriv.publicKey, remoteHtlcPriv.publicKey, localFundingPriv.publicKey, remoteFundingPriv.publicKey, spec, DefaultCommitmentFormat) + val txInfo = makeCommitTx(commitInput, commitTxNumber, localPaymentPriv.publicKey, remotePaymentPriv.publicKey, localIsChannelOpener = true, outputs) val localSig = Transactions.sign(txInfo, localPaymentPriv, TxOwner.Local, DefaultCommitmentFormat) val remoteSig = Transactions.sign(txInfo, remotePaymentPriv, TxOwner.Remote, DefaultCommitmentFormat) val commitTx = Transactions.addSigs(txInfo, localFundingPriv.publicKey, remoteFundingPriv.publicKey, localSig, remoteSig) @@ -819,7 +819,7 @@ class TransactionsSpec extends AnyFunSuite with Logging { { // Different amounts, both outputs untrimmed, local is funder: val spec = CommitmentSpec(Set.empty, feeratePerKw, 150_000_000 msat, 250_000_000 msat) - val closingTx = makeClosingTx(commitInput, localPubKeyScript, remotePubKeyScript, localIsInitiator = true, localDustLimit, 1000 sat, spec) + val closingTx = makeClosingTx(commitInput, localPubKeyScript, remotePubKeyScript, localPaysClosingFees = true, localDustLimit, 1000 sat, spec) assert(closingTx.tx.txOut.length == 2) assert(closingTx.toLocalOutput !== None) val toLocal = closingTx.toLocalOutput.get @@ -831,7 +831,7 @@ class TransactionsSpec extends AnyFunSuite with Logging { { // Same amounts, both outputs untrimmed, local is fundee: val spec = CommitmentSpec(Set.empty, feeratePerKw, 150_000_000 msat, 150_000_000 msat) - val closingTx = makeClosingTx(commitInput, localPubKeyScript, remotePubKeyScript, localIsInitiator = false, localDustLimit, 1000 sat, spec) + val closingTx = makeClosingTx(commitInput, localPubKeyScript, remotePubKeyScript, localPaysClosingFees = false, localDustLimit, 1000 sat, spec) assert(closingTx.tx.txOut.length == 2) assert(closingTx.toLocalOutput !== None) val toLocal = closingTx.toLocalOutput.get @@ -843,7 +843,7 @@ class TransactionsSpec extends AnyFunSuite with Logging { { // Their output is trimmed: val spec = CommitmentSpec(Set.empty, feeratePerKw, 150_000_000 msat, 1_000 msat) - val closingTx = makeClosingTx(commitInput, localPubKeyScript, remotePubKeyScript, localIsInitiator = false, localDustLimit, 1000 sat, spec) + val closingTx = makeClosingTx(commitInput, localPubKeyScript, remotePubKeyScript, localPaysClosingFees = false, localDustLimit, 1000 sat, spec) assert(closingTx.tx.txOut.length == 1) assert(closingTx.toLocalOutput !== None) val toLocal = closingTx.toLocalOutput.get @@ -854,16 +854,16 @@ class TransactionsSpec extends AnyFunSuite with Logging { { // Our output is trimmed: val spec = CommitmentSpec(Set.empty, feeratePerKw, 50_000 msat, 150_000_000 msat) - val closingTx = makeClosingTx(commitInput, localPubKeyScript, remotePubKeyScript, localIsInitiator = true, localDustLimit, 1000 sat, spec) + val closingTx = makeClosingTx(commitInput, localPubKeyScript, remotePubKeyScript, localPaysClosingFees = true, localDustLimit, 1000 sat, spec) assert(closingTx.tx.txOut.length == 1) - assert(closingTx.toLocalOutput == None) + assert(closingTx.toLocalOutput.isEmpty) } { // Both outputs are trimmed: val spec = CommitmentSpec(Set.empty, feeratePerKw, 50_000 msat, 10_000 msat) - val closingTx = makeClosingTx(commitInput, localPubKeyScript, remotePubKeyScript, localIsInitiator = true, localDustLimit, 1000 sat, spec) + val closingTx = makeClosingTx(commitInput, localPubKeyScript, remotePubKeyScript, localPaysClosingFees = true, localDustLimit, 1000 sat, spec) assert(closingTx.tx.txOut.isEmpty) - assert(closingTx.toLocalOutput == None) + assert(closingTx.toLocalOutput.isEmpty) } } 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 b6df964c9c..3c28b2ce35 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 @@ -263,7 +263,8 @@ object ChannelCodecsSpec { maxAcceptedHtlcs = 50, upfrontShutdownScript_opt = None, walletStaticPaymentBasepoint = None, - isInitiator = true, + isChannelOpener = true, + paysCommitTxFees = true, initFeatures = Features.empty) val remoteParams: RemoteParams = RemoteParams( @@ -320,7 +321,7 @@ object ChannelCodecsSpec { val localCommit = LocalCommit(0, CommitmentSpec(htlcs.toSet, FeeratePerKw(1500 sat), 50000000 msat, 70000000 msat), CommitTxAndRemoteSig(CommitTx(commitmentInput, commitTx), remoteSig), Nil) val remoteCommit = RemoteCommit(0, CommitmentSpec(htlcs.map(_.opposite).toSet, FeeratePerKw(1500 sat), 50000 msat, 700000 msat), TxId.fromValidHex("0303030303030303030303030303030303030303030303030303030303030303"), PrivateKey(ByteVector.fill(32)(4)).publicKey) val channelId = htlcs.headOption.map(_.add.channelId).getOrElse(ByteVector32.Zeroes) - val channelFlags = ChannelFlags.Public + val channelFlags = ChannelFlags(announceChannel = true) val commitments = Commitments( ChannelParams(channelId, ChannelConfig.standard, ChannelFeatures(), localParams, remoteParams, channelFlags), CommitmentChanges(LocalChanges(Nil, Nil, Nil), RemoteChanges(Nil, Nil, Nil), localNextHtlcId = 32, remoteNextHtlcId = 4), 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 a1706baef6..fdc46ffe48 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 @@ -58,6 +58,7 @@ class ChannelCodecs4Spec extends AnyFunSuite { CltvExpiryDelta(36), 50, Random.nextBoolean(), + Random.nextBoolean(), Some(hex"deadbeef"), None, Features().initFeatures()) @@ -186,4 +187,18 @@ class ChannelCodecs4Spec extends AnyFunSuite { ) assert(decoded == dualFundedUnconfirmedFundingTx) } + + test("decode local params pay commit tx fees field") { + // The data in this test was encoded using eclair v0.10.0, where a single is_initiator boolean was encoded instead + // 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) + 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) + } + } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/wire/protocol/LightningMessageCodecsSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/wire/protocol/LightningMessageCodecsSpec.scala index 5ef50916d7..685bea7074 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/wire/protocol/LightningMessageCodecsSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/wire/protocol/LightningMessageCodecsSpec.scala @@ -214,7 +214,7 @@ class LightningMessageCodecsSpec extends AnyFunSuite { } test("encode/decode open_channel") { - val defaultOpen = OpenChannel(BlockHash(ByteVector32.Zeroes), ByteVector32.Zeroes, 1 sat, 1 msat, 1 sat, UInt64(1), 1 sat, 1 msat, FeeratePerKw(1 sat), CltvExpiryDelta(1), 1, publicKey(1), point(2), point(3), point(4), point(5), point(6), ChannelFlags.Private) + val defaultOpen = OpenChannel(BlockHash(ByteVector32.Zeroes), ByteVector32.Zeroes, 1 sat, 1 msat, 1 sat, UInt64(1), 1 sat, 1 msat, FeeratePerKw(1 sat), CltvExpiryDelta(1), 1, publicKey(1), point(2), point(3), point(4), point(5), point(6), ChannelFlags(announceChannel = false)) // Legacy encoding that omits the upfront_shutdown_script and trailing tlv stream. // To allow extending all messages with TLV streams, the upfront_shutdown_script was moved to a TLV stream extension // in https://github.com/lightningnetwork/lightning-rfc/pull/714 and made mandatory when including a TLV stream. @@ -382,7 +382,7 @@ class LightningMessageCodecsSpec extends AnyFunSuite { test("encode/decode all channel messages") { val unknownTlv = GenericTlv(UInt64(5), ByteVector.fromValidHex("deadbeef")) val msgs = List( - OpenChannel(BlockHash(randomBytes32()), randomBytes32(), 3 sat, 4 msat, 5 sat, UInt64(6), 7 sat, 8 msat, FeeratePerKw(9 sat), CltvExpiryDelta(10), 11, publicKey(1), point(2), point(3), point(4), point(5), point(6), ChannelFlags.Private), + OpenChannel(BlockHash(randomBytes32()), randomBytes32(), 3 sat, 4 msat, 5 sat, UInt64(6), 7 sat, 8 msat, FeeratePerKw(9 sat), CltvExpiryDelta(10), 11, publicKey(1), point(2), point(3), point(4), point(5), point(6), ChannelFlags(announceChannel = false)), AcceptChannel(randomBytes32(), 3 sat, UInt64(4), 5 sat, 6 msat, 7, CltvExpiryDelta(8), 9, publicKey(1), point(2), point(3), point(4), point(5), point(6)), FundingCreated(randomBytes32(), TxId(ByteVector32.Zeroes), 3, randomBytes64()), FundingSigned(randomBytes32(), randomBytes64()), diff --git a/eclair-node/src/test/scala/fr/acinq/eclair/api/ApiServiceSpec.scala b/eclair-node/src/test/scala/fr/acinq/eclair/api/ApiServiceSpec.scala index e3f91a3dac..aabcd8eb09 100644 --- a/eclair-node/src/test/scala/fr/acinq/eclair/api/ApiServiceSpec.scala +++ b/eclair-node/src/test/scala/fr/acinq/eclair/api/ApiServiceSpec.scala @@ -1208,8 +1208,8 @@ class ApiServiceSpec extends AnyFunSuite with ScalatestRouteTest with IdiomaticM system.eventStream.publish(pset) wsClient.expectMessage(expectedSerializedPset) - val chcr = ChannelCreated(system.deadLetters, system.deadLetters, bobNodeId, isInitiator = true, ByteVector32.One, FeeratePerKw(25 sat), Some(FeeratePerKw(20 sat))) - val expectedSerializedChcr = """{"type":"channel-created","remoteNodeId":"039dc0e0b1d25905e44fdf6f8e89755a5e219685840d0bc1d28d3308f9628a3585","isInitiator":true,"temporaryChannelId":"0100000000000000000000000000000000000000000000000000000000000000","commitTxFeeratePerKw":25,"fundingTxFeeratePerKw":20}""" + val chcr = ChannelCreated(system.deadLetters, system.deadLetters, bobNodeId, isOpener = true, ByteVector32.One, FeeratePerKw(25 sat), Some(FeeratePerKw(20 sat))) + val expectedSerializedChcr = """{"type":"channel-created","remoteNodeId":"039dc0e0b1d25905e44fdf6f8e89755a5e219685840d0bc1d28d3308f9628a3585","isOpener":true,"temporaryChannelId":"0100000000000000000000000000000000000000000000000000000000000000","commitTxFeeratePerKw":25,"fundingTxFeeratePerKw":20}""" assert(serialization.write(chcr) == expectedSerializedChcr) system.eventStream.publish(chcr) wsClient.expectMessage(expectedSerializedChcr)