Fixed a couple of bugs and added --dropcfindex option

This commit is contained in:
Alex 2017-02-01 19:51:23 -07:00 committed by Olaoluwa Osuntokun
parent 763842329b
commit 6102e129c5
4 changed files with 68 additions and 24 deletions

View file

@ -6,7 +6,9 @@ package indexers
import ( import (
"errors" "errors"
"github.com/btcsuite/btcd/blockchain" "github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/database" "github.com/btcsuite/btcd/database"
"github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil"
@ -37,14 +39,14 @@ var (
cfExtendedHeaderKey = []byte("cf1headerbyhashidx") cfExtendedHeaderKey = []byte("cf1headerbyhashidx")
) )
// dbFetchFilter() retrieves a block's basic or extended filter. A filter's // dbFetchFilter retrieves a block's basic or extended filter. A filter's
// absence is not considered an error. // absence is not considered an error.
func dbFetchFilter(dbTx database.Tx, key []byte, h *chainhash.Hash) ([]byte, error) { func dbFetchFilter(dbTx database.Tx, key []byte, h *chainhash.Hash) ([]byte, error) {
idx := dbTx.Metadata().Bucket(key) idx := dbTx.Metadata().Bucket(key)
return idx.Get(h[:]), nil return idx.Get(h[:]), nil
} }
// dbFetchFilterHeader() retrieves a block's basic or extended filter header. // dbFetchFilterHeader retrieves a block's basic or extended filter header.
// A filter's absence is not considered an error. // A filter's absence is not considered an error.
func dbFetchFilterHeader(dbTx database.Tx, key []byte, h *chainhash.Hash) ([]byte, error) { func dbFetchFilterHeader(dbTx database.Tx, key []byte, h *chainhash.Hash) ([]byte, error) {
idx := dbTx.Metadata().Bucket(key) idx := dbTx.Metadata().Bucket(key)
@ -55,13 +57,13 @@ func dbFetchFilterHeader(dbTx database.Tx, key []byte, h *chainhash.Hash) ([]byt
return fh, nil return fh, nil
} }
// dbStoreFilter() stores a block's basic or extended filter. // dbStoreFilter stores a block's basic or extended filter.
func dbStoreFilter(dbTx database.Tx, key []byte, h *chainhash.Hash, f []byte) error { func dbStoreFilter(dbTx database.Tx, key []byte, h *chainhash.Hash, f []byte) error {
idx := dbTx.Metadata().Bucket(key) idx := dbTx.Metadata().Bucket(key)
return idx.Put(h[:], f) return idx.Put(h[:], f)
} }
// dbStoreFilterHeader() stores a block's basic or extended filter header. // dbStoreFilterHeader stores a block's basic or extended filter header.
func dbStoreFilterHeader(dbTx database.Tx, key []byte, h *chainhash.Hash, fh []byte) error { func dbStoreFilterHeader(dbTx database.Tx, key []byte, h *chainhash.Hash, fh []byte) error {
if len(fh) != fastsha256.Size { if len(fh) != fastsha256.Size {
return errors.New("invalid filter header length") return errors.New("invalid filter header length")
@ -70,13 +72,13 @@ func dbStoreFilterHeader(dbTx database.Tx, key []byte, h *chainhash.Hash, fh []b
return idx.Put(h[:], fh) return idx.Put(h[:], fh)
} }
// dbDeleteFilter() deletes a filter's basic or extended filter. // dbDeleteFilter deletes a filter's basic or extended filter.
func dbDeleteFilter(dbTx database.Tx, key []byte, h *chainhash.Hash) error { func dbDeleteFilter(dbTx database.Tx, key []byte, h *chainhash.Hash) error {
idx := dbTx.Metadata().Bucket(key) idx := dbTx.Metadata().Bucket(key)
return idx.Delete(h[:]) return idx.Delete(h[:])
} }
// dbDeleteFilterHeader() deletes a filter's basic or extended filter header. // dbDeleteFilterHeader deletes a filter's basic or extended filter header.
func dbDeleteFilterHeader(dbTx database.Tx, key []byte, h *chainhash.Hash) error { func dbDeleteFilterHeader(dbTx database.Tx, key []byte, h *chainhash.Hash) error {
idx := dbTx.Metadata().Bucket(key) idx := dbTx.Metadata().Bucket(key)
return idx.Delete(h[:]) return idx.Delete(h[:])
@ -84,7 +86,8 @@ func dbDeleteFilterHeader(dbTx database.Tx, key []byte, h *chainhash.Hash) error
// CfIndex implements a committed filter (cf) by hash index. // CfIndex implements a committed filter (cf) by hash index.
type CfIndex struct { type CfIndex struct {
db database.DB db database.DB
chainParams *chaincfg.Params
} }
// Ensure the CfIndex type implements the Indexer interface. // Ensure the CfIndex type implements the Indexer interface.
@ -108,7 +111,7 @@ func (idx *CfIndex) Name() string {
return cfIndexName return cfIndexName
} }
// Create() is invoked when the indexer manager determines the index needs to // Create is invoked when the indexer manager determines the index needs to
// be created for the first time. It creates buckets for the two hash-based cf // be created for the first time. It creates buckets for the two hash-based cf
// indexes (simple, extended). // indexes (simple, extended).
func (idx *CfIndex) Create(dbTx database.Tx) error { func (idx *CfIndex) Create(dbTx database.Tx) error {
@ -126,10 +129,29 @@ func (idx *CfIndex) Create(dbTx database.Tx) error {
return err return err
} }
_, err = meta.CreateBucket(cfExtendedHeaderKey) _, err = meta.CreateBucket(cfExtendedHeaderKey)
if err != nil {
return err
}
firstHeader := make([]byte, chainhash.HashSize)
err = dbStoreFilterHeader(
dbTx,
cfBasicHeaderKey,
&idx.chainParams.GenesisBlock.Header.PrevBlock,
firstHeader,
)
if err != nil {
return err
}
err = dbStoreFilterHeader(
dbTx,
cfExtendedHeaderKey,
&idx.chainParams.GenesisBlock.Header.PrevBlock,
firstHeader,
)
return err return err
} }
// makeBasicFilterForBlock() builds a block's basic filter, which consists of // makeBasicFilterForBlock builds a block's basic filter, which consists of
// all outpoints and pkscript data pushes referenced by transactions within the // all outpoints and pkscript data pushes referenced by transactions within the
// block. // block.
func makeBasicFilterForBlock(block *btcutil.Block) ([]byte, error) { func makeBasicFilterForBlock(block *btcutil.Block) ([]byte, error) {
@ -153,7 +175,7 @@ func makeBasicFilterForBlock(block *btcutil.Block) ([]byte, error) {
return f.Bytes(), nil return f.Bytes(), nil
} }
// makeExtendedFilterForBlock() builds a block's extended filter, which consists // makeExtendedFilterForBlock builds a block's extended filter, which consists
// of all tx hashes and sigscript data pushes contained in the block. // of all tx hashes and sigscript data pushes contained in the block.
func makeExtendedFilterForBlock(block *btcutil.Block) ([]byte, error) { func makeExtendedFilterForBlock(block *btcutil.Block) ([]byte, error) {
b := builder.WithKeyHash(block.Hash()) b := builder.WithKeyHash(block.Hash())
@ -174,7 +196,7 @@ func makeExtendedFilterForBlock(block *btcutil.Block) ([]byte, error) {
return f.Bytes(), nil return f.Bytes(), nil
} }
// makeHeaderForFilter() implements the chaining logic between filters, where // makeHeaderForFilter implements the chaining logic between filters, where
// a filter's header is defined as sha256(sha256(filter) + previousFilterHeader). // a filter's header is defined as sha256(sha256(filter) + previousFilterHeader).
func makeHeaderForFilter(f, pfh []byte) []byte { func makeHeaderForFilter(f, pfh []byte) []byte {
fhash := fastsha256.Sum256(f) fhash := fastsha256.Sum256(f)
@ -185,7 +207,7 @@ func makeHeaderForFilter(f, pfh []byte) []byte {
return fh[:] return fh[:]
} }
// storeFilter() stores a given filter, and performs the steps needed to // storeFilter stores a given filter, and performs the steps needed to
// generate the filter's header. // generate the filter's header.
func storeFilter(dbTx database.Tx, block *btcutil.Block, f []byte, extended bool) error { func storeFilter(dbTx database.Tx, block *btcutil.Block, f []byte, extended bool) error {
// Figure out which buckets to use. // Figure out which buckets to use.
@ -209,14 +231,14 @@ func storeFilter(dbTx database.Tx, block *btcutil.Block, f []byte, extended bool
} }
// Construct the new block's filter header, and store it. // Construct the new block's filter header, and store it.
fh := makeHeaderForFilter(f, pfh) fh := makeHeaderForFilter(f, pfh)
return dbStoreFilterHeader(dbTx, cfBasicHeaderKey, h, fh) return dbStoreFilterHeader(dbTx, hkey, h, fh)
} }
// ConnectBlock() is invoked by the index manager when a new block has been // ConnectBlock is invoked by the index manager when a new block has been
// connected to the main chain. This indexer adds a hash-to-cf mapping for // connected to the main chain. This indexer adds a hash-to-cf mapping for
// every passed block. This is part of the Indexer interface. // every passed block. This is part of the Indexer interface.
func (idx *CfIndex) ConnectBlock(dbTx database.Tx, block *btcutil.Block, func (idx *CfIndex) ConnectBlock(dbTx database.Tx, block *btcutil.Block,
view *blockchain.UtxoViewpoint) error { view *blockchain.UtxoViewpoint) error {
f, err := makeBasicFilterForBlock(block) f, err := makeBasicFilterForBlock(block)
if err != nil { if err != nil {
return err return err
@ -232,11 +254,11 @@ func (idx *CfIndex) ConnectBlock(dbTx database.Tx, block *btcutil.Block,
return storeFilter(dbTx, block, f, true) return storeFilter(dbTx, block, f, true)
} }
// DisconnectBlock() is invoked by the index manager when a block has been // DisconnectBlock is invoked by the index manager when a block has been
// disconnected from the main chain. This indexer removes the hash-to-cf // disconnected from the main chain. This indexer removes the hash-to-cf
// mapping for every passed block. This is part of the Indexer interface. // mapping for every passed block. This is part of the Indexer interface.
func (idx *CfIndex) DisconnectBlock(dbTx database.Tx, block *btcutil.Block, func (idx *CfIndex) DisconnectBlock(dbTx database.Tx, block *btcutil.Block,
view *blockchain.UtxoViewpoint) error { view *blockchain.UtxoViewpoint) error {
err := dbDeleteFilter(dbTx, cfBasicIndexKey, block.Hash()) err := dbDeleteFilter(dbTx, cfBasicIndexKey, block.Hash())
if err != nil { if err != nil {
return err return err
@ -244,7 +266,7 @@ func (idx *CfIndex) DisconnectBlock(dbTx database.Tx, block *btcutil.Block,
return dbDeleteFilter(dbTx, cfExtendedIndexKey, block.Hash()) return dbDeleteFilter(dbTx, cfExtendedIndexKey, block.Hash())
} }
// FilterByBlockHash() returns the serialized contents of a block's basic or // FilterByBlockHash returns the serialized contents of a block's basic or
// extended committed filter. // extended committed filter.
func (idx *CfIndex) FilterByBlockHash(h *chainhash.Hash, extended bool) ([]byte, error) { func (idx *CfIndex) FilterByBlockHash(h *chainhash.Hash, extended bool) ([]byte, error) {
var f []byte var f []byte
@ -260,7 +282,7 @@ func (idx *CfIndex) FilterByBlockHash(h *chainhash.Hash, extended bool) ([]byte,
return f, err return f, err
} }
// FilterHeaderByBlockHash() returns the serialized contents of a block's basic // FilterHeaderByBlockHash returns the serialized contents of a block's basic
// or extended committed filter header. // or extended committed filter header.
func (idx *CfIndex) FilterHeaderByBlockHash(h *chainhash.Hash, extended bool) ([]byte, error) { func (idx *CfIndex) FilterHeaderByBlockHash(h *chainhash.Hash, extended bool) ([]byte, error) {
var fh []byte var fh []byte
@ -283,11 +305,24 @@ func (idx *CfIndex) FilterHeaderByBlockHash(h *chainhash.Hash, extended bool) ([
// It implements the Indexer interface which plugs into the IndexManager that in // It implements the Indexer interface which plugs into the IndexManager that in
// turn is used by the blockchain package. This allows the index to be // turn is used by the blockchain package. This allows the index to be
// seamlessly maintained along with the chain. // seamlessly maintained along with the chain.
func NewCfIndex(db database.DB) *CfIndex { func NewCfIndex(db database.DB, chainParams *chaincfg.Params) *CfIndex {
return &CfIndex{db: db} return &CfIndex{db: db, chainParams: chainParams}
} }
// DropCfIndex drops the CF index from the provided database if exists. // DropCfIndex drops the CF index from the provided database if exists.
func DropCfIndex(db database.DB) error { func DropCfIndex(db database.DB) error {
return dropIndex(db, cfBasicIndexKey, cfIndexName) err := dropIndex(db, cfBasicIndexKey, cfIndexName)
if err != nil {
return err
}
err = dropIndex(db, cfBasicHeaderKey, cfIndexName)
if err != nil {
return err
}
err = dropIndex(db, cfExtendedIndexKey, cfIndexName)
if err != nil {
return err
}
err = dropIndex(db, cfExtendedHeaderKey, cfIndexName)
return err
} }

View file

@ -135,6 +135,14 @@ func btcdMain(serverChan chan<- *server) error {
return nil return nil
} }
if cfg.DropCfIndex {
if err := indexers.DropCfIndex(db); err != nil {
btcdLog.Errorf("%v", err)
return err
}
return nil
}
// Create server and start it. // Create server and start it.
server, err := newServer(cfg.Listeners, db, activeNetParams.Params, server, err := newServer(cfg.Listeners, db, activeNetParams.Params,

View file

@ -151,6 +151,7 @@ type config struct {
UserAgentComments []string `long:"uacomment" description:"Comment to add to the user agent -- See BIP 14 for more information."` UserAgentComments []string `long:"uacomment" description:"Comment to add to the user agent -- See BIP 14 for more information."`
NoPeerBloomFilters bool `long:"nopeerbloomfilters" description:"Disable bloom filtering support"` NoPeerBloomFilters bool `long:"nopeerbloomfilters" description:"Disable bloom filtering support"`
NoCFilters bool `long:"nocfilters" description:"Disable committed filtering (CF) support"` NoCFilters bool `long:"nocfilters" description:"Disable committed filtering (CF) support"`
DropCfIndex bool `long:"dropcfindex" description:"Deletes the index used for committed filtering (CF) support from the database on start up and then exits."`
SigCacheMaxSize uint `long:"sigcachemaxsize" description:"The maximum number of entries in the signature verification cache"` SigCacheMaxSize uint `long:"sigcachemaxsize" description:"The maximum number of entries in the signature verification cache"`
BlocksOnly bool `long:"blocksonly" description:"Do not accept transactions from remote peers."` BlocksOnly bool `long:"blocksonly" description:"Do not accept transactions from remote peers."`
TxIndex bool `long:"txindex" description:"Maintain a full hash-based transaction index which makes all transactions available via the getrawtransaction RPC"` TxIndex bool `long:"txindex" description:"Maintain a full hash-based transaction index which makes all transactions available via the getrawtransaction RPC"`

View file

@ -747,7 +747,7 @@ func (sp *serverPeer) OnGetCFilter(_ *peer.Peer, msg *wire.MsgGetCFilter) {
} }
filterBytes, err := sp.server.cfIndex.FilterByBlockHash(&msg.BlockHash, filterBytes, err := sp.server.cfIndex.FilterByBlockHash(&msg.BlockHash,
msg.Extended) msg.Extended)
if len(filterBytes) > 0 { if len(filterBytes) > 0 {
peerLog.Infof("Obtained CB filter for %v", msg.BlockHash) peerLog.Infof("Obtained CB filter for %v", msg.BlockHash)
@ -2249,7 +2249,7 @@ func newServer(listenAddrs []string, db database.DB, chainParams *chaincfg.Param
} }
if !cfg.NoCFilters { if !cfg.NoCFilters {
indxLog.Info("cf index is enabled") indxLog.Info("cf index is enabled")
s.cfIndex = indexers.NewCfIndex(db) s.cfIndex = indexers.NewCfIndex(db, chainParams)
indexes = append(indexes, s.cfIndex) indexes = append(indexes, s.cfIndex)
} }