blockchain/indexers: Store filter hashes with cfindex.

This commit is contained in:
Jim Posen 2018-01-22 12:59:20 -08:00 committed by Olaoluwa Osuntokun
parent d07fd2f333
commit e617483b44

View file

@ -44,7 +44,18 @@ var (
[]byte("cf1headerbyhashidx"), []byte("cf1headerbyhashidx"),
} }
// cfHashKeys is an array of db bucket names used to house indexes of
// block hashes to cf hashes.
cfHashKeys = [][]byte{
[]byte("cf0hashbyhashidx"),
[]byte("cf1hashbyhashidx"),
}
maxFilterType = uint8(len(cfHeaderKeys) - 1) maxFilterType = uint8(len(cfHeaderKeys) - 1)
// zeroHash is the chainhash.Hash value of all zero bytes, defined here for
// convenience.
zeroHash chainhash.Hash
) )
// dbFetchFilterIdxEntry retrieves a data blob from the filter index database. // dbFetchFilterIdxEntry retrieves a data blob from the filter index database.
@ -118,23 +129,14 @@ func (idx *CfIndex) Create(dbTx database.Tx) error {
} }
} }
firstHeader := make([]byte, chainhash.HashSize) for _, bucketName := range cfHashKeys {
err = dbStoreFilterIdxEntry( _, err = cfIndexParentBucket.CreateBucket(bucketName)
dbTx, if err != nil {
cfHeaderKeys[wire.GCSFilterRegular], return err
&idx.chainParams.GenesisBlock.Header.PrevBlock, }
firstHeader,
)
if err != nil {
return err
} }
return dbStoreFilterIdxEntry( return nil
dbTx,
cfHeaderKeys[wire.GCSFilterExtended],
&idx.chainParams.GenesisBlock.Header.PrevBlock,
firstHeader,
)
} }
// storeFilter stores a given filter, and performs the steps needed to // storeFilter stores a given filter, and performs the steps needed to
@ -148,6 +150,7 @@ func storeFilter(dbTx database.Tx, block *btcutil.Block, f *gcs.Filter,
// Figure out which buckets to use. // Figure out which buckets to use.
fkey := cfIndexKeys[filterType] fkey := cfIndexKeys[filterType]
hkey := cfHeaderKeys[filterType] hkey := cfHeaderKeys[filterType]
hashkey := cfHashKeys[filterType]
// Start by storing the filter. // Start by storing the filter.
h := block.Hash() h := block.Hash()
@ -160,18 +163,34 @@ func storeFilter(dbTx database.Tx, block *btcutil.Block, f *gcs.Filter,
return err return err
} }
// Then fetch the previous block's filter header. // Next store the filter hash.
ph := &block.MsgBlock().Header.PrevBlock filterHash, err := builder.GetFilterHash(f)
pfh, err := dbFetchFilterIdxEntry(dbTx, hkey, ph) if err != nil {
return err
}
err = dbStoreFilterIdxEntry(dbTx, hashkey, h, filterHash[:])
if err != nil { if err != nil {
return err return err
} }
// Construct the new block's filter header, and store it. // Then fetch the previous block's filter header.
prevHeader, err := chainhash.NewHash(pfh) var prevHeader *chainhash.Hash
if err != nil { ph := &block.MsgBlock().Header.PrevBlock
return err if ph.IsEqual(&zeroHash) {
prevHeader = &zeroHash
} else {
pfh, err := dbFetchFilterIdxEntry(dbTx, hkey, ph)
if err != nil {
return err
}
// Construct the new block's filter header, and store it.
prevHeader, err = chainhash.NewHash(pfh)
if err != nil {
return err
}
} }
fh, err := builder.MakeHeaderForFilter(f, *prevHeader) fh, err := builder.MakeHeaderForFilter(f, *prevHeader)
if err != nil { if err != nil {
return err return err
@ -190,8 +209,8 @@ func (idx *CfIndex) ConnectBlock(dbTx database.Tx, block *btcutil.Block,
return err return err
} }
if err := storeFilter(dbTx, block, f, err = storeFilter(dbTx, block, f, wire.GCSFilterRegular)
wire.GCSFilterRegular); err != nil { if err != nil {
return err return err
} }
@ -223,6 +242,13 @@ func (idx *CfIndex) DisconnectBlock(dbTx database.Tx, block *btcutil.Block,
} }
} }
for _, key := range cfHashKeys {
err := dbDeleteFilterIdxEntry(dbTx, key, block.Hash())
if err != nil {
return err
}
}
return nil return nil
} }
@ -259,6 +285,13 @@ func (idx *CfIndex) FilterHeaderByBlockHash(h *chainhash.Hash,
return idx.entryByBlockHash(cfHeaderKeys, filterType, h) return idx.entryByBlockHash(cfHeaderKeys, filterType, h)
} }
// FilterHeaderByBlockHash returns the serialized contents of a block's basic
// or extended committed filter hash.
func (idx *CfIndex) FilterHashByBlockHash(h *chainhash.Hash,
filterType wire.FilterType) ([]byte, error) {
return idx.entryByBlockHash(cfHashKeys, filterType, h)
}
// NewCfIndex returns a new instance of an indexer that is used to create a // NewCfIndex returns a new instance of an indexer that is used to create a
// mapping of the hashes of all blocks in the blockchain to their respective // mapping of the hashes of all blocks in the blockchain to their respective
// committed filters. // committed filters.