core/evm: less iteration in blockhash

This commit is contained in:
Martin Holst Swende 2019-03-15 15:56:37 +01:00
parent 4df46d86d6
commit 8d05c598fd
No known key found for this signature in database
GPG key ID: 683B438C05A5DDF0
3 changed files with 25 additions and 23 deletions

View file

@ -60,24 +60,32 @@ func NewEVMContext(msg Message, header *types.Header, chain ChainContext, author
// GetHashFn returns a GetHashFunc which retrieves header hashes by number // GetHashFn returns a GetHashFunc which retrieves header hashes by number
func GetHashFn(ref *types.Header, chain ChainContext) func(n uint64) common.Hash { func GetHashFn(ref *types.Header, chain ChainContext) func(n uint64) common.Hash {
var cache map[uint64]common.Hash // Cache will initially contain [refHash.parent],
// Then fill up with [refHash.p, refHash.pp, refHash.ppp, ...]
var cache []common.Hash
return func(n uint64) common.Hash { return func(n uint64) common.Hash {
// If there's no hash cache yet, make one // If there's no hash cache yet, make one
if cache == nil { if len(cache) == 0 {
cache = map[uint64]common.Hash{ cache = append(cache, ref.ParentHash)
ref.Number.Uint64() - 1: ref.ParentHash, }
if idx := ref.Number.Uint64() - n - 1; idx < uint64(len(cache)) {
return cache[idx]
}
// No luck in the cache, but we can start iterating from the last element we already know
lastKnownHash := cache[len(cache)-1]
lastKnownNumber := ref.Number.Uint64() - uint64(len(cache))
for {
header := chain.GetHeader(lastKnownHash, lastKnownNumber)
if header == nil {
break
} }
} cache = append(cache, header.ParentHash)
// Try to fulfill the request from the cache lastKnownHash = header.ParentHash
if hash, ok := cache[n]; ok { lastKnownNumber = header.Number.Uint64() - 1
return hash if n == lastKnownNumber {
} return lastKnownHash
// Not cached, iterate the blocks and cache the hashes
for header := chain.GetHeader(ref.ParentHash, ref.Number.Uint64()-1); header != nil; header = chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) {
cache[header.Number.Uint64()-1] = header.ParentHash
if n == header.Number.Uint64()-1 {
return header.ParentHash
} }
} }
return common.Hash{} return common.Hash{}

View file

@ -17,21 +17,15 @@
package runtime package runtime
import ( import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
) )
func NewEnv(cfg *Config) *vm.EVM { func NewEnv(cfg *Config) *vm.EVM {
getHash := cfg.GetHashFn
if getHash == nil {
getHash = func(uint64) common.Hash { return common.Hash{} }
}
context := vm.Context{ context := vm.Context{
CanTransfer: core.CanTransfer, CanTransfer: core.CanTransfer,
Transfer: core.Transfer, Transfer: core.Transfer,
GetHash: getHash, GetHash: cfg.GetHashFn,
Origin: cfg.Origin, Origin: cfg.Origin,
Coinbase: cfg.Coinbase, Coinbase: cfg.Coinbase,
BlockNumber: cfg.BlockNumber, BlockNumber: cfg.BlockNumber,

View file

@ -312,7 +312,7 @@ func TestBlockhash(t *testing.T) {
if last.Uint64() != 744 { if last.Uint64() != 744 {
t.Fatalf("last block should be 744, got %d (%x)", last, ret[64:96]) t.Fatalf("last block should be 744, got %d (%x)", last, ret[64:96])
} }
if chain.counter != 255 { if exp, got := 255, chain.counter; exp != got {
t.Logf("Suboptimal; too much chain iteration, expected 255, got %d", chain.counter) t.Errorf("suboptimal; too much chain iteration, expected %d, got %d", exp, got)
} }
} }