mirror of
https://github.com/ACINQ/eclair.git
synced 2025-02-22 14:22:39 +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:
parent
a58b7e8fa8
commit
25f4cd2df4
9 changed files with 59 additions and 44 deletions
|
@ -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,30 +67,40 @@ 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))
|
||||
}
|
||||
|
||||
/**
|
||||
* When using dual funding or splices, we wait for multiple confirmations even if we're the initiator because:
|
||||
* - 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,10 +133,15 @@ case class ChannelParams(channelId: ByteVector32,
|
|||
|
||||
object ChannelParams {
|
||||
def minDepthScaled(defaultMinDepth: Int, amount: Satoshi): Int = {
|
||||
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)
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,10 +66,11 @@ 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) = {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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] = (
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)),
|
||||
|
|
Loading…
Add table
Reference in a new issue