From f8de10511e6edbc298a72e1e2399a8afe16ed7c6 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 30 Mar 2021 10:13:58 +0200 Subject: [PATCH] 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. --- chainntnfs/neutrinonotify/driver.go | 13 +++++++++--- chainntnfs/neutrinonotify/neutrino.go | 29 ++++++++++++++++++++++++--- chainntnfs/test/test_interface.go | 1 + chainreg/chainregistry.go | 2 +- 4 files changed, 38 insertions(+), 7 deletions(-) diff --git a/chainntnfs/neutrinonotify/driver.go b/chainntnfs/neutrinonotify/driver.go index 68a1b2f25..dbd897180 100644 --- a/chainntnfs/neutrinonotify/driver.go +++ b/chainntnfs/neutrinonotify/driver.go @@ -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 diff --git a/chainntnfs/neutrinonotify/neutrino.go b/chainntnfs/neutrinonotify/neutrino.go index 8842d4ce5..2320c0e6e 100644 --- a/chainntnfs/neutrinonotify/neutrino.go +++ b/chainntnfs/neutrinonotify/neutrino.go @@ -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 { diff --git a/chainntnfs/test/test_interface.go b/chainntnfs/test/test_interface.go index bfa4d23c3..bd6b70aca 100644 --- a/chainntnfs/test/test_interface.go +++ b/chainntnfs/test/test_interface.go @@ -1967,6 +1967,7 @@ func TestInterfaces(t *testing.T, targetBackEnd string) { newNotifier = func() (chainntnfs.TestChainNotifier, error) { return neutrinonotify.New( spvNode, hintCache, hintCache, + blockCache, ), nil } } diff --git a/chainreg/chainregistry.go b/chainreg/chainregistry.go index 5b6d59cfe..ffe236ba6 100644 --- a/chainreg/chainregistry.go +++ b/chainreg/chainregistry.go @@ -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,