Skip to content

Commit

Permalink
chain: refactor btcd filter rescan into maybeShouldFetchBlock
Browse files Browse the repository at this point in the history
  • Loading branch information
Roasbeef committed Sep 22, 2023
1 parent 07be54b commit bb4ca79
Showing 1 changed file with 46 additions and 22 deletions.
68 changes: 46 additions & 22 deletions chain/btcd.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,44 @@ func (c *RPCClient) BlockStamp() (*waddrmgr.BlockStamp, error) {
}
}

// maybeShouldFetchBlock returns true if the contents of a block *might* have
// some items that match our watch list. This uses the neutrino filters to do a
// quick loop up to see if the block has relevant items to avoid downloading
// the full block.
func maybeShouldFetchBlock(rpc *rpcclient.Client, blk wtxmgr.BlockMeta,
watchList [][]byte) (bool, error) {

rawFilter, err := rpc.GetCFilter(&blk.Hash, wire.GCSFilterRegular)
if err != nil {
return false, err
}

// Ensure the filter is large enough to be deserialized.
if len(rawFilter.Data) < 4 {
return false, nil
}

filter, err := gcs.FromNBytes(
builder.DefaultP, builder.DefaultM, rawFilter.Data,
)
if err != nil {
return false, err
}

// Skip any empty filters.
if filter.N() == 0 {
return false, nil
}

key := builder.DeriveKey(&blk.Hash)
matched, err := filter.MatchAny(key, watchList)
if err != nil {
return false, err
}

return matched, nil
}

// FilterBlocks scans the blocks contained in the FilterBlocksRequest for any
// addresses of interest. For each requested block, the corresponding compact
// filter will first be checked for matches, skipping those that do not report
Expand All @@ -221,33 +259,19 @@ func (c *RPCClient) FilterBlocks(
// the filter returns a positive match, the full block is then requested
// and scanned for addresses using the block filterer.
for i, blk := range req.Blocks {
rawFilter, err := c.GetCFilter(&blk.Hash, wire.GCSFilterRegular)
if err != nil {
return nil, err
}

// Ensure the filter is large enough to be deserialized.
if len(rawFilter.Data) < 4 {
continue
}

filter, err := gcs.FromNBytes(
builder.DefaultP, builder.DefaultM, rawFilter.Data,
shouldFetchBlock, err := maybeShouldFetchBlock(
c.Client, blk, watchList,
)
if err != nil {
return nil, err
}

// Skip any empty filters.
if filter.N() == 0 {
continue
}

key := builder.DeriveKey(&blk.Hash)
matched, err := filter.MatchAny(key, watchList)
if err != nil {
return nil, err
} else if !matched {
// If the filter concluded that there're no matches in this
// block, then we don't need to fetch it, as there're no false
// negatives.
if !shouldFetchBlock {
log.Infof("Skipping block height=%d hash=%v, no "+
"filter match", blk.Height, blk.Hash)
continue
}

Expand Down

0 comments on commit bb4ca79

Please sign in to comment.