Skip to content

Commit ec13a04

Browse files
funding: persist ShortChannelID upon first funding confirmation
This change ensures that a channel's ShortChannelID is recorded in the database once its funding transaction receives its initial confirmation. By doing so, we establish a reliable reference point to monitor the channel's progress toward the required confirmation depth. Signed-off-by: Nishant Bansal <[email protected]>
1 parent 6f64189 commit ec13a04

File tree

2 files changed

+234
-17
lines changed

2 files changed

+234
-17
lines changed

funding/manager.go

+122-15
Original file line numberDiff line numberDiff line change
@@ -3012,6 +3012,16 @@ func (f *Manager) waitForFundingWithTimeout(
30123012
confChan := make(chan *confirmedChannel)
30133013
timeoutChan := make(chan error, 1)
30143014
cancelChan := make(chan struct{})
3015+
errorChan := make(chan error, 1)
3016+
3017+
// If the channel is not a zero-conf channel, we add the SCID to the
3018+
// database once the channel opening transaction receives one
3019+
// confirmation. This enables us to calculate the number of
3020+
// confirmations before the pending channel becomes active.
3021+
if !ch.IsZeroConf() {
3022+
f.wg.Add(1)
3023+
go f.handleOpenChanTxConfirmation(ch, cancelChan, errorChan)
3024+
}
30153025

30163026
f.wg.Add(1)
30173027
go f.waitForFundingConfirmation(ch, cancelChan, confChan)
@@ -3025,24 +3035,40 @@ func (f *Manager) waitForFundingWithTimeout(
30253035
}
30263036
defer close(cancelChan)
30273037

3028-
select {
3029-
case err := <-timeoutChan:
3030-
if err != nil {
3031-
return nil, err
3032-
}
3033-
return nil, ErrConfirmationTimeout
3038+
for {
3039+
select {
3040+
case err := <-errorChan:
3041+
if err != nil {
3042+
return nil, fmt.Errorf("waiting for funding"+
3043+
"confirmation failed: %v", err)
3044+
}
30343045

3035-
case <-f.quit:
3036-
// The fundingManager is shutting down, and will resume wait on
3037-
// startup.
3038-
return nil, ErrFundingManagerShuttingDown
3046+
// If the channel opening transaction receives one
3047+
// confirmation successfully, set errorChan to nil to
3048+
// disable this case in the select statement for
3049+
// subsequent channel messages.
3050+
errorChan = nil
30393051

3040-
case confirmedChannel, ok := <-confChan:
3041-
if !ok {
3042-
return nil, fmt.Errorf("waiting for funding" +
3043-
"confirmation failed")
3052+
case err := <-timeoutChan:
3053+
if err != nil {
3054+
return nil, err
3055+
}
3056+
3057+
return nil, ErrConfirmationTimeout
3058+
3059+
case <-f.quit:
3060+
// The fundingManager is shutting down, and will resume
3061+
// wait on startup.
3062+
return nil, ErrFundingManagerShuttingDown
3063+
3064+
case confirmedChannel, ok := <-confChan:
3065+
if !ok {
3066+
return nil, fmt.Errorf("waiting for funding" +
3067+
"confirmation failed")
3068+
}
3069+
3070+
return confirmedChannel, nil
30443071
}
3045-
return confirmedChannel, nil
30463072
}
30473073
}
30483074

@@ -3075,6 +3101,87 @@ func makeFundingScript(channel *channeldb.OpenChannel) ([]byte, error) {
30753101
return input.WitnessScriptHash(multiSigScript)
30763102
}
30773103

3104+
// handleOpenChanTxConfirmation manages the confirmation process of a channel's
3105+
// funding transaction. It registers for confirmation notifications, waits for
3106+
// the funding transaction to be confirmed, updates the channel state, and
3107+
// handles shutdown signals or cancellations.
3108+
//
3109+
// NOTE: This MUST be run as a goroutine.
3110+
func (f *Manager) handleOpenChanTxConfirmation(openChannel *channeldb.
3111+
OpenChannel, cancelChan <-chan struct{}, errorChan chan<- error) {
3112+
3113+
defer f.wg.Done()
3114+
defer close(errorChan)
3115+
3116+
// Generate the funding output script needed to detect the transaction
3117+
// confirmation
3118+
chanFundingScript, err := makeFundingScript(openChannel)
3119+
if err != nil {
3120+
errorChan <- fmt.Errorf("unable to create funding script for "+
3121+
"ChannelPoint(%v): %v", openChannel.FundingOutpoint,
3122+
err)
3123+
3124+
return
3125+
}
3126+
3127+
// Register for transaction confirmation notifications
3128+
chanConfNtfn, err := f.cfg.Notifier.RegisterConfirmationsNtfn(
3129+
&openChannel.FundingOutpoint.Hash, chanFundingScript, 1,
3130+
openChannel.BroadcastHeight(),
3131+
)
3132+
if err != nil {
3133+
errorChan <- fmt.Errorf("unable to register for confirmation "+
3134+
"of ChannelPoint(%v): %v", openChannel.FundingOutpoint,
3135+
err)
3136+
3137+
return
3138+
}
3139+
3140+
var confDetails *chainntnfs.TxConfirmation
3141+
var ok bool
3142+
3143+
// Wait for either the funding confirmation, cancellation, or manager
3144+
// shutdown
3145+
select {
3146+
case confDetails, ok = <-chanConfNtfn.Confirmed:
3147+
// fallthrough
3148+
3149+
case <-cancelChan:
3150+
// canceled waiting for funding confirmation
3151+
return
3152+
3153+
case <-f.quit:
3154+
// fundingManager is shutting down
3155+
return
3156+
}
3157+
3158+
if !ok {
3159+
errorChan <- fmt.Errorf("ChainNotifier shutting down, can't "+
3160+
"complete funding flow for ChannelPoint(%v)",
3161+
openChannel.FundingOutpoint)
3162+
3163+
return
3164+
}
3165+
3166+
fundingPoint := openChannel.FundingOutpoint
3167+
log.Infof("ChannelPoint(%v) confirmed at block %d",
3168+
fundingPoint, confDetails.BlockHeight)
3169+
3170+
// Construct short channel ID from confirmation details
3171+
shortChanID := lnwire.ShortChannelID{
3172+
BlockHeight: confDetails.BlockHeight,
3173+
TxIndex: confDetails.TxIndex,
3174+
TxPosition: uint16(fundingPoint.Index),
3175+
}
3176+
3177+
// Update the channel's state in the database to mark its confirmed SCID
3178+
err = openChannel.MarkConfirmedScid(shortChanID)
3179+
if err != nil {
3180+
errorChan <- fmt.Errorf("failed to update confirmed state for "+
3181+
"ChannelPoint(%v): %v", fundingPoint, err)
3182+
}
3183+
}
3184+
30783185
// waitForFundingConfirmation handles the final stages of the channel funding
30793186
// process once the funding transaction has been broadcast. The primary
30803187
// function of waitForFundingConfirmation is to wait for blockchain

funding/manager_test.go

+112-2
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ func createTestFundingManager(t *testing.T, privKey *btcec.PrivateKey,
407407

408408
chainNotifier := &mockNotifier{
409409
oneConfChannel: make(chan *chainntnfs.TxConfirmation, 1),
410-
sixConfChannel: make(chan *chainntnfs.TxConfirmation, 1),
410+
sixConfChannel: make(chan *chainntnfs.TxConfirmation, 6),
411411
epochChan: make(chan *chainntnfs.BlockEpoch, 2),
412412
}
413413

@@ -1496,6 +1496,16 @@ func testNormalWorkflow(t *testing.T, chanType *lnwire.ChannelType) {
14961496
assertErrorNotSent(t, alice.msgChan)
14971497
assertErrorNotSent(t, bob.msgChan)
14981498

1499+
// We send two notifications:
1500+
// 1. The first adds the SCID to the database, allowing calculation of
1501+
// the number of confirmations before the channel is fully opened.
1502+
// 2. The second marks the channel as open.
1503+
alice.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
1504+
Tx: fundingTx,
1505+
}
1506+
bob.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
1507+
Tx: fundingTx,
1508+
}
14991509
// Notify that transaction was mined.
15001510
alice.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
15011511
Tx: fundingTx,
@@ -1809,6 +1819,16 @@ func TestFundingManagerRestartBehavior(t *testing.T) {
18091819
}
18101820
alice.fundingMgr.cfg.NotifyWhenOnline = notifyWhenOnline
18111821

1822+
// We send two notifications:
1823+
// 1. The first adds the SCID to the database, allowing calculation of
1824+
// the number of confirmations before the channel is fully opened.
1825+
// 2. The second marks the channel as open.
1826+
alice.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
1827+
Tx: fundingTx,
1828+
}
1829+
bob.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
1830+
Tx: fundingTx,
1831+
}
18121832
// Notify that transaction was mined
18131833
alice.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
18141834
Tx: fundingTx,
@@ -1969,6 +1989,16 @@ func TestFundingManagerOfflinePeer(t *testing.T) {
19691989
conChan <- connected
19701990
}
19711991

1992+
// We send two notifications:
1993+
// 1. The first adds the SCID to the database, allowing calculation of
1994+
// the number of confirmations before the channel is fully opened.
1995+
// 2. The second marks the channel as open.
1996+
alice.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
1997+
Tx: fundingTx,
1998+
}
1999+
bob.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
2000+
Tx: fundingTx,
2001+
}
19722002
// Notify that transaction was mined
19732003
alice.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
19742004
Tx: fundingTx,
@@ -2465,6 +2495,16 @@ func TestFundingManagerReceiveChannelReadyTwice(t *testing.T) {
24652495
t, alice, bob, localAmt, pushAmt, 1, updateChan, true, nil,
24662496
)
24672497

2498+
// We send two notifications:
2499+
// 1. The first adds the SCID to the database, allowing calculation of
2500+
// the number of confirmations before the channel is fully opened.
2501+
// 2. The second marks the channel as open.
2502+
alice.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
2503+
Tx: fundingTx,
2504+
}
2505+
bob.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
2506+
Tx: fundingTx,
2507+
}
24682508
// Notify that transaction was mined
24692509
alice.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
24702510
Tx: fundingTx,
@@ -2578,6 +2618,16 @@ func TestFundingManagerRestartAfterChanAnn(t *testing.T) {
25782618
t, alice, bob, localAmt, pushAmt, 1, updateChan, true, nil,
25792619
)
25802620

2621+
// We send two notifications:
2622+
// 1. The first adds the SCID to the database, allowing calculation of
2623+
// the number of confirmations before the channel is fully opened.
2624+
// 2. The second marks the channel as open.
2625+
alice.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
2626+
Tx: fundingTx,
2627+
}
2628+
bob.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
2629+
Tx: fundingTx,
2630+
}
25812631
// Notify that transaction was mined
25822632
alice.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
25832633
Tx: fundingTx,
@@ -2677,6 +2727,16 @@ func TestFundingManagerRestartAfterReceivingChannelReady(t *testing.T) {
26772727
t, alice, bob, localAmt, pushAmt, 1, updateChan, true, nil,
26782728
)
26792729

2730+
// We send two notifications:
2731+
// 1. The first adds the SCID to the database, allowing calculation of
2732+
// the number of confirmations before the channel is fully opened.
2733+
// 2. The second marks the channel as open.
2734+
alice.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
2735+
Tx: fundingTx,
2736+
}
2737+
bob.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
2738+
Tx: fundingTx,
2739+
}
26802740
// Notify that transaction was mined
26812741
alice.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
26822742
Tx: fundingTx,
@@ -2772,6 +2832,16 @@ func TestFundingManagerPrivateChannel(t *testing.T) {
27722832
t, alice, bob, localAmt, pushAmt, 1, updateChan, false, nil,
27732833
)
27742834

2835+
// We send two notifications:
2836+
// 1. The first adds the SCID to the database, allowing calculation of
2837+
// the number of confirmations before the channel is fully opened.
2838+
// 2. The second marks the channel as open.
2839+
alice.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
2840+
Tx: fundingTx,
2841+
}
2842+
bob.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
2843+
Tx: fundingTx,
2844+
}
27752845
// Notify that transaction was mined
27762846
alice.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
27772847
Tx: fundingTx,
@@ -2897,6 +2967,16 @@ func TestFundingManagerPrivateRestart(t *testing.T) {
28972967
t, alice, bob, localAmt, pushAmt, 1, updateChan, false, nil,
28982968
)
28992969

2970+
// We send two notifications:
2971+
// 1. The first adds the SCID to the database, allowing calculation of
2972+
// the number of confirmations before the channel is fully opened.
2973+
// 2. The second marks the channel as open.
2974+
alice.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
2975+
Tx: fundingTx,
2976+
}
2977+
bob.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
2978+
Tx: fundingTx,
2979+
}
29002980
// Notify that transaction was mined
29012981
alice.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
29022982
Tx: fundingTx,
@@ -3339,6 +3419,16 @@ func TestFundingManagerCustomChannelParameters(t *testing.T) {
33393419
t.Fatalf("alice did not publish funding tx")
33403420
}
33413421

3422+
// We send two notifications:
3423+
// 1. The first adds the SCID to the database, allowing calculation of
3424+
// the number of confirmations before the channel is fully opened.
3425+
// 2. The second marks the channel as open.
3426+
alice.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
3427+
Tx: fundingTx,
3428+
}
3429+
bob.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
3430+
Tx: fundingTx,
3431+
}
33423432
// Notify that transaction was mined.
33433433
alice.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
33443434
Tx: fundingTx,
@@ -3675,6 +3765,17 @@ func TestFundingManagerMaxPendingChannels(t *testing.T) {
36753765

36763766
// Notify that the transactions were mined.
36773767
for i := 0; i < maxPending; i++ {
3768+
// We send two notifications:
3769+
// 1. The first adds the SCID to the database, allowing
3770+
// calculation of the number of confirmations before the
3771+
// channel is fully opened.
3772+
// 2. The second marks the channel as open.
3773+
alice.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
3774+
Tx: txs[i],
3775+
}
3776+
bob.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
3777+
Tx: txs[i],
3778+
}
36783779
alice.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
36793780
Tx: txs[i],
36803781
}
@@ -4954,10 +5055,19 @@ func TestFundingManagerCoinbase(t *testing.T) {
49545055
// Send along the oneConfChannel again and then assert that the open
49555056
// event is sent. This serves as the 100 block + MinAcceptDepth
49565057
// confirmation.
5058+
// We send two notifications:
5059+
// 1. The first adds the SCID to the database, allowing calculation of
5060+
// the number of confirmations before the channel is fully opened.
5061+
// 2. The second marks the channel as open.
5062+
alice.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
5063+
Tx: fundingTx,
5064+
}
5065+
bob.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
5066+
Tx: fundingTx,
5067+
}
49575068
alice.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
49585069
Tx: fundingTx,
49595070
}
4960-
49615071
bob.mockNotifier.oneConfChannel <- &chainntnfs.TxConfirmation{
49625072
Tx: fundingTx,
49635073
}

0 commit comments

Comments
 (0)