diff --git a/core/evm.go b/core/evm.go index d303c40a40..e830847bd5 100644 --- a/core/evm.go +++ b/core/evm.go @@ -60,24 +60,33 @@ 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{}