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 68a1b2f2..dbd89718 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 8842d4ce..2320c0e6 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 bfa4d23c..bd6b70ac 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 5b6d59cf..ffe236ba 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,