From 8a33fbf11a81b1fa823c61471c62d611d6692fbf Mon Sep 17 00:00:00 2001
From: Elle Mouton <elle.mouton@gmail.com>
Date: Thu, 18 Mar 2021 14:42:18 +0200
Subject: [PATCH] chainntnfs: add block cache to BitcoindNotifier

This commit adds a blockcache pointer to BitcoindNotifier and wraps its
GetBlock method so that the block cache is used.
---
 chainntnfs/bitcoindnotify/bitcoind.go      | 23 ++++++++++++++++++----
 chainntnfs/bitcoindnotify/bitcoind_test.go | 16 +++++++++++----
 chainntnfs/bitcoindnotify/driver.go        | 14 ++++++++++---
 chainntnfs/test/test_interface.go          |  5 ++++-
 chainreg/chainregistry.go                  |  3 ++-
 5 files changed, 48 insertions(+), 13 deletions(-)

diff --git a/chainntnfs/bitcoindnotify/bitcoind.go b/chainntnfs/bitcoindnotify/bitcoind.go
index 496589463..b30c45dca 100644
--- a/chainntnfs/bitcoindnotify/bitcoind.go
+++ b/chainntnfs/bitcoindnotify/bitcoind.go
@@ -13,6 +13,7 @@ import (
 	"github.com/btcsuite/btcd/wire"
 	"github.com/btcsuite/btcutil"
 	"github.com/btcsuite/btcwallet/chain"
+	"github.com/lightningnetwork/lnd/blockcache"
 	"github.com/lightningnetwork/lnd/chainntnfs"
 	"github.com/lightningnetwork/lnd/queue"
 )
@@ -50,6 +51,9 @@ type BitcoindNotifier struct {
 
 	bestBlock chainntnfs.BlockEpoch
 
+	// blockCache is a LRU block cache.
+	blockCache *blockcache.BlockCache
+
 	// spendHintCache is a cache used to query and update the latest height
 	// hints for an outpoint. Each height hint represents the earliest
 	// height at which the outpoint could have been spent within the chain.
@@ -73,7 +77,8 @@ var _ chainntnfs.ChainNotifier = (*BitcoindNotifier)(nil)
 // willing to accept RPC requests and new zmq clients.
 func New(chainConn *chain.BitcoindConn, chainParams *chaincfg.Params,
 	spendHintCache chainntnfs.SpendHintCache,
-	confirmHintCache chainntnfs.ConfirmHintCache) *BitcoindNotifier {
+	confirmHintCache chainntnfs.ConfirmHintCache,
+	blockCache *blockcache.BlockCache) *BitcoindNotifier {
 
 	notifier := &BitcoindNotifier{
 		chainParams: chainParams,
@@ -86,6 +91,8 @@ func New(chainConn *chain.BitcoindConn, chainParams *chaincfg.Params,
 		spendHintCache:   spendHintCache,
 		confirmHintCache: confirmHintCache,
 
+		blockCache: blockCache,
+
 		quit: make(chan struct{}),
 	}
 
@@ -522,7 +529,7 @@ func (b *BitcoindNotifier) confDetailsManually(confRequest chainntnfs.ConfReques
 					"with height %d", height)
 		}
 
-		block, err := b.chainConn.GetBlock(blockHash)
+		block, err := b.GetBlock(blockHash)
 		if err != nil {
 			return nil, chainntnfs.TxNotFoundManually,
 				fmt.Errorf("unable to get block with hash "+
@@ -558,7 +565,7 @@ func (b *BitcoindNotifier) handleBlockConnected(block chainntnfs.BlockEpoch) err
 	// First, we'll fetch the raw block as we'll need to gather all the
 	// transactions to determine whether any are relevant to our registered
 	// clients.
-	rawBlock, err := b.chainConn.GetBlock(block.Hash)
+	rawBlock, err := b.GetBlock(block.Hash)
 	if err != nil {
 		return fmt.Errorf("unable to get block: %v", err)
 	}
@@ -777,7 +784,7 @@ func (b *BitcoindNotifier) historicalSpendDetails(
 			return nil, fmt.Errorf("unable to retrieve hash for "+
 				"block with height %d: %v", height, err)
 		}
-		block, err := b.chainConn.GetBlock(blockHash)
+		block, err := b.GetBlock(blockHash)
 		if err != nil {
 			return nil, fmt.Errorf("unable to retrieve block "+
 				"with hash %v: %v", blockHash, err)
@@ -955,3 +962,11 @@ func (b *BitcoindNotifier) RegisterBlockEpochNtfn(
 		}, nil
 	}
 }
+
+// GetBlock is used to retrieve the block with the given hash. This function
+// wraps the blockCache's GetBlock function.
+func (b *BitcoindNotifier) GetBlock(hash *chainhash.Hash) (*wire.MsgBlock,
+	error) {
+
+	return b.blockCache.GetBlock(hash, b.chainConn.GetBlock)
+}
diff --git a/chainntnfs/bitcoindnotify/bitcoind_test.go b/chainntnfs/bitcoindnotify/bitcoind_test.go
index 89c68d2e5..e48423bcb 100644
--- a/chainntnfs/bitcoindnotify/bitcoind_test.go
+++ b/chainntnfs/bitcoindnotify/bitcoind_test.go
@@ -11,6 +11,7 @@ import (
 	"github.com/btcsuite/btcd/chaincfg/chainhash"
 	"github.com/btcsuite/btcd/integration/rpctest"
 	"github.com/btcsuite/btcwallet/chain"
+	"github.com/lightningnetwork/lnd/blockcache"
 	"github.com/lightningnetwork/lnd/chainntnfs"
 	"github.com/lightningnetwork/lnd/channeldb"
 )
@@ -55,13 +56,14 @@ func initHintCache(t *testing.T) *chainntnfs.HeightHintCache {
 // bitcoind driver.
 func setUpNotifier(t *testing.T, bitcoindConn *chain.BitcoindConn,
 	spendHintCache chainntnfs.SpendHintCache,
-	confirmHintCache chainntnfs.ConfirmHintCache) *BitcoindNotifier {
+	confirmHintCache chainntnfs.ConfirmHintCache,
+	blockCache *blockcache.BlockCache) *BitcoindNotifier {
 
 	t.Helper()
 
 	notifier := New(
 		bitcoindConn, chainntnfs.NetParams, spendHintCache,
-		confirmHintCache,
+		confirmHintCache, blockCache,
 	)
 	if err := notifier.Start(); err != nil {
 		t.Fatalf("unable to start notifier: %v", err)
@@ -116,8 +118,11 @@ func TestHistoricalConfDetailsTxIndex(t *testing.T) {
 	defer cleanUp()
 
 	hintCache := initHintCache(t)
+	blockCache := blockcache.NewBlockCache(10000)
 
-	notifier := setUpNotifier(t, bitcoindConn, hintCache, hintCache)
+	notifier := setUpNotifier(
+		t, bitcoindConn, hintCache, hintCache, blockCache,
+	)
 	defer notifier.Stop()
 
 	syncNotifierWithMiner(t, notifier, miner)
@@ -209,8 +214,11 @@ func TestHistoricalConfDetailsNoTxIndex(t *testing.T) {
 	defer cleanUp()
 
 	hintCache := initHintCache(t)
+	blockCache := blockcache.NewBlockCache(10000)
 
-	notifier := setUpNotifier(t, bitcoindConn, hintCache, hintCache)
+	notifier := setUpNotifier(
+		t, bitcoindConn, hintCache, hintCache, blockCache,
+	)
 	defer notifier.Stop()
 
 	// Since the node has its txindex disabled, we fall back to scanning the
diff --git a/chainntnfs/bitcoindnotify/driver.go b/chainntnfs/bitcoindnotify/driver.go
index 6054f0dee..634aa3545 100644
--- a/chainntnfs/bitcoindnotify/driver.go
+++ b/chainntnfs/bitcoindnotify/driver.go
@@ -6,15 +6,16 @@ import (
 
 	"github.com/btcsuite/btcd/chaincfg"
 	"github.com/btcsuite/btcwallet/chain"
+	"github.com/lightningnetwork/lnd/blockcache"
 	"github.com/lightningnetwork/lnd/chainntnfs"
 )
 
 // createNewNotifier creates a new instance of the ChainNotifier interface
 // implemented by BitcoindNotifier.
 func createNewNotifier(args ...interface{}) (chainntnfs.ChainNotifier, error) {
-	if len(args) != 4 {
+	if len(args) != 5 {
 		return nil, fmt.Errorf("incorrect number of arguments to "+
-			".New(...), expected 4, instead passed %v", len(args))
+			".New(...), expected 5, instead passed %v", len(args))
 	}
 
 	chainConn, ok := args[0].(*chain.BitcoindConn)
@@ -41,7 +42,14 @@ func createNewNotifier(args ...interface{}) (chainntnfs.ChainNotifier, error) {
 			"is incorrect, expected a chainntnfs.ConfirmHintCache")
 	}
 
-	return New(chainConn, chainParams, spendHintCache, confirmHintCache), nil
+	blockCache, ok := args[4].(*blockcache.BlockCache)
+	if !ok {
+		return nil, errors.New("fifth argument to bitcoindnotify.New " +
+			"is incorrect, expected a *blockcache.BlockCache")
+	}
+
+	return New(chainConn, chainParams, spendHintCache,
+		confirmHintCache, blockCache), nil
 }
 
 // init registers a driver for the BtcdNotifier concrete implementation of the
diff --git a/chainntnfs/test/test_interface.go b/chainntnfs/test/test_interface.go
index 622975e16..4b5c69f3b 100644
--- a/chainntnfs/test/test_interface.go
+++ b/chainntnfs/test/test_interface.go
@@ -19,6 +19,7 @@ import (
 	"github.com/btcsuite/btcwallet/chain"
 	_ "github.com/btcsuite/btcwallet/walletdb/bdb" // Required to auto-register the boltdb walletdb implementation.
 	"github.com/lightninglabs/neutrino"
+	"github.com/lightningnetwork/lnd/blockcache"
 	"github.com/lightningnetwork/lnd/chainntnfs"
 	"github.com/lightningnetwork/lnd/chainntnfs/bitcoindnotify"
 	"github.com/lightningnetwork/lnd/chainntnfs/btcdnotify"
@@ -1930,6 +1931,8 @@ func TestInterfaces(t *testing.T, targetBackEnd string) {
 			t.Fatalf("unable to create height hint cache: %v", err)
 		}
 
+		blockCache := blockcache.NewBlockCache(10000)
+
 		var (
 			cleanUp     func()
 			newNotifier func() (chainntnfs.TestChainNotifier, error)
@@ -1944,7 +1947,7 @@ func TestInterfaces(t *testing.T, targetBackEnd string) {
 			newNotifier = func() (chainntnfs.TestChainNotifier, error) {
 				return bitcoindnotify.New(
 					bitcoindConn, chainntnfs.NetParams,
-					hintCache, hintCache,
+					hintCache, hintCache, blockCache,
 				), nil
 			}
 
diff --git a/chainreg/chainregistry.go b/chainreg/chainregistry.go
index dda18a805..28f7e3864 100644
--- a/chainreg/chainregistry.go
+++ b/chainreg/chainregistry.go
@@ -416,7 +416,8 @@ func NewChainControl(cfg *Config) (*ChainControl, func(), error) {
 		}
 
 		cc.ChainNotifier = bitcoindnotify.New(
-			bitcoindConn, cfg.ActiveNetParams.Params, hintCache, hintCache,
+			bitcoindConn, cfg.ActiveNetParams.Params, hintCache,
+			hintCache, blockCache,
 		)
 		cc.ChainView = chainview.NewBitcoindFilteredChainView(
 			bitcoindConn, blockCache,