diff --git a/blockchain/indexers/cfindex.go b/blockchain/indexers/cfindex.go index d89013a0..0e7d3bbf 100644 --- a/blockchain/indexers/cfindex.go +++ b/blockchain/indexers/cfindex.go @@ -30,21 +30,21 @@ var ( // the index. The rest of the buckets live below this bucket. cfIndexParentBucketKey = []byte("cfindexparentbucket") - // cfBasicIndexKey is the name of the db bucket used to house the - // block hash -> basic cf index (cf#0). - cfBasicIndexKey = []byte("cf0byhashidx") + // cfIndexKeys is an array of db bucket names used to house indexes of + // block hashes to cfilters. + cfIndexKeys = [][]byte{ + []byte("cf0byhashidx"), + []byte("cf1byhashidx"), + } - // cfBasicHeaderKey is the name of the db bucket used to house the - // block hash -> basic cf header index (cf#0). - cfBasicHeaderKey = []byte("cf0headerbyhashidx") + // cfHeaderKeys is an array of db bucket names used to house indexes of + // block hashes to cf headers. + cfHeaderKeys = [][]byte{ + []byte("cf0headerbyhashidx"), + []byte("cf1headerbyhashidx"), + } - // cfExtendedIndexKey is the name of the db bucket used to house the - // block hash -> extended cf index (cf#1). - cfExtendedIndexKey = []byte("cf1byhashidx") - - // cfExtendedHeaderKey is the name of the db bucket used to house the - // block hash -> extended cf header index (cf#1). - cfExtendedHeaderKey = []byte("cf1headerbyhashidx") + maxFilterType = uint8(len(cfHeaderKeys) - 1) ) // dbFetchFilter retrieves a block's basic or extended filter. A filter's @@ -131,27 +131,25 @@ func (idx *CfIndex) Create(dbTx database.Tx) error { if err != nil { return err } - _, err = cfIndexParentBucket.CreateBucket(cfBasicIndexKey) - if err != nil { - return err + + for _, bucketName := range cfIndexKeys { + _, err = cfIndexParentBucket.CreateBucket(bucketName) + if err != nil { + return err + } } - _, err = cfIndexParentBucket.CreateBucket(cfBasicHeaderKey) - if err != nil { - return err - } - _, err = cfIndexParentBucket.CreateBucket(cfExtendedIndexKey) - if err != nil { - return err - } - _, err = cfIndexParentBucket.CreateBucket(cfExtendedHeaderKey) - if err != nil { - return err + + for _, bucketName := range cfHeaderKeys { + _, err = cfIndexParentBucket.CreateBucket(bucketName) + if err != nil { + return err + } } firstHeader := make([]byte, chainhash.HashSize) err = dbStoreFilterHeader( dbTx, - cfBasicHeaderKey, + cfHeaderKeys[0], &idx.chainParams.GenesisBlock.Header.PrevBlock, firstHeader, ) @@ -161,7 +159,7 @@ func (idx *CfIndex) Create(dbTx database.Tx) error { return dbStoreFilterHeader( dbTx, - cfExtendedHeaderKey, + cfHeaderKeys[1], &idx.chainParams.GenesisBlock.Header.PrevBlock, firstHeader, ) @@ -170,15 +168,14 @@ func (idx *CfIndex) Create(dbTx database.Tx) error { // storeFilter stores a given filter, and performs the steps needed to // generate the filter's header. func storeFilter(dbTx database.Tx, block *btcutil.Block, f *gcs.Filter, - extended bool) error { + filterType uint8) error { + if filterType > maxFilterType { + return errors.New("unsupported filter type") + } // Figure out which buckets to use. - fkey := cfBasicIndexKey - hkey := cfBasicHeaderKey - if extended { - fkey = cfExtendedIndexKey - hkey = cfExtendedHeaderKey - } + fkey := cfIndexKeys[filterType] + hkey := cfHeaderKeys[filterType] // Start by storing the filter. h := block.Hash() @@ -218,7 +215,7 @@ func (idx *CfIndex) ConnectBlock(dbTx database.Tx, block *btcutil.Block, return err } - if err := storeFilter(dbTx, block, f, false); err != nil { + if err := storeFilter(dbTx, block, f, 0); err != nil { return err } @@ -227,7 +224,7 @@ func (idx *CfIndex) ConnectBlock(dbTx database.Tx, block *btcutil.Block, return err } - return storeFilter(dbTx, block, f, true) + return storeFilter(dbTx, block, f, 1) } // DisconnectBlock is invoked by the index manager when a block has been @@ -236,26 +233,34 @@ func (idx *CfIndex) ConnectBlock(dbTx database.Tx, block *btcutil.Block, func (idx *CfIndex) DisconnectBlock(dbTx database.Tx, block *btcutil.Block, view *blockchain.UtxoViewpoint) error { - err := dbDeleteFilter(dbTx, cfBasicIndexKey, block.Hash()) - if err != nil { - return err + for _, key := range cfIndexKeys { + err := dbDeleteFilter(dbTx, key, block.Hash()) + if err != nil { + return err + } } - return dbDeleteFilter(dbTx, cfExtendedIndexKey, block.Hash()) + for _, key := range cfHeaderKeys { + err := dbDeleteFilterHeader(dbTx, key, block.Hash()) + if err != nil { + return err + } + } + + return nil } // FilterByBlockHash returns the serialized contents of a block's basic or // extended committed filter. -func (idx *CfIndex) FilterByBlockHash(h *chainhash.Hash, extended bool) ([]byte, error) { +func (idx *CfIndex) FilterByBlockHash(h *chainhash.Hash, filterType uint8) ([]byte, error) { var f []byte err := idx.db.View(func(dbTx database.Tx) error { - var err error - key := cfBasicIndexKey - if extended { - key = cfExtendedIndexKey + if filterType > maxFilterType { + return errors.New("unsupported filter type") } - f, err = dbFetchFilter(dbTx, key, h) + var err error + f, err = dbFetchFilter(dbTx, cfIndexKeys[filterType], h) return err }) return f, err @@ -263,16 +268,15 @@ func (idx *CfIndex) FilterByBlockHash(h *chainhash.Hash, extended bool) ([]byte, // FilterHeaderByBlockHash returns the serialized contents of a block's basic // or extended committed filter header. -func (idx *CfIndex) FilterHeaderByBlockHash(h *chainhash.Hash, extended bool) ([]byte, error) { +func (idx *CfIndex) FilterHeaderByBlockHash(h *chainhash.Hash, filterType uint8) ([]byte, error) { var fh []byte err := idx.db.View(func(dbTx database.Tx) error { - var err error - key := cfBasicHeaderKey - if extended { - key = cfExtendedHeaderKey + if filterType > 1 { + return errors.New("unsupported filter type") } - fh, err = dbFetchFilterHeader(dbTx, key, h) + var err error + fh, err = dbFetchFilterHeader(dbTx, cfHeaderKeys[filterType], h) return err }) return fh, err diff --git a/btcjson/chainsvrcmds.go b/btcjson/chainsvrcmds.go index f3993975..e7d736f0 100644 --- a/btcjson/chainsvrcmds.go +++ b/btcjson/chainsvrcmds.go @@ -278,33 +278,34 @@ func NewGetBlockTemplateCmd(request *TemplateRequest) *GetBlockTemplateCmd { Request: request, } } + // GetCFilterCmd defines the getcfilter JSON-RPC command. type GetCFilterCmd struct { - Hash string - Extended bool + Hash string + FilterType uint8 } // NewGetCFilterCmd returns a new instance which can be used to issue a // getcfilter JSON-RPC command. -func NewGetCFilterCmd(hash string, extended bool) *GetCFilterCmd { +func NewGetCFilterCmd(hash string, filterType uint8) *GetCFilterCmd { return &GetCFilterCmd{ - Hash: hash, - Extended: extended, + Hash: hash, + FilterType: filterType, } } // GetCFilterHeaderCmd defines the getcfilterheader JSON-RPC command. type GetCFilterHeaderCmd struct { - Hash string - Extended bool + Hash string + FilterType uint8 } // NewGetCFilterHeaderCmd returns a new instance which can be used to issue a // getcfilterheader JSON-RPC command. -func NewGetCFilterHeaderCmd(hash string, extended bool) *GetCFilterHeaderCmd { +func NewGetCFilterHeaderCmd(hash string, filterType uint8) *GetCFilterHeaderCmd { return &GetCFilterHeaderCmd{ - Hash: hash, - Extended: extended, + Hash: hash, + FilterType: filterType, } } diff --git a/btcjson/chainsvrcmds_test.go b/btcjson/chainsvrcmds_test.go index 1b2c33e7..cb284a4a 100644 --- a/btcjson/chainsvrcmds_test.go +++ b/btcjson/chainsvrcmds_test.go @@ -320,27 +320,27 @@ func TestChainSvrCmds(t *testing.T) { { name: "getcfilter", newCmd: func() (interface{}, error) { - return btcjson.NewCmd("getcfilter", "123", false) + return btcjson.NewCmd("getcfilter", "123", 0) }, staticCmd: func() interface{} { - return btcjson.NewGetCFilterCmd("123", false) + return btcjson.NewGetCFilterCmd("123", 0) }, marshalled: `{"jsonrpc":"1.0","method":"getcfilter","params":["123",false],"id":1}`, unmarshalled: &btcjson.GetCFilterCmd{ - Hash: "123", + Hash: "123", }, }, { name: "getcfilterheader", newCmd: func() (interface{}, error) { - return btcjson.NewCmd("getcfilterheader", "123", false) + return btcjson.NewCmd("getcfilterheader", "123", 0) }, staticCmd: func() interface{} { - return btcjson.NewGetCFilterHeaderCmd("123", false) + return btcjson.NewGetCFilterHeaderCmd("123", 0) }, marshalled: `{"jsonrpc":"1.0","method":"getcfilterheader","params":["123",false],"id":1}`, unmarshalled: &btcjson.GetCFilterHeaderCmd{ - Hash: "123", + Hash: "123", }, }, { diff --git a/peer/peer_test.go b/peer/peer_test.go index acab18bb..701df744 100644 --- a/peer/peer_test.go +++ b/peer/peer_test.go @@ -536,7 +536,7 @@ func TestPeerListeners(t *testing.T) { }, { "OnGetCFilter", - wire.NewMsgGetCFilter(&chainhash.Hash{}, false), + wire.NewMsgGetCFilter(&chainhash.Hash{}, 0), }, { "OnGetCFHeaders", @@ -544,7 +544,7 @@ func TestPeerListeners(t *testing.T) { }, { "OnCFilter", - wire.NewMsgCFilter(&chainhash.Hash{}, true, + wire.NewMsgCFilter(&chainhash.Hash{}, 1, []byte("payload")), }, { diff --git a/rpcserver.go b/rpcserver.go index f6729d00..b10d5287 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -2163,7 +2163,7 @@ func handleGetCFilter(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) return nil, rpcDecodeHexError(c.Hash) } - filterBytes, err := s.cfg.CfIndex.FilterByBlockHash(hash, c.Extended) + filterBytes, err := s.cfg.CfIndex.FilterByBlockHash(hash, c.FilterType) if err != nil { rpcsLog.Debugf("Could not find committed filter for %v: %v", hash, err) @@ -2192,7 +2192,7 @@ func handleGetCFilterHeader(s *rpcServer, cmd interface{}, closeChan <-chan stru return nil, rpcDecodeHexError(c.Hash) } - headerBytes, err := s.cfg.CfIndex.FilterHeaderByBlockHash(hash, c.Extended) + headerBytes, err := s.cfg.CfIndex.FilterHeaderByBlockHash(hash, c.FilterType) if len(headerBytes) > 0 { rpcsLog.Debugf("Found header of committed filter for %v", hash) } else { diff --git a/server.go b/server.go index 0ef9c8ec..272904af 100644 --- a/server.go +++ b/server.go @@ -747,7 +747,7 @@ func (sp *serverPeer) OnGetCFilter(_ *peer.Peer, msg *wire.MsgGetCFilter) { } filterBytes, err := sp.server.cfIndex.FilterByBlockHash(&msg.BlockHash, - msg.Extended) + msg.FilterType) if len(filterBytes) > 0 { peerLog.Tracef("Obtained CF for %v", msg.BlockHash) @@ -756,7 +756,7 @@ func (sp *serverPeer) OnGetCFilter(_ *peer.Peer, msg *wire.MsgGetCFilter) { err) } - filterMsg := wire.NewMsgCFilter(&msg.BlockHash, msg.Extended, + filterMsg := wire.NewMsgCFilter(&msg.BlockHash, msg.FilterType, filterBytes) sp.QueueMessage(filterMsg, nil) } @@ -789,7 +789,7 @@ func (sp *serverPeer) OnGetCFHeaders(_ *peer.Peer, msg *wire.MsgGetCFHeaders) { // Fetch the raw committed filter header bytes from the // database. headerBytes, err := sp.server.cfIndex.FilterHeaderByBlockHash( - &msg.HashStop, msg.Extended) + &msg.HashStop, msg.FilterType) if (err != nil) || (len(headerBytes) == 0) { peerLog.Warnf("Could not obtain CF header for %v: %v", msg.HashStop, err) @@ -808,7 +808,7 @@ func (sp *serverPeer) OnGetCFHeaders(_ *peer.Peer, msg *wire.MsgGetCFHeaders) { headersMsg := wire.NewMsgCFHeaders() headersMsg.AddCFHeader(&header) headersMsg.StopHash = msg.HashStop - headersMsg.Extended = msg.Extended + headersMsg.FilterType = msg.FilterType sp.QueueMessage(headersMsg, nil) return } @@ -849,7 +849,7 @@ func (sp *serverPeer) OnGetCFHeaders(_ *peer.Peer, msg *wire.MsgGetCFHeaders) { // Fetch the raw committed filter header bytes from the // database. headerBytes, err := sp.server.cfIndex.FilterHeaderByBlockHash( - &hashList[i], msg.Extended) + &hashList[i], msg.FilterType) if (err != nil) || (len(headerBytes) == 0) { peerLog.Warnf("Could not obtain CF header for %v: %v", hashList[i], err) @@ -868,7 +868,7 @@ func (sp *serverPeer) OnGetCFHeaders(_ *peer.Peer, msg *wire.MsgGetCFHeaders) { headersMsg.AddCFHeader(&header) } - headersMsg.Extended = msg.Extended + headersMsg.FilterType = msg.FilterType headersMsg.StopHash = hashList[len(hashList)-1] sp.QueueMessage(headersMsg, nil) } diff --git a/wire/message_test.go b/wire/message_test.go index 88533f4d..6bf7fd2b 100644 --- a/wire/message_test.go +++ b/wire/message_test.go @@ -69,9 +69,9 @@ func TestMessage(t *testing.T) { bh := NewBlockHeader(1, &chainhash.Hash{}, &chainhash.Hash{}, 0, 0) msgMerkleBlock := NewMsgMerkleBlock(bh) msgReject := NewMsgReject("block", RejectDuplicate, "duplicate block") - msgGetCFilter := NewMsgGetCFilter(&chainhash.Hash{}, false) + msgGetCFilter := NewMsgGetCFilter(&chainhash.Hash{}, 0) msgGetCFHeaders := NewMsgGetCFHeaders() - msgCFilter := NewMsgCFilter(&chainhash.Hash{}, true, []byte("payload")) + msgCFilter := NewMsgCFilter(&chainhash.Hash{}, 1, []byte("payload")) msgCFHeaders := NewMsgCFHeaders() tests := []struct { diff --git a/wire/msgcfheaders.go b/wire/msgcfheaders.go index 43676bba..cb5ca76e 100644 --- a/wire/msgcfheaders.go +++ b/wire/msgcfheaders.go @@ -28,7 +28,7 @@ const ( // MsgGetCFHeaders for details on requesting the headers. type MsgCFHeaders struct { StopHash chainhash.Hash - Extended bool + FilterType uint8 HeaderHashes []*chainhash.Hash } @@ -53,8 +53,8 @@ func (msg *MsgCFHeaders) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) return err } - // Read extended flag - err = readElement(r, &msg.Extended) + // Read filter type + err = readElement(r, &msg.FilterType) if err != nil { return err } @@ -97,8 +97,8 @@ func (msg *MsgCFHeaders) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) return err } - // Write extended flag - err = writeElement(w, msg.Extended) + // Write filter type + err = writeElement(w, msg.FilterType) if err != nil { return err } diff --git a/wire/msgcfilter.go b/wire/msgcfilter.go index d48065eb..048d4b98 100644 --- a/wire/msgcfilter.go +++ b/wire/msgcfilter.go @@ -17,9 +17,9 @@ const ( ) type MsgCFilter struct { - BlockHash chainhash.Hash - Extended bool - Data []byte + BlockHash chainhash.Hash + FilterType uint8 + Data []byte } // BtcDecode decodes r using the bitcoin protocol encoding into the receiver. @@ -31,8 +31,8 @@ func (msg *MsgCFilter) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) er if err != nil { return err } - // Read extended flag - err = readElement(r, &msg.Extended) + // Read filter type + err = readElement(r, &msg.FilterType) if err != nil { return err } @@ -57,7 +57,7 @@ func (msg *MsgCFilter) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) er return err } - err = writeElement(w, msg.Extended) + err = writeElement(w, msg.FilterType) if err != nil { return err } @@ -96,11 +96,11 @@ func (msg *MsgCFilter) MaxPayloadLength(pver uint32) uint32 { // NewMsgCFilter returns a new bitcoin cfilter message that conforms to the // Message interface. See MsgCFilter for details. -func NewMsgCFilter(blockHash *chainhash.Hash, extended bool, +func NewMsgCFilter(blockHash *chainhash.Hash, filterType uint8, data []byte) *MsgCFilter { return &MsgCFilter{ - BlockHash: *blockHash, - Extended: extended, - Data: data, + BlockHash: *blockHash, + FilterType: filterType, + Data: data, } } diff --git a/wire/msggetcfheaders.go b/wire/msggetcfheaders.go index 97df30d7..e8b7f30c 100644 --- a/wire/msggetcfheaders.go +++ b/wire/msggetcfheaders.go @@ -12,13 +12,13 @@ import ( ) // MsgGetCFHeaders is a message similar to MsgGetHeaders, but for committed -// filter headers. It allows to set the Extended field to get headers in the -// chain of basic (false) or extended (true) headers. +// filter headers. It allows to set the FilterType field to get headers in the +// chain of basic (0x00) or extended (0x01) headers. type MsgGetCFHeaders struct { ProtocolVersion uint32 BlockLocatorHashes []*chainhash.Hash HashStop chainhash.Hash - Extended bool + FilterType uint8 } // AddBlockLocatorHash adds a new block locator hash to the message. @@ -70,7 +70,7 @@ func (msg *MsgGetCFHeaders) BtcDecode(r io.Reader, pver uint32, _ MessageEncodin return err } - return readElement(r, &msg.Extended) + return readElement(r, &msg.FilterType) } // BtcEncode encodes the receiver to w using the bitcoin protocol encoding. @@ -106,7 +106,7 @@ func (msg *MsgGetCFHeaders) BtcEncode(w io.Writer, pver uint32, _ MessageEncodin return err } - return writeElement(w, msg.Extended) + return writeElement(w, msg.FilterType) } // Command returns the protocol command string for the message. This is part @@ -119,7 +119,7 @@ func (msg *MsgGetCFHeaders) Command() string { // receiver. This is part of the Message interface implementation. func (msg *MsgGetCFHeaders) MaxPayloadLength(pver uint32) uint32 { // Version 4 bytes + num block locator hashes (varInt) + max allowed - // block locators + hash stop + Extended flag 1 byte. + // block locators + hash stop + filter type 1 byte. return 4 + MaxVarIntPayload + (MaxBlockLocatorsPerMsg * chainhash.HashSize) + chainhash.HashSize + 1 } diff --git a/wire/msggetcfilter.go b/wire/msggetcfilter.go index 89dd5100..85c351df 100644 --- a/wire/msggetcfilter.go +++ b/wire/msggetcfilter.go @@ -11,8 +11,8 @@ import ( ) type MsgGetCFilter struct { - BlockHash chainhash.Hash - Extended bool + BlockHash chainhash.Hash + FilterType uint8 } func (msg *MsgGetCFilter) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) error { @@ -20,7 +20,7 @@ func (msg *MsgGetCFilter) BtcDecode(r io.Reader, pver uint32, _ MessageEncoding) if err != nil { return err } - return readElement(r, &msg.Extended) + return readElement(r, &msg.FilterType) } // BtcEncode encodes the receiver to w using the bitcoin protocol encoding. @@ -30,7 +30,7 @@ func (msg *MsgGetCFilter) BtcEncode(w io.Writer, pver uint32, _ MessageEncoding) if err != nil { return err } - return writeElement(w, msg.Extended) + return writeElement(w, msg.FilterType) } // Command returns the protocol command string for the message. This is part @@ -42,16 +42,16 @@ func (msg *MsgGetCFilter) Command() string { // MaxPayloadLength returns the maximum length the payload can be for the // receiver. This is part of the Message interface implementation. func (msg *MsgGetCFilter) MaxPayloadLength(pver uint32) uint32 { - // Block hash + Extended flag. + // Block hash + filter type. return chainhash.HashSize + 1 } // NewMsgGetCFilter returns a new bitcoin getcfilter message that conforms to // the Message interface using the passed parameters and defaults for the // remaining fields. -func NewMsgGetCFilter(blockHash *chainhash.Hash, extended bool) *MsgGetCFilter { +func NewMsgGetCFilter(blockHash *chainhash.Hash, filterType uint8) *MsgGetCFilter { return &MsgGetCFilter{ - BlockHash: *blockHash, - Extended: extended, + BlockHash: *blockHash, + FilterType: filterType, } }