mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
implement hash reads from smart contract
This commit is contained in:
parent
b4460a8f74
commit
6164aadba8
4 changed files with 45 additions and 28 deletions
55
core/evm.go
55
core/evm.go
|
|
@ -17,6 +17,7 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
|
@ -24,6 +25,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
// ChainContext supports retrieving headers and consensus parameters from the
|
||||
|
|
@ -89,40 +91,51 @@ func NewEVMTxContext(msg *Message) vm.TxContext {
|
|||
}
|
||||
|
||||
// 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) vm.GetHashFunc {
|
||||
// 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, statedb vm.StateDB, eip2935 bool) common.Hash {
|
||||
if ref.Number.Uint64() <= n {
|
||||
// This situation can happen if we're doing tracing and using
|
||||
// block overrides.
|
||||
return common.Hash{}
|
||||
}
|
||||
// If there's no hash cache yet, make one
|
||||
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
|
||||
// Use the cache if it is within 256 blocks from the head.
|
||||
if n >= ref.Number.Uint64()-256 {
|
||||
// If there's no hash cache yet, make one
|
||||
if len(cache) == 0 {
|
||||
cache = append(cache, ref.ParentHash)
|
||||
}
|
||||
cache = append(cache, header.ParentHash)
|
||||
lastKnownHash = header.ParentHash
|
||||
lastKnownNumber = header.Number.Uint64() - 1
|
||||
if n == lastKnownNumber {
|
||||
return lastKnownHash
|
||||
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)
|
||||
lastKnownHash = header.ParentHash
|
||||
lastKnownNumber = header.Number.Uint64() - 1
|
||||
if n == lastKnownNumber {
|
||||
return lastKnownHash
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if eip2935 {
|
||||
var key common.Hash
|
||||
binary.BigEndian.PutUint64(key[24:], n)
|
||||
return statedb.GetState(params.HistoryStorageAddress, key)
|
||||
}
|
||||
}
|
||||
|
||||
return common.Hash{}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ type (
|
|||
TransferFunc func(StateDB, common.Address, common.Address, *big.Int)
|
||||
// GetHashFunc returns the n'th block hash in the blockchain
|
||||
// and is used by the BLOCKHASH EVM op code.
|
||||
GetHashFunc func(uint64) common.Hash
|
||||
GetHashFunc func(uint64, StateDB, bool) common.Hash
|
||||
)
|
||||
|
||||
func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) {
|
||||
|
|
|
|||
|
|
@ -441,13 +441,17 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) (
|
|||
}
|
||||
var upper, lower uint64
|
||||
upper = interpreter.evm.Context.BlockNumber.Uint64()
|
||||
if upper < 257 {
|
||||
lower = 0
|
||||
} else {
|
||||
evm := interpreter.evm
|
||||
|
||||
// After Prague, the values preceding FORKNUM will be 0,
|
||||
// as requested in EIP-2935. So it's fine to allow 0 as
|
||||
// the lower bound.
|
||||
if !evm.chainRules.IsPrague && upper >= 257 {
|
||||
lower = upper - 256
|
||||
}
|
||||
|
||||
if num64 >= lower && num64 < upper {
|
||||
num.SetBytes(interpreter.evm.Context.GetHash(num64).Bytes())
|
||||
num.SetBytes(evm.Context.GetHash(num64, evm.StateDB, evm.chainRules.IsPrague).Bytes())
|
||||
} else {
|
||||
num.Clear()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ type Config struct {
|
|||
Random *common.Hash
|
||||
|
||||
State *state.StateDB
|
||||
GetHashFn func(n uint64) common.Hash
|
||||
GetHashFn vm.GetHashFunc
|
||||
}
|
||||
|
||||
// sets defaults on the config
|
||||
|
|
@ -90,7 +90,7 @@ func setDefaults(cfg *Config) {
|
|||
cfg.BlockNumber = new(big.Int)
|
||||
}
|
||||
if cfg.GetHashFn == nil {
|
||||
cfg.GetHashFn = func(n uint64) common.Hash {
|
||||
cfg.GetHashFn = func(n uint64, _ vm.StateDB, _ bool) common.Hash {
|
||||
return common.BytesToHash(crypto.Keccak256([]byte(new(big.Int).SetUint64(n).String())))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue