chainntnfs: add block cache to NeutrinoNotifier

This commit adds gives BtcdNotifier access to the block cache and wraps
its GetBlock method so that the block cache's mutex map for the specific
hash is used.
This commit is contained in:
Elle Mouton 2021-03-30 10:13:58 +02:00
parent 6ad5781bf1
commit f8de10511e
4 changed files with 38 additions and 7 deletions

View File

@ -5,15 +5,16 @@ import (
"fmt"
"github.com/lightninglabs/neutrino"
"github.com/lightningnetwork/lnd/blockcache"
"github.com/lightningnetwork/lnd/chainntnfs"
)
// createNewNotifier creates a new instance of the ChainNotifier interface
// implemented by NeutrinoNotifier.
func createNewNotifier(args ...interface{}) (chainntnfs.ChainNotifier, error) {
if len(args) != 3 {
if len(args) != 4 {
return nil, fmt.Errorf("incorrect number of arguments to "+
".New(...), expected 3, instead passed %v", len(args))
".New(...), expected 4, instead passed %v", len(args))
}
config, ok := args[0].(*neutrino.ChainService)
@ -34,7 +35,13 @@ func createNewNotifier(args ...interface{}) (chainntnfs.ChainNotifier, error) {
"is incorrect, expected a chainntfs.ConfirmHintCache")
}
return New(config, spendHintCache, confirmHintCache), nil
blockCache, ok := args[3].(*blockcache.BlockCache)
if !ok {
return nil, errors.New("fourth argument to neutrinonotify.New " +
"is incorrect, expected a *blockcache.BlockCache")
}
return New(config, spendHintCache, confirmHintCache, blockCache), nil
}
// init registers a driver for the NeutrinoNotify concrete implementation of

View File

@ -17,7 +17,9 @@ import (
"github.com/btcsuite/btcutil/gcs/builder"
"github.com/lightninglabs/neutrino"
"github.com/lightninglabs/neutrino/headerfs"
"github.com/lightningnetwork/lnd/blockcache"
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/queue"
)
@ -73,6 +75,9 @@ type NeutrinoNotifier struct {
// which the transaction could have confirmed within the chain.
confirmHintCache chainntnfs.ConfirmHintCache
// blockCache is an LRU block cache.
blockCache *blockcache.BlockCache
wg sync.WaitGroup
quit chan struct{}
}
@ -86,7 +91,8 @@ var _ chainntnfs.ChainNotifier = (*NeutrinoNotifier)(nil)
// NOTE: The passed neutrino node should already be running and active before
// being passed into this function.
func New(node *neutrino.ChainService, spendHintCache chainntnfs.SpendHintCache,
confirmHintCache chainntnfs.ConfirmHintCache) *NeutrinoNotifier {
confirmHintCache chainntnfs.ConfirmHintCache,
blockCache *blockcache.BlockCache) *NeutrinoNotifier {
return &NeutrinoNotifier{
notificationCancels: make(chan interface{}),
@ -105,6 +111,8 @@ func New(node *neutrino.ChainService, spendHintCache chainntnfs.SpendHintCache,
spendHintCache: spendHintCache,
confirmHintCache: confirmHintCache,
blockCache: blockCache,
quit: make(chan struct{}),
}
}
@ -571,7 +579,7 @@ func (n *NeutrinoNotifier) historicalConfDetails(confRequest chainntnfs.ConfRequ
// In the case that we do have a match, we'll fetch the block
// from the network so we can find the positional data required
// to send the proper response.
block, err := n.p2pNode.GetBlock(*blockHash)
block, err := n.GetBlock(*blockHash)
if err != nil {
return nil, fmt.Errorf("unable to get block from network: %v", err)
}
@ -628,7 +636,7 @@ func (n *NeutrinoNotifier) handleBlockConnected(newBlock *filteredBlock) error {
// getFilteredBlock is a utility to retrieve the full filtered block from a block epoch.
func (n *NeutrinoNotifier) getFilteredBlock(epoch chainntnfs.BlockEpoch) (*filteredBlock, error) {
rawBlock, err := n.p2pNode.GetBlock(*epoch.Hash)
rawBlock, err := n.GetBlock(*epoch.Hash)
if err != nil {
return nil, fmt.Errorf("unable to get block: %v", err)
}
@ -908,6 +916,21 @@ func (n *NeutrinoNotifier) RegisterConfirmationsNtfn(txid *chainhash.Hash,
return ntfn.Event, nil
}
// GetBlock is used to retrieve the block with the given hash. Since the block
// cache used by neutrino will be the same as that used by LND (since it is
// passed to neutrino on initialisation), the neutrino GetBlock method can be
// called directly since it already uses the block cache. However, neutrino
// does not lock the block cache mutex for the given block hash and so that is
// done here.
func (n *NeutrinoNotifier) GetBlock(hash chainhash.Hash) (
*btcutil.Block, error) {
n.blockCache.HashMutex.Lock(lntypes.Hash(hash))
defer n.blockCache.HashMutex.Unlock(lntypes.Hash(hash))
return n.p2pNode.GetBlock(hash)
}
// blockEpochRegistration represents a client's intent to receive a
// notification with each newly connected block.
type blockEpochRegistration struct {

View File

@ -1967,6 +1967,7 @@ func TestInterfaces(t *testing.T, targetBackEnd string) {
newNotifier = func() (chainntnfs.TestChainNotifier, error) {
return neutrinonotify.New(
spvNode, hintCache, hintCache,
blockCache,
), nil
}
}

View File

@ -317,7 +317,7 @@ func NewChainControl(cfg *Config, blockCache *blockcache.BlockCache) (
// along with the wallet's ChainSource, which are all backed by
// the neutrino light client.
cc.ChainNotifier = neutrinonotify.New(
cfg.NeutrinoCS, hintCache, hintCache,
cfg.NeutrinoCS, hintCache, hintCache, blockCache,
)
cc.ChainView, err = chainview.NewCfFilteredChainView(
cfg.NeutrinoCS, blockCache,