From d6c2492c7f5a6df1f5bc3ed0b2058fbc7bd6b37a Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 18 Jan 2014 20:59:53 -0600 Subject: [PATCH] Add FetchBlockHeightBySha/FetchBlockHeaderBySha. This commit introduces two new functions to the btcdb.Db interface named FetchBlockHeightBySha and FetchBlockHeaderBySha. The FetchBlockHeightBySha function is useful since previously it was only possible to get the height of block by fetching the entire block with FetchBlockBySha and pulling the height out of the returned btcutil.Block. The FetchBlockHeaderBySha function will ultimately make it much more efficient to fetch block headers. Currently, due to the database design in the ldb backend, the entire block has to be loaded anyways, so the only current benefit is to avoid the deserialize on all of the transactions. However, ultimately btcdb will gain a more efficient backend which can also avoid reading all of the extra transaction data altogether. --- db.go | 7 +++++++ ldb/block.go | 32 ++++++++++++++++++++++++++++++++ memdb/memdb.go | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+) diff --git a/db.go b/db.go index a1144ec0..68853f68 100644 --- a/db.go +++ b/db.go @@ -59,6 +59,13 @@ type Db interface { // cache the underlying data if desired. FetchBlockBySha(sha *btcwire.ShaHash) (blk *btcutil.Block, err error) + // FetchBlockHeightBySha returns the block height for the given hash. + FetchBlockHeightBySha(sha *btcwire.ShaHash) (height int64, err error) + + // FetchBlockHeaderBySha returns a btcwire.BlockHeader for the given + // sha. The implementation may cache the underlying data if desired. + FetchBlockHeaderBySha(sha *btcwire.ShaHash) (bh *btcwire.BlockHeader, err error) + // FetchBlockShaByHeight returns a block hash based on its height in the // block chain. FetchBlockShaByHeight(height int64) (sha *btcwire.ShaHash, err error) diff --git a/ldb/block.go b/ldb/block.go index bcfa0696..64f2053c 100644 --- a/ldb/block.go +++ b/ldb/block.go @@ -38,6 +38,38 @@ func (db *LevelDb) fetchBlockBySha(sha *btcwire.ShaHash) (blk *btcutil.Block, er return } +// FetchBlockHeightBySha returns the block height for the given hash. This is +// part of the btcdb.Db interface implementation. +func (db *LevelDb) FetchBlockHeightBySha(sha *btcwire.ShaHash) (int64, error) { + db.dbLock.Lock() + defer db.dbLock.Unlock() + + return db.getBlkLoc(sha) +} + +// FetchBlockHeaderBySha - return a btcwire ShaHash +func (db *LevelDb) FetchBlockHeaderBySha(sha *btcwire.ShaHash) (bh *btcwire.BlockHeader, err error) { + db.dbLock.Lock() + defer db.dbLock.Unlock() + + // Read the raw block from the database. + buf, _, err := db.fetchSha(sha) + if err != nil { + return nil, err + } + + // Only deserialize the header portion and ensure the transaction count + // is zero since this is a standalone header. + var blockHeader btcwire.BlockHeader + err = blockHeader.Deserialize(bytes.NewBuffer(buf)) + if err != nil { + return nil, err + } + bh = &blockHeader + + return bh, err +} + func (db *LevelDb) getBlkLoc(sha *btcwire.ShaHash) (int64, error) { var blkHeight int64 diff --git a/memdb/memdb.go b/memdb/memdb.go index 4b805627..e9bd795a 100644 --- a/memdb/memdb.go +++ b/memdb/memdb.go @@ -230,6 +230,44 @@ func (db *MemDb) FetchBlockBySha(sha *btcwire.ShaHash) (*btcutil.Block, error) { return nil, fmt.Errorf("block %v is not in database", sha) } +// FetchBlockHeightBySha returns the block height for the given hash. This is +// part of the btcdb.Db interface implementation. +func (db *MemDb) FetchBlockHeightBySha(sha *btcwire.ShaHash) (int64, error) { + db.Lock() + defer db.Unlock() + + if db.closed { + return 0, ErrDbClosed + } + + if blockHeight, exists := db.blocksBySha[*sha]; exists { + return blockHeight, nil + } + + return 0, fmt.Errorf("block %v is not in database", sha) +} + +// FetchBlockHeaderBySha returns a btcwire.BlockHeader for the given sha. The +// implementation may cache the underlying data if desired. This is part of the +// btcdb.Db interface implementation. +// +// This implementation does not use any additional cache since the entire +// database is already in memory. +func (db *MemDb) FetchBlockHeaderBySha(sha *btcwire.ShaHash) (*btcwire.BlockHeader, error) { + db.Lock() + defer db.Unlock() + + if db.closed { + return nil, ErrDbClosed + } + + if blockHeight, exists := db.blocksBySha[*sha]; exists { + return &db.blocks[int(blockHeight)].Header, nil + } + + return nil, fmt.Errorf("block header %v is not in database", sha) +} + // FetchBlockShaByHeight returns a block hash based on its height in the block // chain. This is part of the btcdb.Db interface implementation. func (db *MemDb) FetchBlockShaByHeight(height int64) (*btcwire.ShaHash, error) {