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" "fmt"
"github.com/lightninglabs/neutrino" "github.com/lightninglabs/neutrino"
"github.com/lightningnetwork/lnd/blockcache"
"github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/chainntnfs"
) )
// createNewNotifier creates a new instance of the ChainNotifier interface // createNewNotifier creates a new instance of the ChainNotifier interface
// implemented by NeutrinoNotifier. // implemented by NeutrinoNotifier.
func createNewNotifier(args ...interface{}) (chainntnfs.ChainNotifier, error) { func createNewNotifier(args ...interface{}) (chainntnfs.ChainNotifier, error) {
if len(args) != 3 { if len(args) != 4 {
return nil, fmt.Errorf("incorrect number of arguments to "+ 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) config, ok := args[0].(*neutrino.ChainService)
@ -34,7 +35,13 @@ func createNewNotifier(args ...interface{}) (chainntnfs.ChainNotifier, error) {
"is incorrect, expected a chainntfs.ConfirmHintCache") "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 // 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/btcsuite/btcutil/gcs/builder"
"github.com/lightninglabs/neutrino" "github.com/lightninglabs/neutrino"
"github.com/lightninglabs/neutrino/headerfs" "github.com/lightninglabs/neutrino/headerfs"
"github.com/lightningnetwork/lnd/blockcache"
"github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/queue" "github.com/lightningnetwork/lnd/queue"
) )
@ -73,6 +75,9 @@ type NeutrinoNotifier struct {
// which the transaction could have confirmed within the chain. // which the transaction could have confirmed within the chain.
confirmHintCache chainntnfs.ConfirmHintCache confirmHintCache chainntnfs.ConfirmHintCache
// blockCache is an LRU block cache.
blockCache *blockcache.BlockCache
wg sync.WaitGroup wg sync.WaitGroup
quit chan struct{} quit chan struct{}
} }
@ -86,7 +91,8 @@ var _ chainntnfs.ChainNotifier = (*NeutrinoNotifier)(nil)
// NOTE: The passed neutrino node should already be running and active before // NOTE: The passed neutrino node should already be running and active before
// being passed into this function. // being passed into this function.
func New(node *neutrino.ChainService, spendHintCache chainntnfs.SpendHintCache, func New(node *neutrino.ChainService, spendHintCache chainntnfs.SpendHintCache,
confirmHintCache chainntnfs.ConfirmHintCache) *NeutrinoNotifier { confirmHintCache chainntnfs.ConfirmHintCache,
blockCache *blockcache.BlockCache) *NeutrinoNotifier {
return &NeutrinoNotifier{ return &NeutrinoNotifier{
notificationCancels: make(chan interface{}), notificationCancels: make(chan interface{}),
@ -105,6 +111,8 @@ func New(node *neutrino.ChainService, spendHintCache chainntnfs.SpendHintCache,
spendHintCache: spendHintCache, spendHintCache: spendHintCache,
confirmHintCache: confirmHintCache, confirmHintCache: confirmHintCache,
blockCache: blockCache,
quit: make(chan struct{}), 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 // 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 // from the network so we can find the positional data required
// to send the proper response. // to send the proper response.
block, err := n.p2pNode.GetBlock(*blockHash) block, err := n.GetBlock(*blockHash)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to get block from network: %v", err) 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. // getFilteredBlock is a utility to retrieve the full filtered block from a block epoch.
func (n *NeutrinoNotifier) getFilteredBlock(epoch chainntnfs.BlockEpoch) (*filteredBlock, error) { 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 { if err != nil {
return nil, fmt.Errorf("unable to get block: %v", err) 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 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 // blockEpochRegistration represents a client's intent to receive a
// notification with each newly connected block. // notification with each newly connected block.
type blockEpochRegistration struct { type blockEpochRegistration struct {

View File

@ -1967,6 +1967,7 @@ func TestInterfaces(t *testing.T, targetBackEnd string) {
newNotifier = func() (chainntnfs.TestChainNotifier, error) { newNotifier = func() (chainntnfs.TestChainNotifier, error) {
return neutrinonotify.New( return neutrinonotify.New(
spvNode, hintCache, hintCache, spvNode, hintCache, hintCache,
blockCache,
), nil ), 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 // along with the wallet's ChainSource, which are all backed by
// the neutrino light client. // the neutrino light client.
cc.ChainNotifier = neutrinonotify.New( cc.ChainNotifier = neutrinonotify.New(
cfg.NeutrinoCS, hintCache, hintCache, cfg.NeutrinoCS, hintCache, hintCache, blockCache,
) )
cc.ChainView, err = chainview.NewCfFilteredChainView( cc.ChainView, err = chainview.NewCfFilteredChainView(
cfg.NeutrinoCS, blockCache, cfg.NeutrinoCS, blockCache,