routing/chainview: optimize neutrino implementation of FilterBlock
This commit optimizes the neutrino implementation of FilterBlock method of the ChainView interface. The old implementation would _always_ fetch the entire block and manually scan through it. Instead, we can just fetch the filter, and then if the items match, fetch the block itself. This will save bandwidth during a lnd node’s pruning of the channel graph after a period of dormancy.
This commit is contained in:
parent
5e2381a64c
commit
38beeebe3d
@ -10,6 +10,7 @@ import (
|
||||
"github.com/roasbeef/btcd/wire"
|
||||
"github.com/roasbeef/btcrpcclient"
|
||||
"github.com/roasbeef/btcutil"
|
||||
"github.com/roasbeef/btcutil/gcs/builder"
|
||||
"github.com/roasbeef/btcwallet/waddrmgr"
|
||||
)
|
||||
|
||||
@ -237,16 +238,55 @@ func (c *CfFilteredChainView) chainFilterer() {
|
||||
//
|
||||
// NOTE: This is part of the FilteredChainView interface.
|
||||
func (c *CfFilteredChainView) FilterBlock(blockHash *chainhash.Hash) (*FilteredBlock, error) {
|
||||
// As we need to manually filter a block, we'll first fetch the block
|
||||
// form the network.
|
||||
block, err := c.p2pNode.GetBlockFromNetwork(*blockHash)
|
||||
// First, we'll fetch the block header itself so we can obtain the
|
||||
// height which is part of our return value.
|
||||
_, blockHeight, err := c.p2pNode.BlockHeaders.FetchHeader(blockHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Along with the block, we'll also need the height of the block in
|
||||
// order to complete the notification.
|
||||
_, blockHeight, err := c.p2pNode.BlockHeaders.FetchHeader(blockHash)
|
||||
filteredBlock := &FilteredBlock{
|
||||
Hash: *blockHash,
|
||||
Height: blockHeight,
|
||||
}
|
||||
|
||||
// Next, using the block, hash, we'll fetch the compact filter for this
|
||||
// block. We only require the regular filter as we're just looking for
|
||||
// outpoint that have been spent.
|
||||
filter, err := c.p2pNode.GetCFilter(*blockHash, false)
|
||||
if err != nil {
|
||||
return filteredBlock, err
|
||||
}
|
||||
|
||||
// Before we can match the filter, we'll need to map each item in our
|
||||
// chain filter to the representation that included in the compact
|
||||
// filters.
|
||||
c.filterMtx.RLock()
|
||||
relevantPoints := make([][]byte, 0, len(c.chainFilter))
|
||||
for op := range c.chainFilter {
|
||||
opBytes := builder.OutPointToFilterEntry(op)
|
||||
relevantPoints = append(relevantPoints, opBytes)
|
||||
}
|
||||
c.filterMtx.RUnlock()
|
||||
|
||||
// With our relevant points constructed, we can finally match against
|
||||
// the retrieved filter.
|
||||
matched, err := filter.MatchAny(builder.DeriveKey(blockHash),
|
||||
relevantPoints)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If there wasn't a match, then we'll return the filtered block as is
|
||||
// (void of any transactions).
|
||||
if !matched {
|
||||
return filteredBlock, nil
|
||||
}
|
||||
|
||||
// If we reach this point, then there was a match, so we'll need to
|
||||
// fetch the block itself so we can scan it for any actual matches (as
|
||||
// there's a fp rate).
|
||||
block, err := c.p2pNode.GetBlockFromNetwork(*blockHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -254,7 +294,6 @@ func (c *CfFilteredChainView) FilterBlock(blockHash *chainhash.Hash) (*FilteredB
|
||||
// Finally, we'll step through the block, input by input, to see if any
|
||||
// transactions spend any outputs from our watched sub-set of the UTXO
|
||||
// set.
|
||||
var filteredTxns []*wire.MsgTx
|
||||
for _, tx := range block.Transactions() {
|
||||
for _, txIn := range tx.MsgTx().TxIn {
|
||||
prevOp := txIn.PreviousOutPoint
|
||||
@ -264,7 +303,10 @@ func (c *CfFilteredChainView) FilterBlock(blockHash *chainhash.Hash) (*FilteredB
|
||||
c.filterMtx.RUnlock()
|
||||
|
||||
if ok {
|
||||
filteredTxns = append(filteredTxns, tx.MsgTx())
|
||||
filteredBlock.Transactions = append(
|
||||
filteredBlock.Transactions,
|
||||
tx.MsgTx(),
|
||||
)
|
||||
|
||||
c.filterMtx.Lock()
|
||||
delete(c.chainFilter, prevOp)
|
||||
@ -275,11 +317,7 @@ func (c *CfFilteredChainView) FilterBlock(blockHash *chainhash.Hash) (*FilteredB
|
||||
}
|
||||
}
|
||||
|
||||
return &FilteredBlock{
|
||||
Hash: *blockHash,
|
||||
Height: blockHeight,
|
||||
Transactions: filteredTxns,
|
||||
}, nil
|
||||
return filteredBlock, nil
|
||||
}
|
||||
|
||||
// UpdateFilter updates the UTXO filter which is to be consulted when creating
|
||||
|
Loading…
Reference in New Issue
Block a user