Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use default confirmations for single-funded channel #3013

Merged
merged 2 commits into from
Feb 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,16 @@ case class ChannelParams(channelId: ByteVector32,
)

/**
* As funder we trust ourselves to not double spend funding txs: we could always use a zero-confirmation watch,
* but we need a scid to send the initial channel_update and remote may not provide an alias. That's why we always
* wait for one conf, except if the channel has the zero-conf feature (because presumably the peer will send an
* alias in that case).
* Returns the number of confirmations needed to safely handle a funding transaction that we unilaterally funded.
* As funder we trust ourselves to not double spend funding txs, so we don't need to scale the number of confirmations
* based on the funding amount. We want to wait a few blocks though to ensure that the short_channel_id we obtain will
* not be invalidated by a reorg.
*/
def minDepthFunder: Option[Long] = {
def minDepthFunder(defaultMinDepth: Int): Option[Long] = {
if (localParams.initFeatures.hasFeature(Features.ZeroConf)) {
None
} else {
Some(1)
Some(defaultMinDepth.toLong)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ trait ChannelOpenSingleFunded extends SingleFundingHandlers with ErrorHandlers {
val blockHeight = nodeParams.currentBlockHeight
context.system.eventStream.publish(ChannelSignatureReceived(self, commitments))
log.info(s"publishing funding tx fundingTxid=${commitment.fundingTxId}")
watchFundingConfirmed(commitment.fundingTxId, params.minDepthFunder, delay_opt = None)
watchFundingConfirmed(commitment.fundingTxId, params.minDepthFunder(nodeParams.channelConf.minDepth), delay_opt = None)
// we will publish the funding tx only after the channel state has been written to disk because we want to
// make sure we first persist the commitment that returns back the funds to us in case of problem
goto(WAIT_FOR_FUNDING_CONFIRMED) using DATA_WAIT_FOR_FUNDING_CONFIRMED(commitments, blockHeight, None, Left(fundingCreated)) storing() calling publishFundingTx(d.channelId, fundingTx, fundingTxFee, d.replyTo)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ trait SingleFundingHandlers extends CommonFundingHandlers {

def singleFundingMinDepth(d: ChannelDataWithCommitments): Long = {
val minDepth_opt = if (d.commitments.params.localParams.isChannelOpener) {
d.commitments.params.minDepthFunder
d.commitments.params.minDepthFunder(nodeParams.channelConf.minDepth)
} else {
// When we're not the channel initiator we scale the min_depth confirmations depending on the funding amount.
d.commitments.params.minDepthFundee(nodeParams.channelConf.minDepth, d.commitments.latest.commitInput.txOut.amount)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class WaitForFundingSignedStateSpec extends TestKitBaseClass with FixtureAnyFunS
awaitCond(alice.stateName == WAIT_FOR_FUNDING_CONFIRMED)
val watchConfirmed = alice2blockchain.expectMsgType[WatchFundingConfirmed]
val fundingTxId = watchConfirmed.txId
assert(watchConfirmed.minDepth == 1) // when funder we trust ourselves so we never wait more than 1 block
assert(watchConfirmed.minDepth == 6)
val txPublished = listener.expectMsgType[TransactionPublished]
assert(txPublished.tx.txid == fundingTxId)
assert(txPublished.miningFee > 0.sat)
Expand All @@ -117,7 +117,7 @@ class WaitForFundingSignedStateSpec extends TestKitBaseClass with FixtureAnyFunS
bob2alice.forward(alice)
awaitCond(alice.stateName == WAIT_FOR_FUNDING_CONFIRMED)
val watchConfirmed = alice2blockchain.expectMsgType[WatchFundingConfirmed]
assert(watchConfirmed.minDepth == 1) // when funder we trust ourselves so we never wait more than 1 block
assert(watchConfirmed.minDepth == 6) // when funder we don't scale the number of confirmations based on the funding amount
aliceOpenReplyTo.expectMsgType[OpenChannelResponse.Created]
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,13 +124,10 @@ abstract class ChannelIntegrationSpec extends IntegrationSpec {
connect(nodes("C"), nodes("F"), 5000000 sat, 500000000 msat)
awaitCond(stateListenerC.expectMsgType[ChannelStateChanged](max = 60 seconds).currentState == WAIT_FOR_FUNDING_CONFIRMED, max = 30 seconds)
awaitCond(stateListenerF.expectMsgType[ChannelStateChanged](max = 60 seconds).currentState == WAIT_FOR_FUNDING_CONFIRMED, max = 30 seconds)
generateBlocks(1, Some(minerAddress))
// the funder sends its channel_ready after only one block
awaitCond(stateListenerC.expectMsgType[ChannelStateChanged](max = 60 seconds).currentState == WAIT_FOR_CHANNEL_READY, max = 30 seconds)
generateBlocks(5, Some(minerAddress))
// the fundee sends its channel_ready after 6 blocks
awaitCond(stateListenerF.expectMsgType[ChannelStateChanged](max = 60 seconds).currentState == NORMAL, max = 30 seconds)
// we exchange channel_ready and move to the NORMAL state after 6 blocks
generateBlocks(6, Some(minerAddress))
awaitCond(stateListenerC.expectMsgType[ChannelStateChanged](max = 60 seconds).currentState == NORMAL, max = 30 seconds)
awaitCond(stateListenerF.expectMsgType[ChannelStateChanged](max = 60 seconds).currentState == NORMAL, max = 30 seconds)
awaitAnnouncements(2)
// first we make sure we are in sync with current blockchain height
val currentBlockHeight = getBlockHeight()
Expand Down