rewrite instruction to check if 256th ancestor passed shanghai

This commit is contained in:
Guillaume Ballet 2024-01-22 18:23:32 +01:00
parent 12770a1fa1
commit 78cce0e69d
3 changed files with 48 additions and 20 deletions

View file

@ -36,6 +36,8 @@ type ChainContext interface {
// GetHeader returns the header corresponding to the hash/number argument pair.
GetHeader(common.Hash, uint64) *types.Header
Config() *params.ChainConfig
}
// NewEVMBlockContext creates a new context for use in the EVM.
@ -103,39 +105,52 @@ func GetHashFn(ref *types.Header, chain ChainContext) vm.GetHashFunc {
return common.Hash{}
}
// 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
var eip2935Ancestor *types.Header
// If there's no hash cache yet, make one and fill
// it with all 256 hashes. We have to get all blocks
// since for eip2935 we need to query the 256th
// ancestor to find out if it had eip2935 enabled.
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))
limit := uint64(257)
if ref.Number.Uint64() < limit {
limit = ref.Number.Uint64()
}
for {
for ref.Number.Uint64()-lastKnownNumber < limit {
header := chain.GetHeader(lastKnownHash, lastKnownNumber)
if header == nil {
break
}
if lastKnownNumber == n {
eip2935Ancestor = header
}
cache = append(cache, header.ParentHash)
lastKnownHash = header.ParentHash
lastKnownNumber = header.Number.Uint64() - 1
if n == lastKnownNumber {
return lastKnownHash
}
}
} else {
if eip2935 {
// Check if the 256th ancestor had already activated eip 2935.
// If the ancestor is nil, then this is the case of a testnet
// that forked within 256 blocks of the genesis.
if eip2935Ancestor != nil && chain.Config().IsPrague(eip2935Ancestor.Number, eip2935Ancestor.Time) {
var key common.Hash
binary.BigEndian.PutUint64(key[24:], n)
return statedb.GetState(params.HistoryStorageAddress, key)
}
// if the 256th ancestor did not have eip2935 enabled, try
// to get the value from the cache.
if idx := ref.Number.Uint64() - n - 1; idx < uint64(len(cache)) {
return cache[idx]
}
// something went wrong while building the cache
return common.Hash{}
}
}

View file

@ -247,6 +247,14 @@ func (d *dummyChain) GetHeader(h common.Hash, n uint64) *types.Header {
return fakeHeader(n, parentHash)
}
func (d *dummyChain) Config() *params.ChainConfig {
return nil
}
func (d *dummyChain) GetHeaderByNumber(n uint64) *types.Header {
return d.GetHeader(common.Hash{}, n)
}
// TestBlockhash tests the blockhash operation. It's a bit special, since it internally
// requires access to a chain reader.
func TestBlockhash(t *testing.T) {

View file

@ -1043,6 +1043,7 @@ func (diff *BlockOverrides) Apply(blockCtx *vm.BlockContext) {
type ChainContextBackend interface {
Engine() consensus.Engine
HeaderByNumber(context.Context, rpc.BlockNumber) (*types.Header, error)
ChainConfig() *params.ChainConfig
}
// ChainContext is an implementation of core.ChainContext. It's main use-case
@ -1071,6 +1072,10 @@ func (context *ChainContext) GetHeader(hash common.Hash, number uint64) *types.H
return header
}
func (context *ChainContext) Config() *params.ChainConfig {
return context.b.ChainConfig()
}
func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.StateDB, header *types.Header, overrides *StateOverride, blockOverrides *BlockOverrides, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) {
if err := overrides.Apply(state); err != nil {
return nil, err