core: optimize HasBlock check

This avoids a random database read to get the number.
This commit is contained in:
Felix Lange 2017-07-15 01:24:04 +02:00
parent 9956e2a2ca
commit d4486f0cb0
6 changed files with 19 additions and 11 deletions

View file

@ -164,7 +164,7 @@ func ImportChain(chain *core.BlockChain, fn string) error {
func hasAllBlocks(chain *core.BlockChain, bs []*types.Block) bool { func hasAllBlocks(chain *core.BlockChain, bs []*types.Block) bool {
for _, b := range bs { for _, b := range bs {
if !chain.HasBlock(b.Hash()) { if !chain.HasBlock(b.Hash(), b.NumberU64()) {
return false return false
} }
} }

View file

@ -516,8 +516,12 @@ func (bc *BlockChain) GetBodyRLP(hash common.Hash) rlp.RawValue {
// HasBlock checks if a block is fully present in the database or not, caching // HasBlock checks if a block is fully present in the database or not, caching
// it if present. // it if present.
func (bc *BlockChain) HasBlock(hash common.Hash) bool { func (bc *BlockChain) HasBlock(hash common.Hash, number uint64) bool {
return bc.GetBlockByHash(hash) != nil if bc.blockCache.Contains(hash) {
return true
}
ok, _ := bc.chainDb.Has(blockBodyKey(hash, number))
return ok
} }
// HasBlockAndState checks if a block and associated state trie is fully present // HasBlockAndState checks if a block and associated state trie is fully present
@ -723,7 +727,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
return i, fmt.Errorf("containing header #%d [%x…] unknown", block.Number(), block.Hash().Bytes()[:4]) return i, fmt.Errorf("containing header #%d [%x…] unknown", block.Number(), block.Hash().Bytes()[:4])
} }
// Skip if the entire data is already known // Skip if the entire data is already known
if bc.HasBlock(block.Hash()) { if bc.HasBlock(block.Hash(), block.NumberU64()) {
stats.ignored++ stats.ignored++
continue continue
} }
@ -793,7 +797,7 @@ func (bc *BlockChain) WriteBlock(block *types.Block) (status WriteStatus, err er
bc.mu.Lock() bc.mu.Lock()
defer bc.mu.Unlock() defer bc.mu.Unlock()
if bc.HasBlock(block.Hash()) { if bc.HasBlock(block.Hash(), block.NumberU64()) {
log.Trace("Block existed", "hash", block.Hash()) log.Trace("Block existed", "hash", block.Hash())
return return
} }

View file

@ -170,7 +170,7 @@ func GetHeader(db DatabaseReader, hash common.Hash, number uint64) *types.Header
// GetBodyRLP retrieves the block body (transactions and uncles) in RLP encoding. // GetBodyRLP retrieves the block body (transactions and uncles) in RLP encoding.
func GetBodyRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue { func GetBodyRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue {
data, _ := db.Get(append(append(bodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...)) data, _ := db.Get(blockBodyKey(hash, number))
return data return data
} }
@ -178,6 +178,10 @@ func headerKey(hash common.Hash, number uint64) []byte {
return append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...) return append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
} }
func blockBodyKey(hash common.Hash, number uint64) []byte {
return append(append(bodyPrefix, 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 {

View file

@ -241,7 +241,7 @@ func (api *PrivateAdminAPI) ExportChain(file string) (bool, error) {
func hasAllBlocks(chain *core.BlockChain, bs []*types.Block) bool { func hasAllBlocks(chain *core.BlockChain, bs []*types.Block) bool {
for _, b := range bs { for _, b := range bs {
if !chain.HasBlock(b.Hash()) { if !chain.HasBlock(b.Hash(), b.NumberU64()) {
return false return false
} }
} }

View file

@ -609,7 +609,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
// Schedule all the unknown hashes for retrieval // Schedule all the unknown hashes for retrieval
unknown := make(newBlockHashesData, 0, len(announces)) unknown := make(newBlockHashesData, 0, len(announces))
for _, block := range announces { for _, block := range announces {
if !pm.blockchain.HasBlock(block.Hash) { if !pm.blockchain.HasBlock(block.Hash, block.Number) {
unknown = append(unknown, block) unknown = append(unknown, block)
} }
} }
@ -699,7 +699,7 @@ func (pm *ProtocolManager) BroadcastBlock(block *types.Block, propagate bool) {
return return
} }
// Otherwise if the block is indeed in out own chain, announce it // Otherwise if the block is indeed in out own chain, announce it
if pm.blockchain.HasBlock(hash) { if pm.blockchain.HasBlock(hash, block.NumberU64()) {
for _, peer := range peers { for _, peer := range peers {
peer.SendNewBlockHashes([]common.Hash{hash}, []uint64{block.NumberU64()}) peer.SendNewBlockHashes([]common.Hash{hash}, []uint64{block.NumberU64()})
} }

View file

@ -252,8 +252,8 @@ func (self *LightChain) GetBodyRLP(ctx context.Context, hash common.Hash) (rlp.R
// HasBlock checks if a block is fully present in the database or not, caching // HasBlock checks if a block is fully present in the database or not, caching
// it if present. // it if present.
func (bc *LightChain) HasBlock(hash common.Hash) bool { func (bc *LightChain) HasBlock(hash common.Hash, number uint64) bool {
blk, _ := bc.GetBlockByHash(NoOdr, hash) blk, _ := bc.GetBlock(NoOdr, hash, number)
return blk != nil return blk != nil
} }