mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-16 17:03:46 +00:00
core: optimize HasHeader check
This avoids one random database read get the block number. For many uses of HasHeader, the expectation is that it's actually there. Using Has avoids a load + decode of the value.
This commit is contained in:
parent
cd0a1e99f5
commit
88aeee4437
7 changed files with 24 additions and 17 deletions
|
|
@ -734,7 +734,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
|
|||
return
|
||||
}
|
||||
// Short circuit if the owner header is unknown
|
||||
if !bc.HasHeader(block.Hash()) {
|
||||
if !bc.HasHeader(block.Hash(), block.NumberU64()) {
|
||||
errs[index] = fmt.Errorf("containing header #%d [%x…] unknown", block.Number(), block.Hash().Bytes()[:4])
|
||||
atomic.AddInt32(&failed, 1)
|
||||
return
|
||||
|
|
@ -1357,8 +1357,8 @@ func (bc *BlockChain) GetHeaderByHash(hash common.Hash) *types.Header {
|
|||
|
||||
// HasHeader checks if a block header is present in the database or not, caching
|
||||
// it if present.
|
||||
func (bc *BlockChain) HasHeader(hash common.Hash) bool {
|
||||
return bc.hc.HasHeader(hash)
|
||||
func (bc *BlockChain) HasHeader(hash common.Hash, number uint64) bool {
|
||||
return bc.hc.HasHeader(hash, number)
|
||||
}
|
||||
|
||||
// GetBlockHashesFromHash retrieves a number of block hashes starting at a given
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ func GetHeadFastBlockHash(db DatabaseReader) common.Hash {
|
|||
// GetHeaderRLP retrieves a block header in its raw RLP database encoding, or nil
|
||||
// if the header's not found.
|
||||
func GetHeaderRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue {
|
||||
data, _ := db.Get(append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...))
|
||||
data, _ := db.Get(headerKey(hash, number))
|
||||
return data
|
||||
}
|
||||
|
||||
|
|
@ -174,6 +174,10 @@ func GetBodyRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue
|
|||
return data
|
||||
}
|
||||
|
||||
func headerKey(hash common.Hash, number uint64) []byte {
|
||||
return append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
|
||||
}
|
||||
|
||||
// GetBody retrieves the block body (transactons, uncles) corresponding to the
|
||||
// hash, nil if none found.
|
||||
func GetBody(db DatabaseReader, hash common.Hash, number uint64) *types.Body {
|
||||
|
|
|
|||
|
|
@ -267,7 +267,7 @@ func (hc *HeaderChain) InsertHeaderChain(chain []*types.Header, writeHeader WhCa
|
|||
return i, errors.New("aborted")
|
||||
}
|
||||
// If the header's already known, skip it, otherwise store
|
||||
if hc.GetHeader(header.Hash(), header.Number.Uint64()) != nil {
|
||||
if hc.HasHeader(header.Hash(), header.Number.Uint64()) {
|
||||
stats.ignored++
|
||||
continue
|
||||
}
|
||||
|
|
@ -361,10 +361,13 @@ func (hc *HeaderChain) GetHeaderByHash(hash common.Hash) *types.Header {
|
|||
return hc.GetHeader(hash, hc.GetBlockNumber(hash))
|
||||
}
|
||||
|
||||
// HasHeader checks if a block header is present in the database or not, caching
|
||||
// it if present.
|
||||
func (hc *HeaderChain) HasHeader(hash common.Hash) bool {
|
||||
return hc.GetHeaderByHash(hash) != nil
|
||||
// HasHeader checks if a block header is present in the database or not.
|
||||
func (hc *HeaderChain) HasHeader(hash common.Hash, number uint64) bool {
|
||||
if _, ok := hc.headerCache.Get(hash); ok {
|
||||
return true
|
||||
}
|
||||
ok, _ := hc.chainDb.Has(headerKey(hash, number))
|
||||
return ok
|
||||
}
|
||||
|
||||
// GetHeaderByNumber retrieves a block header from the database by number,
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ type Downloader struct {
|
|||
// LightChain encapsulates functions required to synchronise a light chain.
|
||||
type LightChain interface {
|
||||
// HasHeader verifies a header's presence in the local chain.
|
||||
HasHeader(common.Hash) bool
|
||||
HasHeader(h common.Hash, number uint64) bool
|
||||
|
||||
// GetHeaderByHash retrieves a header from the local chain.
|
||||
GetHeaderByHash(common.Hash) *types.Header
|
||||
|
|
@ -666,7 +666,7 @@ func (d *Downloader) findAncestor(p *peerConnection, height uint64) (uint64, err
|
|||
continue
|
||||
}
|
||||
// Otherwise check if we already know the header or not
|
||||
if (d.mode == FullSync && d.blockchain.HasBlockAndState(headers[i].Hash())) || (d.mode != FullSync && d.lightchain.HasHeader(headers[i].Hash())) {
|
||||
if (d.mode == FullSync && d.blockchain.HasBlockAndState(headers[i].Hash())) || (d.mode != FullSync && d.lightchain.HasHeader(headers[i].Hash(), headers[i].Number.Uint64())) {
|
||||
number, hash = headers[i].Number.Uint64(), headers[i].Hash()
|
||||
|
||||
// If every header is known, even future ones, the peer straight out lied about its head
|
||||
|
|
@ -731,7 +731,7 @@ func (d *Downloader) findAncestor(p *peerConnection, height uint64) (uint64, err
|
|||
arrived = true
|
||||
|
||||
// Modify the search interval based on the response
|
||||
if (d.mode == FullSync && !d.blockchain.HasBlockAndState(headers[0].Hash())) || (d.mode != FullSync && !d.lightchain.HasHeader(headers[0].Hash())) {
|
||||
if (d.mode == FullSync && !d.blockchain.HasBlockAndState(headers[0].Hash())) || (d.mode != FullSync && !d.lightchain.HasHeader(headers[0].Hash(), headers[0].Number.Uint64())) {
|
||||
end = check
|
||||
break
|
||||
}
|
||||
|
|
@ -1256,7 +1256,7 @@ func (d *Downloader) processHeaders(origin uint64, td *big.Int) error {
|
|||
// Collect the yet unknown headers to mark them as uncertain
|
||||
unknown := make([]*types.Header, 0, len(headers))
|
||||
for _, header := range chunk {
|
||||
if !d.lightchain.HasHeader(header.Hash()) {
|
||||
if !d.lightchain.HasHeader(header.Hash(), header.Number.Uint64()) {
|
||||
unknown = append(unknown, header)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ func (dl *downloadTester) sync(id string, td *big.Int, mode SyncMode) error {
|
|||
}
|
||||
|
||||
// HasHeader checks if a header is present in the testers canonical chain.
|
||||
func (dl *downloadTester) HasHeader(hash common.Hash) bool {
|
||||
func (dl *downloadTester) HasHeader(hash common.Hash, number uint64) bool {
|
||||
return dl.GetHeaderByHash(hash) != nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ func errResp(code errCode, format string, v ...interface{}) error {
|
|||
}
|
||||
|
||||
type BlockChain interface {
|
||||
HasHeader(hash common.Hash) bool
|
||||
HasHeader(hash common.Hash, number uint64) bool
|
||||
GetHeader(hash common.Hash, number uint64) *types.Header
|
||||
GetHeaderByHash(hash common.Hash) *types.Header
|
||||
CurrentHeader() *types.Header
|
||||
|
|
|
|||
|
|
@ -418,8 +418,8 @@ func (self *LightChain) GetHeaderByHash(hash common.Hash) *types.Header {
|
|||
|
||||
// HasHeader checks if a block header is present in the database or not, caching
|
||||
// it if present.
|
||||
func (bc *LightChain) HasHeader(hash common.Hash) bool {
|
||||
return bc.hc.HasHeader(hash)
|
||||
func (bc *LightChain) HasHeader(hash common.Hash, number uint64) bool {
|
||||
return bc.hc.HasHeader(hash, number)
|
||||
}
|
||||
|
||||
// GetBlockHashesFromHash retrieves a number of block hashes starting at a given
|
||||
|
|
|
|||
Loading…
Reference in a new issue