Skip to content

Commit

Permalink
blockchain: Optimize exported header access.
Browse files Browse the repository at this point in the history
This optimizes the FetchHeader function to make use of the fact that all
block nodes are now in memory and therefore it is no longer necessary to
consult the database for them.

It also renames the function to HeaderByHash so it is consistent with
other similar functions such as HeaderByHeight, BlockByHash, and
BlockByHeight and updates all callers in the repo accordingly.

This speeds up fetching all of the headers in the chain by roughly 3x to
4x for a chain height of 246,000 headers.  Longer chains will benefit
more.

For example, here is some timing information before and after this
commit plus the full block index in memory commit for 246,000 headers:

7200 RPM HDD:
-------------
Previous fetch time: ~15.76s
New fetch time: ~4.17s

SSD:
----
Previous fetch time: ~12.63s
New fetch time: ~4.17s
  • Loading branch information
davecgh committed Jun 12, 2018
1 parent 5386a63 commit a235b83
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 24 deletions.
6 changes: 3 additions & 3 deletions blockchain/blockindex_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,12 @@ func TestBlockNodeHeader(t *testing.T) {
// Ensure fetching the header from the chain produces the same header used
// to create the node.
testHeaderHash := testHeader.BlockHash()
gotHeader, err := bc.FetchHeader(&testHeaderHash)
gotHeader, err := bc.HeaderByHash(&testHeaderHash)
if err != nil {
t.Fatalf("FetchHeader: unexpected error: %v", err)
t.Fatalf("HeaderByHash: unexpected error: %v", err)
}
if !reflect.DeepEqual(gotHeader, testHeader) {
t.Fatalf("FetchHeader: mismatched headers: got %+v, want %+v",
t.Fatalf("HeaderByHash: mismatched headers: got %+v, want %+v",
gotHeader, testHeader)
}
}
Expand Down
25 changes: 8 additions & 17 deletions blockchain/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -1681,27 +1681,18 @@ func (b *BlockChain) MaxBlockSize() (int64, error) {
return maxSize, err
}

// FetchHeader returns the block header identified by the given hash or an error
// if it doesn't exist.
// HeaderByHash returns the block header identified by the given hash or an
// error if it doesn't exist. Note that this will return headers from both the
// main chain and any side chains.
//
// This function is safe for concurrent access.
func (b *BlockChain) FetchHeader(hash *chainhash.Hash) (wire.BlockHeader, error) {
// Reconstruct the header from the block index if possible.
if node := b.index.LookupNode(hash); node != nil {
return node.Header(), nil
func (b *BlockChain) HeaderByHash(hash *chainhash.Hash) (wire.BlockHeader, error) {
node := b.index.LookupNode(hash)
if node == nil {
return wire.BlockHeader{}, fmt.Errorf("block %s is not known", hash)
}

// Fall back to loading it from the database.
var header *wire.BlockHeader
err := b.db.View(func(dbTx database.Tx) error {
var err error
header, err = dbFetchHeaderByHash(dbTx, hash)
return err
})
if err != nil {
return wire.BlockHeader{}, err
}
return *header, nil
return node.Header(), nil
}

// locateInventory returns the node of the block after the first known block in
Expand Down
8 changes: 4 additions & 4 deletions rpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -2069,7 +2069,7 @@ func handleGetBlockHeader(s *rpcServer, cmd interface{}, closeChan <-chan struct
if err != nil {
return nil, rpcDecodeHexError(c.Hash)
}
blockHeader, err := s.chain.FetchHeader(hash)
blockHeader, err := s.chain.HeaderByHash(hash)
if err != nil {
return nil, &dcrjson.RPCError{
Code: dcrjson.ErrRPCBlockNotFound,
Expand Down Expand Up @@ -3349,7 +3349,7 @@ func handleGetNetworkHashPS(s *rpcServer, cmd interface{}, closeChan <-chan stru
}

// Fetch the header from chain.
header, err := s.chain.FetchHeader(hash)
header, err := s.chain.HeaderByHash(hash)
if err != nil {
context := "Failed to fetch block header"
return nil, rpcInternalError(err.Error(), context)
Expand Down Expand Up @@ -3568,7 +3568,7 @@ func handleGetRawTransaction(s *rpcServer, cmd interface{}, closeChan <-chan str
)
if blkHash != nil {
// Fetch the header from chain.
header, err := s.chain.FetchHeader(blkHash)
header, err := s.chain.HeaderByHash(blkHash)
if err != nil {
context := "Failed to fetch block header"
return nil, rpcInternalError(err.Error(), context)
Expand Down Expand Up @@ -4960,7 +4960,7 @@ func handleSearchRawTransactions(s *rpcServer, cmd interface{}, closeChan <-chan
var blkHeight int64
if blkHash := rtx.blkHash; blkHash != nil {
// Fetch the header from chain.
header, err := s.chain.FetchHeader(blkHash)
header, err := s.chain.HeaderByHash(blkHash)
if err != nil {
return nil, &dcrjson.RPCError{
Code: dcrjson.ErrRPCBlockNotFound,
Expand Down

0 comments on commit a235b83

Please sign in to comment.