diff --git a/core/evm.go b/core/evm.go index b654bbd479..8abe5a0477 100644 --- a/core/evm.go +++ b/core/evm.go @@ -60,24 +60,32 @@ func NewEVMContext(msg Message, header *types.Header, chain ChainContext, author // GetHashFn returns a GetHashFunc which retrieves header hashes by number 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 { // If there's no hash cache yet, make one - if cache == nil { - cache = map[uint64]common.Hash{ - ref.Number.Uint64() - 1: ref.ParentHash, + if len(cache) == 0 { + cache = append(cache, 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 } - } - // Try to fulfill the request from the cache - if hash, ok := cache[n]; ok { - return hash - } - // 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 + cache = append(cache, header.ParentHash) + lastKnownHash = header.ParentHash + lastKnownNumber = header.Number.Uint64() - 1 + if n == lastKnownNumber { + return lastKnownHash } } return common.Hash{} diff --git a/core/vm/runtime/env.go b/core/vm/runtime/env.go index 42a5b0f801..38ee448904 100644 --- a/core/vm/runtime/env.go +++ b/core/vm/runtime/env.go @@ -17,21 +17,15 @@ package runtime import ( - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/vm" ) func NewEnv(cfg *Config) *vm.EVM { - getHash := cfg.GetHashFn - if getHash == nil { - getHash = func(uint64) common.Hash { return common.Hash{} } - } - context := vm.Context{ CanTransfer: core.CanTransfer, Transfer: core.Transfer, - GetHash: getHash, + GetHash: cfg.GetHashFn, Origin: cfg.Origin, Coinbase: cfg.Coinbase, BlockNumber: cfg.BlockNumber, diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index cc1c746732..33491c0dd6 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -312,7 +312,7 @@ func TestBlockhash(t *testing.T) { if last.Uint64() != 744 { t.Fatalf("last block should be 744, got %d (%x)", last, ret[64:96]) } - if chain.counter != 255 { - t.Logf("Suboptimal; too much chain iteration, expected 255, got %d", chain.counter) + if exp, got := 255, chain.counter; exp != got { + t.Errorf("suboptimal; too much chain iteration, expected %d, got %d", exp, got) } }