Skip to content

Commit ab3b3c8

Browse files
authored
Merge pull request #9258 from yyforyongyu/fix-notification
chainntnfs: fix missing notifications
2 parents c3fac0e + db6901c commit ab3b3c8

File tree

6 files changed

+105
-33
lines changed

6 files changed

+105
-33
lines changed

chainntnfs/bitcoindnotify/bitcoind.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -665,8 +665,14 @@ func (b *BitcoindNotifier) handleBlockConnected(block chainntnfs.BlockEpoch) err
665665
// satisfy any client requests based upon the new block.
666666
b.bestBlock = block
667667

668+
err = b.txNotifier.NotifyHeight(uint32(block.Height))
669+
if err != nil {
670+
return fmt.Errorf("unable to notify height: %w", err)
671+
}
672+
668673
b.notifyBlockEpochs(block.Height, block.Hash, block.BlockHeader)
669-
return b.txNotifier.NotifyHeight(uint32(block.Height))
674+
675+
return nil
670676
}
671677

672678
// notifyBlockEpochs notifies all registered block epoch clients of the newly

chainntnfs/btcdnotify/btcd.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -725,11 +725,16 @@ func (b *BtcdNotifier) handleBlockConnected(epoch chainntnfs.BlockEpoch) error {
725725
// satisfy any client requests based upon the new block.
726726
b.bestBlock = epoch
727727

728+
err = b.txNotifier.NotifyHeight(uint32(epoch.Height))
729+
if err != nil {
730+
return fmt.Errorf("unable to notify height: %w", err)
731+
}
732+
728733
b.notifyBlockEpochs(
729734
epoch.Height, epoch.Hash, epoch.BlockHeader,
730735
)
731736

732-
return b.txNotifier.NotifyHeight(uint32(epoch.Height))
737+
return nil
733738
}
734739

735740
// notifyBlockEpochs notifies all registered block epoch clients of the newly

chainntnfs/interface.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,9 @@ type ConfirmationEvent struct {
258258
// channels.
259259
func NewConfirmationEvent(numConfs uint32, cancel func()) *ConfirmationEvent {
260260
return &ConfirmationEvent{
261+
// We cannot rely on the subscriber to immediately read from
262+
// the channel so we need to create a larger buffer to avoid
263+
// blocking the notifier.
261264
Confirmed: make(chan *TxConfirmation, 1),
262265
Updates: make(chan uint32, numConfs),
263266
NegativeConf: make(chan int32, 1),

chainntnfs/neutrinonotify/neutrino.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -689,10 +689,16 @@ func (n *NeutrinoNotifier) handleBlockConnected(newBlock *filteredBlock) error {
689689
n.bestBlock.Height = int32(newBlock.height)
690690
n.bestBlock.BlockHeader = newBlock.header
691691

692+
err = n.txNotifier.NotifyHeight(newBlock.height)
693+
if err != nil {
694+
return fmt.Errorf("unable to notify height: %w", err)
695+
}
696+
692697
n.notifyBlockEpochs(
693698
int32(newBlock.height), &newBlock.hash, newBlock.header,
694699
)
695-
return n.txNotifier.NotifyHeight(newBlock.height)
700+
701+
return nil
696702
}
697703

698704
// getFilteredBlock is a utility to retrieve the full filtered block from a block epoch.

chainntnfs/txnotifier.go

Lines changed: 75 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -244,20 +244,25 @@ type ConfNtfn struct {
244244
// notification is to be sent.
245245
NumConfirmations uint32
246246

247-
// Event contains references to the channels that the notifications are to
248-
// be sent over.
247+
// Event contains references to the channels that the notifications are
248+
// to be sent over.
249249
Event *ConfirmationEvent
250250

251251
// HeightHint is the minimum height in the chain that we expect to find
252252
// this txid.
253253
HeightHint uint32
254254

255-
// dispatched is false if the confirmed notification has not been sent yet.
255+
// dispatched is false if the confirmed notification has not been sent
256+
// yet.
256257
dispatched bool
257258

258259
// includeBlock is true if the dispatched notification should also have
259260
// the block included with it.
260261
includeBlock bool
262+
263+
// numConfsLeft is the number of confirmations left to be sent to the
264+
// subscriber.
265+
numConfsLeft uint32
261266
}
262267

263268
// HistoricalConfDispatch parametrizes a manual rescan for a particular
@@ -589,6 +594,7 @@ func (n *TxNotifier) newConfNtfn(txid *chainhash.Hash,
589594
}),
590595
HeightHint: heightHint,
591596
includeBlock: opts.includeBlock,
597+
numConfsLeft: numConfs,
592598
}, nil
593599
}
594600

@@ -664,8 +670,8 @@ func (n *TxNotifier) RegisterConf(txid *chainhash.Hash, pkScript []byte,
664670
// already been found, we'll attempt to deliver them immediately
665671
// to this client.
666672
Log.Debugf("Attempting to dispatch confirmation for %v on "+
667-
"registration since rescan has finished",
668-
ntfn.ConfRequest)
673+
"registration since rescan has finished, conf_id=%v",
674+
ntfn.ConfRequest, ntfn.ConfID)
669675

670676
// The default notification we assigned above includes the
671677
// block along with the rest of the details. However not all
@@ -679,9 +685,13 @@ func (n *TxNotifier) RegisterConf(txid *chainhash.Hash, pkScript []byte,
679685
confDetails = &confDetailsCopy
680686
}
681687

682-
err := n.dispatchConfDetails(ntfn, confDetails)
683-
if err != nil {
684-
return nil, err
688+
// Deliver the details to the whole conf set where this ntfn
689+
// lives in.
690+
for _, subscriber := range confSet.ntfns {
691+
err := n.dispatchConfDetails(subscriber, confDetails)
692+
if err != nil {
693+
return nil, err
694+
}
685695
}
686696

687697
return &ConfRegistration{
@@ -912,10 +922,16 @@ func (n *TxNotifier) dispatchConfDetails(
912922
// If there are no conf details to dispatch or if the notification has
913923
// already been dispatched, then we can skip dispatching to this
914924
// client.
915-
if details == nil || ntfn.dispatched {
916-
Log.Debugf("Skipping dispatch of conf details(%v) for "+
917-
"request %v, dispatched=%v", details, ntfn.ConfRequest,
918-
ntfn.dispatched)
925+
if details == nil {
926+
Log.Debugf("Skipped dispatching nil conf details for request "+
927+
"%v, conf_id=%v", ntfn.ConfRequest, ntfn.ConfID)
928+
929+
return nil
930+
}
931+
932+
if ntfn.dispatched {
933+
Log.Debugf("Skipped dispatched conf details for request %v "+
934+
"conf_id=%v", ntfn.ConfRequest, ntfn.ConfID)
919935

920936
return nil
921937
}
@@ -925,16 +941,16 @@ func (n *TxNotifier) dispatchConfDetails(
925941
// we'll dispatch a confirmation notification to the caller.
926942
confHeight := details.BlockHeight + ntfn.NumConfirmations - 1
927943
if confHeight <= n.currentHeight {
928-
Log.Debugf("Dispatching %v confirmation notification for %v",
929-
ntfn.NumConfirmations, ntfn.ConfRequest)
944+
Log.Debugf("Dispatching %v confirmation notification for "+
945+
"conf_id=%v, %v", ntfn.NumConfirmations, ntfn.ConfID,
946+
ntfn.ConfRequest)
930947

931948
// We'll send a 0 value to the Updates channel,
932949
// indicating that the transaction/output script has already
933950
// been confirmed.
934-
select {
935-
case ntfn.Event.Updates <- 0:
936-
case <-n.quit:
937-
return ErrTxNotifierExiting
951+
err := n.notifyNumConfsLeft(ntfn, 0)
952+
if err != nil {
953+
return err
938954
}
939955

940956
select {
@@ -944,8 +960,8 @@ func (n *TxNotifier) dispatchConfDetails(
944960
return ErrTxNotifierExiting
945961
}
946962
} else {
947-
Log.Debugf("Queueing %v confirmation notification for %v at tip ",
948-
ntfn.NumConfirmations, ntfn.ConfRequest)
963+
Log.Debugf("Queueing %v confirmation notification for %v at "+
964+
"tip", ntfn.NumConfirmations, ntfn.ConfRequest)
949965

950966
// Otherwise, we'll keep track of the notification
951967
// request by the height at which we should dispatch the
@@ -961,10 +977,9 @@ func (n *TxNotifier) dispatchConfDetails(
961977
// confirmations are left for the transaction/output script to
962978
// be confirmed.
963979
numConfsLeft := confHeight - n.currentHeight
964-
select {
965-
case ntfn.Event.Updates <- numConfsLeft:
966-
case <-n.quit:
967-
return ErrTxNotifierExiting
980+
err := n.notifyNumConfsLeft(ntfn, numConfsLeft)
981+
if err != nil {
982+
return err
968983
}
969984
}
970985

@@ -1729,10 +1744,9 @@ func (n *TxNotifier) NotifyHeight(height uint32) error {
17291744
continue
17301745
}
17311746

1732-
select {
1733-
case ntfn.Event.Updates <- numConfsLeft:
1734-
case <-n.quit:
1735-
return ErrTxNotifierExiting
1747+
err := n.notifyNumConfsLeft(ntfn, numConfsLeft)
1748+
if err != nil {
1749+
return err
17361750
}
17371751
}
17381752
}
@@ -1743,8 +1757,9 @@ func (n *TxNotifier) NotifyHeight(height uint32) error {
17431757
for ntfn := range n.ntfnsByConfirmHeight[height] {
17441758
confSet := n.confNotifications[ntfn.ConfRequest]
17451759

1746-
Log.Debugf("Dispatching %v confirmation notification for %v",
1747-
ntfn.NumConfirmations, ntfn.ConfRequest)
1760+
Log.Debugf("Dispatching %v confirmation notification for "+
1761+
"conf_id=%v, %v", ntfn.NumConfirmations, ntfn.ConfID,
1762+
ntfn.ConfRequest)
17481763

17491764
// The default notification we assigned above includes the
17501765
// block along with the rest of the details. However not all
@@ -1833,6 +1848,9 @@ func (n *TxNotifier) DisconnectTip(blockHeight uint32) error {
18331848
default:
18341849
}
18351850

1851+
// We also reset the num of confs update.
1852+
ntfn.numConfsLeft = ntfn.NumConfirmations
1853+
18361854
// Then, we'll check if the current
18371855
// transaction/output script was included in the
18381856
// block currently being disconnected. If it
@@ -2069,3 +2087,30 @@ func (n *TxNotifier) TearDown() {
20692087
}
20702088
}
20712089
}
2090+
2091+
// notifyNumConfsLeft sends the number of confirmations left to the
2092+
// notification subscriber through the Event.Updates channel.
2093+
//
2094+
// NOTE: must be used with the TxNotifier's lock held.
2095+
func (n *TxNotifier) notifyNumConfsLeft(ntfn *ConfNtfn, num uint32) error {
2096+
// If the number left is no less than the recorded value, we can skip
2097+
// sending it as it means this same value has already been sent before.
2098+
if num >= ntfn.numConfsLeft {
2099+
Log.Debugf("Skipped dispatched update (numConfsLeft=%v) for "+
2100+
"request %v conf_id=%v", num, ntfn.ConfRequest,
2101+
ntfn.ConfID)
2102+
2103+
return nil
2104+
}
2105+
2106+
// Update the number of confirmations left to the notification.
2107+
ntfn.numConfsLeft = num
2108+
2109+
select {
2110+
case ntfn.Event.Updates <- num:
2111+
case <-n.quit:
2112+
return ErrTxNotifierExiting
2113+
}
2114+
2115+
return nil
2116+
}

docs/release-notes/release-notes-0.19.0.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@
5454
* [Fixed a bug](https://github.com/lightningnetwork/lnd/pull/9275) where the
5555
peer may block the shutdown process of lnd.
5656

57+
* [Fixed a case](https://github.com/lightningnetwork/lnd/pull/9258) where the
58+
confirmation notification may be missed.
59+
5760
# New Features
5861
## Functional Enhancements
5962
## RPC Additions
@@ -199,6 +202,10 @@ The underlying functionality between those two options remain the same.
199202
* Oliver Gugger
200203
* Pins
201204
* Viktor Tigerström
205+
<<<<<<< HEAD
202206
* Yong Yu
203207
* Ziggie
204208

209+
=======
210+
* Ziggie
211+
>>>>>>> 5a6264b6a (docs: update release notes)

0 commit comments

Comments
 (0)