mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-09-23 17:59:41 +02:00
chainntnfs: cache spend hints within the different chain notifiers
In this commit, we extend the different ChainNotifier implementations to cache height hints for our spend events. Each outpoint we've requested a spend notification for will have its initial height hint cached. We then increment this height hint at every new block for unspent outpoints. This allows us to retrieve the *exact* height at which the outpoint has been spent. By doing this, we optimize the different ChainNotifier implementations since they will no longer have to rescan forward (and possibly fetch blocks in the neutrino/pruned node case) from the initial height hint.
This commit is contained in:
@@ -603,22 +603,23 @@ func (n *NeutrinoNotifier) handleBlockConnected(newBlock *filteredBlock) error {
|
||||
// First process the block for our internal state. A new block has
|
||||
// been connected to the main chain. Send out any N confirmation
|
||||
// notifications which may have been triggered by this new block.
|
||||
err := n.txConfNotifier.ConnectTip(&newBlock.hash, newBlock.height,
|
||||
newBlock.txns)
|
||||
err := n.txConfNotifier.ConnectTip(
|
||||
&newBlock.hash, newBlock.height, newBlock.txns,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to connect tip: %v", err)
|
||||
}
|
||||
|
||||
chainntnfs.Log.Infof("New block: height=%v, sha=%v",
|
||||
newBlock.height, newBlock.hash)
|
||||
chainntnfs.Log.Infof("New block: height=%v, sha=%v", newBlock.height,
|
||||
newBlock.hash)
|
||||
|
||||
n.bestHeight = newBlock.height
|
||||
|
||||
// Next, notify any subscribed clients of the block.
|
||||
n.notifyBlockEpochs(int32(newBlock.height), &newBlock.hash)
|
||||
|
||||
// Finally, we'll scan over the list of relevant transactions and
|
||||
// possibly dispatch notifications for confirmations and spends.
|
||||
// Scan over the list of relevant transactions and possibly dispatch
|
||||
// notifications for spends.
|
||||
for _, tx := range newBlock.txns {
|
||||
mtx := tx.MsgTx()
|
||||
txSha := mtx.TxHash()
|
||||
@@ -661,6 +662,24 @@ func (n *NeutrinoNotifier) handleBlockConnected(newBlock *filteredBlock) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, we'll update the spend height hint for all of our watched
|
||||
// outpoints that have not been spent yet. This is safe to do as we do
|
||||
// not watch already spent outpoints for spend notifications.
|
||||
ops := make([]wire.OutPoint, 0, len(n.spendNotifications))
|
||||
for op := range n.spendNotifications {
|
||||
ops = append(ops, op)
|
||||
}
|
||||
|
||||
if len(ops) > 0 {
|
||||
err := n.spendHintCache.CommitSpendHint(newBlock.height, ops...)
|
||||
if err != nil {
|
||||
// The error is not fatal, so we should not return an
|
||||
// error to the caller.
|
||||
chainntnfs.Log.Errorf("Unable to update spend hint to "+
|
||||
"%d for %v: %v", newBlock.height, ops, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -740,15 +759,26 @@ func (n *NeutrinoNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
|
||||
currentHeight := n.bestHeight
|
||||
n.heightMtx.RUnlock()
|
||||
|
||||
chainntnfs.Log.Infof("New spend notification for outpoint=%v, "+
|
||||
"height_hint=%v", outpoint, heightHint)
|
||||
// Before proceeding to register the notification, we'll query our
|
||||
// height hint cache to determine whether a better one exists.
|
||||
if hint, err := n.spendHintCache.QuerySpendHint(*outpoint); err == nil {
|
||||
if hint > heightHint {
|
||||
chainntnfs.Log.Debugf("Using height hint %d retrieved "+
|
||||
"from cache for %v", hint, outpoint)
|
||||
heightHint = hint
|
||||
}
|
||||
}
|
||||
|
||||
// Construct a notification request for the outpoint. We'll defer
|
||||
// sending it to the main event loop until after we've guaranteed that
|
||||
// the outpoint has not been spent.
|
||||
ntfn := &spendNotification{
|
||||
targetOutpoint: outpoint,
|
||||
spendChan: make(chan *chainntnfs.SpendDetail, 1),
|
||||
spendID: atomic.AddUint64(&n.spendClientCounter, 1),
|
||||
heightHint: heightHint,
|
||||
}
|
||||
|
||||
spendEvent := &chainntnfs.SpendEvent{
|
||||
Spend: ntfn.spendChan,
|
||||
Cancel: func() {
|
||||
@@ -760,8 +790,9 @@ func (n *NeutrinoNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
|
||||
// Submit spend cancellation to notification dispatcher.
|
||||
select {
|
||||
case n.notificationCancels <- cancel:
|
||||
// Cancellation is being handled, drain the spend chan until it is
|
||||
// closed before yielding to the caller.
|
||||
// Cancellation is being handled, drain the
|
||||
// spend chan until it is closed before yielding
|
||||
// to the caller.
|
||||
for {
|
||||
select {
|
||||
case _, ok := <-ntfn.spendChan:
|
||||
@@ -851,6 +882,16 @@ func (n *NeutrinoNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
|
||||
return nil, ErrChainNotifierShuttingDown
|
||||
}
|
||||
|
||||
// Finally, we'll add a spent hint with the current height to the cache
|
||||
// in order to better keep track of when this outpoint is spent.
|
||||
err = n.spendHintCache.CommitSpendHint(currentHeight, *outpoint)
|
||||
if err != nil {
|
||||
// The error is not fatal, so we should not return an error to
|
||||
// the caller.
|
||||
chainntnfs.Log.Errorf("Unable to update spend hint to %d for "+
|
||||
"%v: %v", currentHeight, outpoint, err)
|
||||
}
|
||||
|
||||
return spendEvent, nil
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user