1
0
Fork 0
mirror of https://github.com/ACINQ/eclair.git synced 2025-02-22 22:25:26 +01:00

Remove minDepth from InteractiveTxParams (#2635)

We can recompute `minDepth` based on our default config, the channel
capacity and our local features.

The only parameter that could change is our local features, which could
create issues if we enable/disable zero-conf in the middle of a funding
attempt: we may accept an RBF attempt for a transaction that we previously
treated as zero-conf, which will break the channel. But since activating
zero-conf means we have trust in our peer, and this is an unlikely
scenario, this is acceptable.

Co-authored-by: Pierre-Marie Padiou <pm47@users.noreply.github.com>
This commit is contained in:
Bastien Teinturier 2023-05-03 16:22:04 +02:00 committed by GitHub
parent a58b7e8fa8
commit 25f4cd2df4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 59 additions and 44 deletions

View file

@ -8,6 +8,7 @@ import fr.acinq.eclair.blockchain.fee.{FeeratePerKw, OnChainFeeConf}
import fr.acinq.eclair.channel.Helpers.Closing
import fr.acinq.eclair.channel.Monitoring.Metrics
import fr.acinq.eclair.channel.fsm.Channel
import fr.acinq.eclair.channel.fund.InteractiveTxBuilder.SharedTransaction
import fr.acinq.eclair.crypto.keymanager.ChannelKeyManager
import fr.acinq.eclair.crypto.{Generators, ShaChain}
import fr.acinq.eclair.payment.OutgoingPaymentPacket
@ -66,13 +67,14 @@ case class ChannelParams(channelId: ByteVector32,
* be able to steal the entire channel funding, but would likely miss block rewards during that process, making it
* economically irrational for them.
*
* @param fundingSatoshis funding amount of the channel
* @param fundingAmount funding amount of the channel
* @return number of confirmations needed, if any
*/
def minDepthFundee(defaultMinDepth: Int, fundingSatoshis: Satoshi): Option[Long] = fundingSatoshis match {
case _ if localParams.initFeatures.hasFeature(Features.ZeroConf) => None // zero-conf stay zero-conf, whatever the funding amount is
case funding if funding <= Channel.MAX_FUNDING_WITHOUT_WUMBO => Some(defaultMinDepth)
case funding => Some(ChannelParams.minDepthScaled(defaultMinDepth, funding))
def minDepthFundee(defaultMinDepth: Int, fundingAmount: Satoshi): Option[Long] =
if (localParams.initFeatures.hasFeature(Features.ZeroConf)) {
None // zero-conf stay zero-conf, whatever the funding amount is
} else {
Some(ChannelParams.minDepthScaled(defaultMinDepth, fundingAmount))
}
/**
@ -80,16 +82,25 @@ case class ChannelParams(channelId: ByteVector32,
* - our peer may also contribute to the funding transaction, even if they don't contribute to the channel funding amount
* - even if they don't, we may RBF the transaction and don't want to handle reorgs
*
* @param fundingAmount the total target channel funding amount, including local and remote contributions.
* @param fundingAmount total funding amount of the channel.
* @param remoteContributes_opt true if the remote has the ability to double-spend the transaction (even if they're
* not contributing to the shared funding amount). Should be empty if we don't know yet
* if the remote will contribute to the shared transaction.
*/
def minDepthDualFunding(defaultMinDepth: Int, fundingAmount: Satoshi): Option[Long] = {
def minDepthDualFunding(defaultMinDepth: Int, fundingAmount: Satoshi, remoteContributes_opt: Option[Boolean] = None): Option[Long] = {
if (localParams.initFeatures.hasFeature(Features.ZeroConf)) {
None
} else {
minDepthFundee(defaultMinDepth, fundingAmount)
Some(ChannelParams.minDepthScaled(defaultMinDepth, fundingAmount))
}
}
/**
* When the shared transaction has been built and we know exactly how our peer is going to contribute, we can compute
* the real min_depth that we are going to actually use.
*/
def minDepthDualFunding(defaultMinDepth: Int, sharedTx: SharedTransaction): Option[Long] = minDepthDualFunding(defaultMinDepth, sharedTx.sharedOutput.amount, Some(sharedTx.remoteInputs.nonEmpty))
/**
*
* @param localScriptPubKey local script pubkey (provided in CMD_CLOSE, as an upfront shutdown script, or set to the current final onchain script)
@ -122,12 +133,17 @@ case class ChannelParams(channelId: ByteVector32,
object ChannelParams {
def minDepthScaled(defaultMinDepth: Int, amount: Satoshi): Int = {
if (amount <= Channel.MAX_FUNDING_WITHOUT_WUMBO) {
// small amount: not scaled
defaultMinDepth
} else {
val blockReward = 6.25 // this is true as of ~May 2020, but will be too large after 2024
val scalingFactor = 15
val blocksToReachFunding = (((scalingFactor * amount.toBtc.toDouble) / blockReward).ceil + 1).toInt
defaultMinDepth.max(blocksToReachFunding)
}
}
}
// @formatter:off
case class LocalChanges(proposed: List[UpdateMessage], signed: List[UpdateMessage], acked: List[UpdateMessage]) {

View file

@ -267,7 +267,8 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with
watchFundingConfirmed(commitment.fundingTxId, Some(singleFundingMinDepth(data)))
case fundingTx: LocalFundingStatus.DualFundedUnconfirmedFundingTx =>
publishFundingTx(fundingTx)
watchFundingConfirmed(fundingTx.sharedTx.txId, fundingTx.fundingParams.minDepth_opt)
val minDepth_opt = data.commitments.params.minDepthDualFunding(nodeParams.channelConf.minDepthBlocks, fundingTx.sharedTx.tx)
watchFundingConfirmed(fundingTx.sharedTx.txId, minDepth_opt)
case fundingTx: LocalFundingStatus.ZeroconfPublishedFundingTx =>
// those are zero-conf channels, the min-depth isn't critical, we use the default
watchFundingConfirmed(fundingTx.tx.txid, Some(nodeParams.channelConf.minDepthBlocks.toLong))
@ -523,7 +524,8 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with
// We don't have their tx_sigs, but they have ours, and could publish the funding tx without telling us.
// That's why we move on immediately to the next step, and will update our unsigned funding tx when we
// receive their tx_sigs.
watchFundingConfirmed(signingSession.fundingTx.txId, signingSession.fundingParams.minDepth_opt)
val minDepth_opt = d.commitments.params.minDepthDualFunding(nodeParams.channelConf.minDepthBlocks, signingSession1.fundingTx.sharedTx.tx)
watchFundingConfirmed(signingSession.fundingTx.txId, minDepth_opt)
val commitments1 = d.commitments.add(signingSession1.commitment)
val d1 = d.copy(commitments = commitments1, spliceStatus = SpliceStatus.NoSplice)
stay() using d1 storing() sending signingSession1.localSigs
@ -828,7 +830,6 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with
pushAmount = 0.msat,
requireConfirmedInputs = nodeParams.channelConf.requireConfirmedInputsForDualFunding
)
val nextFundingAmount = parentCommitment.capacity + spliceAck.fundingContribution + msg.fundingContribution
val fundingParams = InteractiveTxParams(
channelId = d.channelId,
isInitiator = false,
@ -840,7 +841,6 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with
lockTime = nodeParams.currentBlockHeight.toLong,
dustLimit = d.commitments.params.localParams.dustLimit.max(d.commitments.params.remoteParams.dustLimit),
targetFeerate = msg.feerate,
minDepth_opt = d.commitments.params.minDepthDualFunding(nodeParams.channelConf.minDepthBlocks, nextFundingAmount),
requireConfirmedInputs = RequireConfirmedInputs(forLocal = msg.requireConfirmedInputs, forRemote = spliceAck.requireConfirmedInputs)
)
val txBuilder = context.spawnAnonymous(InteractiveTxBuilder(
@ -869,7 +869,6 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with
case SpliceStatus.SpliceRequested(cmd, spliceInit) =>
log.info("our peer accepted our splice request and will contribute {} to the funding transaction", msg.fundingContribution)
val parentCommitment = d.commitments.latest.commitment
val nextFundingAmount = parentCommitment.capacity + spliceInit.fundingContribution + msg.fundingContribution
val fundingParams = InteractiveTxParams(
channelId = d.channelId,
isInitiator = true,
@ -881,7 +880,6 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with
lockTime = spliceInit.lockTime,
dustLimit = d.commitments.params.localParams.dustLimit.max(d.commitments.params.remoteParams.dustLimit),
targetFeerate = spliceInit.feerate,
minDepth_opt = d.commitments.params.minDepthDualFunding(nodeParams.channelConf.minDepthBlocks, nextFundingAmount),
requireConfirmedInputs = RequireConfirmedInputs(forLocal = msg.requireConfirmedInputs, forRemote = spliceInit.requireConfirmedInputs)
)
val txBuilder = context.spawnAnonymous(InteractiveTxBuilder(
@ -983,7 +981,8 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with
rollbackFundingAttempt(signingSession.fundingTx.tx, previousTxs = Seq.empty) // no splice rbf yet
stay() using d.copy(spliceStatus = SpliceStatus.SpliceAborted) sending TxAbort(d.channelId, f.getMessage)
case Right(signingSession1) =>
watchFundingConfirmed(signingSession.fundingTx.txId, signingSession.fundingParams.minDepth_opt)
val minDepth_opt = d.commitments.params.minDepthDualFunding(nodeParams.channelConf.minDepthBlocks, signingSession1.fundingTx.sharedTx.tx)
watchFundingConfirmed(signingSession.fundingTx.txId, minDepth_opt)
val commitments1 = d.commitments.add(signingSession1.commitment)
val d1 = d.copy(commitments = commitments1, spliceStatus = SpliceStatus.NoSplice)
log.info("publishing funding tx for channelId={} fundingTxId={}", d.channelId, signingSession1.fundingTx.sharedTx.txId)

View file

@ -167,7 +167,10 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers {
val channelParams = ChannelParams(channelId, d.init.channelConfig, channelFeatures, localParams, remoteParams, open.channelFlags)
val localAmount = d.init.fundingContribution_opt.getOrElse(0 sat)
val remoteAmount = open.fundingAmount
val minDepth_opt = channelParams.minDepthDualFunding(nodeParams.channelConf.minDepthBlocks, localAmount + remoteAmount)
// At this point, the min_depth is an estimate and may change after we know exactly how our peer contributes
// to the funding transaction. Maybe they will contribute 0 satoshis to the shared output, but still add inputs
// and outputs.
val minDepth_opt = channelParams.minDepthFundee(nodeParams.channelConf.minDepthBlocks, localAmount + remoteAmount)
val upfrontShutdownScript_opt = localParams.upfrontShutdownScript_opt.map(scriptPubKey => ChannelTlv.UpfrontShutdownScriptTlv(scriptPubKey))
val tlvs: Set[AcceptDualFundedChannelTlv] = Set(
upfrontShutdownScript_opt,
@ -207,7 +210,6 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers {
lockTime = open.lockTime,
dustLimit = open.dustLimit.max(accept.dustLimit),
targetFeerate = open.fundingFeerate,
minDepth_opt = minDepth_opt,
requireConfirmedInputs = RequireConfirmedInputs(forLocal = open.requireConfirmedInputs, forRemote = accept.requireConfirmedInputs)
)
@ -260,7 +262,6 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers {
val channelParams = ChannelParams(channelId, d.init.channelConfig, channelFeatures, localParams, remoteParams, d.lastSent.channelFlags)
val localAmount = d.lastSent.fundingAmount
val remoteAmount = accept.fundingAmount
val minDepth_opt = channelParams.minDepthDualFunding(nodeParams.channelConf.minDepthBlocks, localAmount + remoteAmount)
val fundingParams = InteractiveTxParams(
channelId = channelId,
isInitiator = localParams.isInitiator,
@ -272,7 +273,6 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers {
lockTime = d.lastSent.lockTime,
dustLimit = d.lastSent.dustLimit.max(accept.dustLimit),
targetFeerate = d.lastSent.fundingFeerate,
minDepth_opt = minDepth_opt,
requireConfirmedInputs = RequireConfirmedInputs(forLocal = accept.requireConfirmedInputs, forRemote = d.lastSent.requireConfirmedInputs)
)
val purpose = InteractiveTxBuilder.FundingTx(d.lastSent.commitmentFeerate, accept.firstPerCommitmentPoint)
@ -377,7 +377,8 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers {
// We don't have their tx_sigs, but they have ours, and could publish the funding tx without telling us.
// That's why we move on immediately to the next step, and will update our unsigned funding tx when we
// receive their tx_sigs.
watchFundingConfirmed(d.signingSession.fundingTx.txId, d.signingSession.fundingParams.minDepth_opt)
val minDepth_opt = d.channelParams.minDepthDualFunding(nodeParams.channelConf.minDepthBlocks, signingSession1.fundingTx.sharedTx.tx)
watchFundingConfirmed(d.signingSession.fundingTx.txId, minDepth_opt)
val commitments = Commitments(
params = d.channelParams,
changes = CommitmentChanges.init(),
@ -399,7 +400,8 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers {
rollbackFundingAttempt(d.signingSession.fundingTx.tx, Nil)
goto(CLOSED) sending Error(d.channelId, f.getMessage)
case Right(signingSession) =>
watchFundingConfirmed(d.signingSession.fundingTx.txId, d.signingSession.fundingParams.minDepth_opt)
val minDepth_opt = d.channelParams.minDepthDualFunding(nodeParams.channelConf.minDepthBlocks, signingSession.fundingTx.sharedTx.tx)
watchFundingConfirmed(d.signingSession.fundingTx.txId, minDepth_opt)
val commitments = Commitments(
params = d.channelParams,
changes = CommitmentChanges.init(),
@ -463,7 +465,8 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers {
rollbackRbfAttempt(signingSession, d)
stay() using d.copy(rbfStatus = RbfStatus.RbfAborted) sending TxAbort(d.channelId, f.getMessage)
case Right(signingSession1) =>
watchFundingConfirmed(signingSession.fundingTx.txId, signingSession.fundingParams.minDepth_opt)
val minDepth_opt = d.commitments.params.minDepthDualFunding(nodeParams.channelConf.minDepthBlocks, signingSession1.fundingTx.sharedTx.tx)
watchFundingConfirmed(signingSession.fundingTx.txId, minDepth_opt)
val commitments1 = d.commitments.add(signingSession1.commitment)
val d1 = DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED(commitments1, d.localPushAmount, d.remotePushAmount, d.waitingSince, d.lastChecked, RbfStatus.NoRbf, d.deferred)
stay() using d1 storing() sending signingSession1.localSigs calling publishFundingTx(signingSession1.fundingTx)
@ -476,7 +479,7 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers {
}
case Event(cmd: CMD_BUMP_FUNDING_FEE, d: DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED) =>
val zeroConf = d.latestFundingTx.fundingParams.minDepth_opt.isEmpty
val zeroConf = d.commitments.params.minDepthDualFunding(nodeParams.channelConf.minDepthBlocks, d.latestFundingTx.sharedTx.tx).isEmpty
if (!d.latestFundingTx.fundingParams.isInitiator) {
cmd.replyTo ! RES_FAILURE(cmd, InvalidRbfNonInitiator(d.channelId))
stay()
@ -501,7 +504,7 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers {
}
case Event(msg: TxInitRbf, d: DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED) =>
val zeroConf = d.latestFundingTx.fundingParams.minDepth_opt.isEmpty
val zeroConf = d.commitments.params.minDepthDualFunding(nodeParams.channelConf.minDepthBlocks, d.latestFundingTx.sharedTx.tx).isEmpty
if (d.latestFundingTx.fundingParams.isInitiator) {
// Only the initiator is allowed to initiate RBF.
log.info("rejecting tx_init_rbf, we're the initiator, not them!")
@ -570,8 +573,6 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers {
remoteContribution = msg.fundingContribution,
lockTime = cmd.lockTime,
targetFeerate = cmd.targetFeerate,
// we now have more than one version of the funding tx, so we cannot use zero-conf.
minDepth_opt = d.latestFundingTx.fundingParams.minDepth_opt.orElse(Some(nodeParams.channelConf.minDepthBlocks.toLong))
)
val txBuilder = context.spawnAnonymous(InteractiveTxBuilder(
nodeParams, fundingParams,
@ -611,7 +612,8 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers {
// No need to store their commit_sig, they will re-send it if we disconnect.
stay() using d.copy(rbfStatus = RbfStatus.RbfWaitingForSigs(signingSession1))
case signingSession1: InteractiveTxSigningSession.SendingSigs =>
watchFundingConfirmed(signingSession.fundingTx.txId, signingSession.fundingParams.minDepth_opt)
val minDepth_opt = d.commitments.params.minDepthDualFunding(nodeParams.channelConf.minDepthBlocks, signingSession1.fundingTx.sharedTx.tx)
watchFundingConfirmed(signingSession.fundingTx.txId, minDepth_opt)
val commitments1 = d.commitments.add(signingSession1.commitment)
val d1 = DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED(commitments1, d.localPushAmount, d.remotePushAmount, d.waitingSince, d.lastChecked, RbfStatus.NoRbf, d.deferred)
stay() using d1 storing() sending signingSession1.localSigs

View file

@ -17,7 +17,6 @@
package fr.acinq.eclair.channel.fsm
import fr.acinq.bitcoin.scalacompat.{Transaction, TxIn}
import fr.acinq.eclair.NotificationsLogger
import fr.acinq.eclair.NotificationsLogger.NotifyNodeOperator
import fr.acinq.eclair.blockchain.CurrentBlockHeight
import fr.acinq.eclair.channel.Helpers.Closing
@ -27,6 +26,7 @@ import fr.acinq.eclair.channel.fsm.Channel.BITCOIN_FUNDING_DOUBLE_SPENT
import fr.acinq.eclair.channel.fund.InteractiveTxBuilder._
import fr.acinq.eclair.channel.fund.{InteractiveTxBuilder, InteractiveTxSigningSession}
import fr.acinq.eclair.wire.protocol.{ChannelReady, Error}
import fr.acinq.eclair.{Features, NotificationsLogger}
import scala.concurrent.Future
import scala.util.{Failure, Success}
@ -57,8 +57,8 @@ trait DualFundingHandlers extends CommonFundingHandlers {
}
/** Return true if we should stop waiting for confirmations when receiving our peer's channel_ready. */
def switchToZeroConf(remoteChannelReady: ChannelReady, d: DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED): Boolean = d.latestFundingTx.fundingParams.minDepth_opt match {
case Some(_) =>
def switchToZeroConf(remoteChannelReady: ChannelReady, d: DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED): Boolean = {
if (!d.commitments.params.localParams.initFeatures.hasFeature(Features.ZeroConf)) {
// We're not using zero-conf, but our peer decided to trust us anyway. We can skip waiting for confirmations if:
// - they provided a channel alias
// - there is a single version of the funding tx (otherwise we don't know which one to use)
@ -66,11 +66,12 @@ trait DualFundingHandlers extends CommonFundingHandlers {
remoteChannelReady.alias_opt.isDefined &&
d.commitments.active.size == 1 &&
d.latestFundingTx.sharedTx.tx.remoteInputs.isEmpty
case None =>
} else {
// We're already using zero-conf, but our peer was very fast and we received their channel_ready before our
// watcher notification that the funding tx has been successfully published.
false
}
}
def handleNewBlockDualFundingUnconfirmed(c: CurrentBlockHeight, d: DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED) = {
// We regularly notify the node operator that they may want to RBF this channel.

View file

@ -146,7 +146,6 @@ object InteractiveTxBuilder {
lockTime: Long,
dustLimit: Satoshi,
targetFeerate: FeeratePerKw,
minDepth_opt: Option[Long],
requireConfirmedInputs: RequireConfirmedInputs) {
/** The amount of the new funding output, which is the sum of the shared input, if any, and both sides' contributions. */
val fundingAmount: Satoshi = sharedInput_opt.map(_.info.txOut.amount).getOrElse(0 sat) + localContribution + remoteContribution

View file

@ -231,7 +231,6 @@ private[channel] object ChannelCodecs4 {
("lockTime" | uint32) ::
("dustLimit" | satoshi) ::
("targetFeerate" | feeratePerKw) ::
("minDepth_opt" | optional(bool8, uint32)) ::
("requireConfirmedInputs" | requireConfirmedInputsCodec)).as[InteractiveTxBuilder.InteractiveTxParams]
private val sharedInteractiveTxInputCodec: Codec[InteractiveTxBuilder.Input.Shared] = (

View file

@ -105,8 +105,8 @@ class InteractiveTxBuilderSpec extends TestKitBaseClass with AnyFunSuiteLike wit
def createSpliceFixtureParams(fundingTxIndex: Long, fundingAmountA: Satoshi, fundingAmountB: Satoshi, targetFeerate: FeeratePerKw, dustLimit: Satoshi, lockTime: Long, sharedInputA: SharedFundingInput, sharedInputB: SharedFundingInput, spliceOutputsA: List[TxOut] = Nil, spliceOutputsB: List[TxOut] = Nil, requireConfirmedInputs: RequireConfirmedInputs = RequireConfirmedInputs(forLocal = false, forRemote = false)): FixtureParams = {
val fundingPubKeyA = nodeParamsA.channelKeyManager.fundingPublicKey(channelParamsA.localParams.fundingKeyPath, fundingTxIndex).publicKey
val fundingPubKeyB = nodeParamsB.channelKeyManager.fundingPublicKey(channelParamsB.localParams.fundingKeyPath, fundingTxIndex).publicKey
val fundingParamsA = InteractiveTxParams(channelId, isInitiator = true, fundingAmountA, fundingAmountB, Some(sharedInputA), fundingPubKeyB, spliceOutputsA, lockTime, dustLimit, targetFeerate, Some(3), requireConfirmedInputs)
val fundingParamsB = InteractiveTxParams(channelId, isInitiator = false, fundingAmountB, fundingAmountA, Some(sharedInputB), fundingPubKeyA, spliceOutputsB, lockTime, dustLimit, targetFeerate, Some(3), requireConfirmedInputs)
val fundingParamsA = InteractiveTxParams(channelId, isInitiator = true, fundingAmountA, fundingAmountB, Some(sharedInputA), fundingPubKeyB, spliceOutputsA, lockTime, dustLimit, targetFeerate, requireConfirmedInputs)
val fundingParamsB = InteractiveTxParams(channelId, isInitiator = false, fundingAmountB, fundingAmountA, Some(sharedInputB), fundingPubKeyA, spliceOutputsB, lockTime, dustLimit, targetFeerate, requireConfirmedInputs)
copy(fundingParamsA = fundingParamsA, fundingParamsB = fundingParamsB)
}
@ -214,8 +214,8 @@ class InteractiveTxBuilderSpec extends TestKitBaseClass with AnyFunSuiteLike wit
val channelId = randomBytes32()
val fundingPubKeyA = nodeParamsA.channelKeyManager.fundingPublicKey(localParamsA.fundingKeyPath, fundingTxIndex = 0).publicKey
val fundingPubKeyB = nodeParamsB.channelKeyManager.fundingPublicKey(localParamsB.fundingKeyPath, fundingTxIndex = 0).publicKey
val fundingParamsA = InteractiveTxParams(channelId, isInitiator = true, fundingAmountA, fundingAmountB, None, fundingPubKeyB, Nil, lockTime, dustLimit, targetFeerate, Some(3), requireConfirmedInputs)
val fundingParamsB = InteractiveTxParams(channelId, isInitiator = false, fundingAmountB, fundingAmountA, None, fundingPubKeyA, Nil, lockTime, dustLimit, targetFeerate, Some(3), requireConfirmedInputs)
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)

View file

@ -540,7 +540,6 @@ class WaitForDualFundingConfirmedStateSpec extends TestKitBaseClass with Fixture
.modify(_.commitments.active.at(0).localFundingStatus)
.setTo(fundingTx1)
alice.setState(alice.stateName, aliceData1)
assert(alice.stateData.asInstanceOf[DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED].latestFundingTx.fundingParams.minDepth_opt.nonEmpty)
assert(alice.stateData.asInstanceOf[DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED].latestFundingTx.fundingParams.remoteContribution == 0.sat)
assert(alice.stateData.asInstanceOf[DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED].latestFundingTx.sharedTx.tx.remoteInputs.nonEmpty)
bob ! WatchFundingConfirmedTriggered(BlockHeight(42000), 42, fundingTx1.sharedTx.asInstanceOf[FullySignedSharedTransaction].signedTx)

View file

@ -133,7 +133,7 @@ class ChannelCodecs4Spec extends AnyFunSuite {
Transaction(2, Seq(TxIn(fundingInput.outPoint, Nil, 0)), Seq(TxOut(150_000 sat, Script.pay2wpkh(randomKey().publicKey))), 0),
)
val waitingForSigs = InteractiveTxSigningSession.WaitingForSigs(
InteractiveTxParams(channelId, isInitiator = true, 100_000 sat, 75_000 sat, None, randomKey().publicKey, Nil, 0, 330 sat, FeeratePerKw(500 sat), None, RequireConfirmedInputs(forLocal = false, forRemote = false)),
InteractiveTxParams(channelId, isInitiator = true, 100_000 sat, 75_000 sat, None, randomKey().publicKey, Nil, 0, 330 sat, FeeratePerKw(500 sat), RequireConfirmedInputs(forLocal = false, forRemote = false)),
fundingTxIndex = 0,
PartiallySignedSharedTransaction(fundingTx, TxSignatures(channelId, randomBytes32(), Nil)),
Left(UnsignedLocalCommit(0, CommitmentSpec(Set.empty, FeeratePerKw(1000 sat), 100_000_000 msat, 75_000_000 msat), commitTx, Nil)),