mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-17 01:13:45 +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
|
return
|
||||||
}
|
}
|
||||||
// Short circuit if the owner header is unknown
|
// 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])
|
errs[index] = fmt.Errorf("containing header #%d [%x…] unknown", block.Number(), block.Hash().Bytes()[:4])
|
||||||
atomic.AddInt32(&failed, 1)
|
atomic.AddInt32(&failed, 1)
|
||||||
return
|
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
|
// HasHeader checks if a block header is present in the database or not, caching
|
||||||
// it if present.
|
// it if present.
|
||||||
func (bc *BlockChain) HasHeader(hash common.Hash) bool {
|
func (bc *BlockChain) HasHeader(hash common.Hash, number uint64) bool {
|
||||||
return bc.hc.HasHeader(hash)
|
return bc.hc.HasHeader(hash, number)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBlockHashesFromHash retrieves a number of block hashes starting at a given
|
// 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
|
// GetHeaderRLP retrieves a block header in its raw RLP database encoding, or nil
|
||||||
// if the header's not found.
|
// if the header's not found.
|
||||||
func GetHeaderRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue {
|
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
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -174,6 +174,10 @@ func GetBodyRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue
|
||||||
return data
|
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
|
// GetBody retrieves the block body (transactons, uncles) corresponding to the
|
||||||
// hash, nil if none found.
|
// hash, nil if none found.
|
||||||
func GetBody(db DatabaseReader, hash common.Hash, number uint64) *types.Body {
|
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")
|
return i, errors.New("aborted")
|
||||||
}
|
}
|
||||||
// If the header's already known, skip it, otherwise store
|
// 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++
|
stats.ignored++
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -361,10 +361,13 @@ func (hc *HeaderChain) GetHeaderByHash(hash common.Hash) *types.Header {
|
||||||
return hc.GetHeader(hash, hc.GetBlockNumber(hash))
|
return hc.GetHeader(hash, hc.GetBlockNumber(hash))
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasHeader checks if a block header is present in the database or not, caching
|
// HasHeader checks if a block header is present in the database or not.
|
||||||
// it if present.
|
func (hc *HeaderChain) HasHeader(hash common.Hash, number uint64) bool {
|
||||||
func (hc *HeaderChain) HasHeader(hash common.Hash) bool {
|
if _, ok := hc.headerCache.Get(hash); ok {
|
||||||
return hc.GetHeaderByHash(hash) != nil
|
return true
|
||||||
|
}
|
||||||
|
ok, _ := hc.chainDb.Has(headerKey(hash, number))
|
||||||
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetHeaderByNumber retrieves a block header from the database by number,
|
// 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.
|
// LightChain encapsulates functions required to synchronise a light chain.
|
||||||
type LightChain interface {
|
type LightChain interface {
|
||||||
// HasHeader verifies a header's presence in the local chain.
|
// 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 retrieves a header from the local chain.
|
||||||
GetHeaderByHash(common.Hash) *types.Header
|
GetHeaderByHash(common.Hash) *types.Header
|
||||||
|
|
@ -666,7 +666,7 @@ func (d *Downloader) findAncestor(p *peerConnection, height uint64) (uint64, err
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Otherwise check if we already know the header or not
|
// 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()
|
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
|
// 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
|
arrived = true
|
||||||
|
|
||||||
// Modify the search interval based on the response
|
// 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
|
end = check
|
||||||
break
|
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
|
// Collect the yet unknown headers to mark them as uncertain
|
||||||
unknown := make([]*types.Header, 0, len(headers))
|
unknown := make([]*types.Header, 0, len(headers))
|
||||||
for _, header := range chunk {
|
for _, header := range chunk {
|
||||||
if !d.lightchain.HasHeader(header.Hash()) {
|
if !d.lightchain.HasHeader(header.Hash(), header.Number.Uint64()) {
|
||||||
unknown = append(unknown, header)
|
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.
|
// 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
|
return dl.GetHeaderByHash(hash) != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ func errResp(code errCode, format string, v ...interface{}) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
type BlockChain interface {
|
type BlockChain interface {
|
||||||
HasHeader(hash common.Hash) bool
|
HasHeader(hash common.Hash, number uint64) bool
|
||||||
GetHeader(hash common.Hash, number uint64) *types.Header
|
GetHeader(hash common.Hash, number uint64) *types.Header
|
||||||
GetHeaderByHash(hash common.Hash) *types.Header
|
GetHeaderByHash(hash common.Hash) *types.Header
|
||||||
CurrentHeader() *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
|
// HasHeader checks if a block header is present in the database or not, caching
|
||||||
// it if present.
|
// it if present.
|
||||||
func (bc *LightChain) HasHeader(hash common.Hash) bool {
|
func (bc *LightChain) HasHeader(hash common.Hash, number uint64) bool {
|
||||||
return bc.hc.HasHeader(hash)
|
return bc.hc.HasHeader(hash, number)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBlockHashesFromHash retrieves a number of block hashes starting at a given
|
// GetBlockHashesFromHash retrieves a number of block hashes starting at a given
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue