mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-03 03:31:14 +00:00
core, consensus/misc, params: implement EIP-7997 (#35223)
EIP: https://eips.ethereum.org/EIPS/eip-7997
This commit is contained in:
parent
46b79ea078
commit
c8953d10c2
6 changed files with 189 additions and 0 deletions
47
consensus/misc/eip7997.go
Normal file
47
consensus/misc/eip7997.go
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright 2026 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package misc
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/core/tracing"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
// ApplyEIP7997 inserts the deterministic deployment factory into the state as an
|
||||
// irregular state transition, as specified by EIP-7997. The factory is a keyless
|
||||
// CREATE2 factory that, once present at the canonical address on every EVM chain,
|
||||
// allows contracts to be deployed at identical addresses across chains.
|
||||
func ApplyEIP7997(statedb vm.StateDB) {
|
||||
// The account must hold the canonical factory runtime code. If its code hash
|
||||
// already matches, the chain satisfies EIP-7997 and nothing needs to change.
|
||||
wantHash := crypto.Keccak256Hash(params.DeterministicFactoryCode)
|
||||
if statedb.GetCodeHash(params.DeterministicFactoryAddress) == wantHash {
|
||||
return
|
||||
}
|
||||
if !statedb.Exist(params.DeterministicFactoryAddress) {
|
||||
statedb.CreateAccount(params.DeterministicFactoryAddress)
|
||||
}
|
||||
statedb.CreateContract(params.DeterministicFactoryAddress)
|
||||
statedb.SetCode(params.DeterministicFactoryAddress, params.DeterministicFactoryCode, tracing.CodeChangeUnspecified)
|
||||
|
||||
// Preserve a pre-existing nonce; only bump the default zero nonce to 1.
|
||||
if statedb.GetNonce(params.DeterministicFactoryAddress) == 0 {
|
||||
statedb.SetNonce(params.DeterministicFactoryAddress, 1, tracing.NonceChangeNewContract)
|
||||
}
|
||||
}
|
||||
|
|
@ -385,6 +385,11 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
|||
if config.DAOForkSupport && config.DAOForkBlock != nil && config.DAOForkBlock.Cmp(b.header.Number) == 0 {
|
||||
misc.ApplyDAOHardFork(statedb)
|
||||
}
|
||||
// EIP-7997: insert the deterministic deployment factory at the Amsterdam
|
||||
// activation block via an irregular state transition.
|
||||
if config.IsAmsterdam(b.header.Number, b.header.Time) && !config.IsAmsterdam(parent.Number(), parent.Time()) {
|
||||
misc.ApplyEIP7997(statedb)
|
||||
}
|
||||
|
||||
if config.IsPrague(b.header.Number, b.header.Time) || config.IsUBT(b.header.Number, b.header.Time) {
|
||||
// EIP-2935
|
||||
|
|
|
|||
113
core/eip7997_test.go
Normal file
113
core/eip7997_test.go
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
// Copyright 2026 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// Tests for EIP-7997: the deterministic deployment factory inserted as an
|
||||
// irregular state transition at the Amsterdam activation block.
|
||||
|
||||
package core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus/misc"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
// TestApplyEIP7997 verifies the irregular state transition seeds the factory
|
||||
// account with the canonical code and nonce.
|
||||
func TestApplyEIP7997(t *testing.T) {
|
||||
sdb := mkState(nil)
|
||||
misc.ApplyEIP7997(sdb)
|
||||
|
||||
if got := sdb.GetCode(params.DeterministicFactoryAddress); !bytes.Equal(got, params.DeterministicFactoryCode) {
|
||||
t.Fatalf("factory code mismatch:\n got %x\nwant %x", got, params.DeterministicFactoryCode)
|
||||
}
|
||||
if got := sdb.GetNonce(params.DeterministicFactoryAddress); got != 1 {
|
||||
t.Fatalf("factory nonce = %d, want %d", got, 1)
|
||||
}
|
||||
}
|
||||
|
||||
// TestApplyEIP7997Existing checks that a chain which already hosts the factory
|
||||
// (for example via its keyless creation transaction) is left untouched, so the
|
||||
// transition never rewrites an existing nonce.
|
||||
func TestApplyEIP7997Existing(t *testing.T) {
|
||||
sdb := mkState(types.GenesisAlloc{
|
||||
params.DeterministicFactoryAddress: {Code: params.DeterministicFactoryCode, Nonce: 5},
|
||||
})
|
||||
misc.ApplyEIP7997(sdb)
|
||||
|
||||
if got := sdb.GetNonce(params.DeterministicFactoryAddress); got != 5 {
|
||||
t.Fatalf("existing factory nonce overwritten: got %d, want 5", got)
|
||||
}
|
||||
}
|
||||
|
||||
// TestApplyEIP7997WrongCode checks that an account occupying the factory address
|
||||
// with the wrong code is force-overwritten with the canonical runtime code, while
|
||||
// a pre-existing non-zero nonce is preserved.
|
||||
func TestApplyEIP7997WrongCode(t *testing.T) {
|
||||
sdb := mkState(types.GenesisAlloc{
|
||||
params.DeterministicFactoryAddress: {Code: []byte{0x60, 0x00}, Nonce: 7},
|
||||
})
|
||||
misc.ApplyEIP7997(sdb)
|
||||
|
||||
if got := sdb.GetCode(params.DeterministicFactoryAddress); !bytes.Equal(got, params.DeterministicFactoryCode) {
|
||||
t.Fatalf("factory code not overwritten:\n got %x\nwant %x", got, params.DeterministicFactoryCode)
|
||||
}
|
||||
if got := sdb.GetNonce(params.DeterministicFactoryAddress); got != 7 {
|
||||
t.Fatalf("factory nonce = %d, want %d (existing nonce must be preserved)", got, 7)
|
||||
}
|
||||
}
|
||||
|
||||
// TestEIP7997FactoryDeploys exercises the inserted factory bytecode: calling it
|
||||
// with a salt followed by init code must CREATE2-deploy the contract at the
|
||||
// canonical deterministic address and return that address (20 bytes, unpadded).
|
||||
func TestEIP7997FactoryDeploys(t *testing.T) {
|
||||
sdb := mkState(nil)
|
||||
misc.ApplyEIP7997(sdb)
|
||||
|
||||
var (
|
||||
caller = common.Address{0xca}
|
||||
salt [32]byte
|
||||
// initcode returning the single-byte runtime 0xfe:
|
||||
// PUSH1 0xfe PUSH1 0x00 MSTORE8 PUSH1 0x01 PUSH1 0x00 RETURN
|
||||
initcode = common.FromHex("60fe60005360016000f3")
|
||||
)
|
||||
salt[31] = 0x42
|
||||
|
||||
input := append(append([]byte{}, salt[:]...), initcode...)
|
||||
|
||||
ret, _, err := amsterdamCoreEVM(sdb).Call(caller, params.DeterministicFactoryAddress, input, vm.NewGasBudget(10_000_000, 0), new(uint256.Int))
|
||||
if err != nil {
|
||||
t.Fatalf("factory call failed: %v", err)
|
||||
}
|
||||
|
||||
want := crypto.CreateAddress2(params.DeterministicFactoryAddress, salt, crypto.Keccak256(initcode))
|
||||
if len(ret) != 20 {
|
||||
t.Fatalf("factory returned %d bytes, want 20", len(ret))
|
||||
}
|
||||
if got := common.BytesToAddress(ret); got != want {
|
||||
t.Fatalf("factory returned address %x, want %x", got, want)
|
||||
}
|
||||
if code := sdb.GetCode(want); !bytes.Equal(code, []byte{0xfe}) {
|
||||
t.Fatalf("deployed runtime code = %x, want fe", code)
|
||||
}
|
||||
}
|
||||
|
|
@ -725,6 +725,8 @@ func DeveloperGenesisBlock(gasLimit uint64, faucet *common.Address) *Genesis {
|
|||
// EIP-8282 - Builder Execution Requests
|
||||
params.BuilderDepositAddress: {Nonce: 1, Code: params.BuilderDepositCode, Balance: common.Big0},
|
||||
params.BuilderExitAddress: {Nonce: 1, Code: params.BuilderExitCode, Balance: common.Big0},
|
||||
// EIP-7997 - Deterministic deployment factory
|
||||
params.DeterministicFactoryAddress: {Nonce: 1, Code: params.DeterministicFactoryCode, Balance: common.Big0},
|
||||
},
|
||||
}
|
||||
if faucet != nil {
|
||||
|
|
|
|||
|
|
@ -81,6 +81,11 @@ func (p *StateProcessor) Process(ctx context.Context, block *types.Block, stated
|
|||
if config.DAOForkSupport && config.DAOForkBlock != nil && config.DAOForkBlock.Cmp(block.Number()) == 0 {
|
||||
misc.ApplyDAOHardFork(tracingStateDB)
|
||||
}
|
||||
// EIP-7997: insert the deterministic deployment factory at the Amsterdam
|
||||
// activation block via an irregular state transition.
|
||||
if isEIP7997Transition(config, p.chain, header) {
|
||||
misc.ApplyEIP7997(tracingStateDB)
|
||||
}
|
||||
var (
|
||||
context = NewEVMBlockContext(header, p.chain, nil)
|
||||
signer = types.MakeSigner(config, header.Number, header.Time)
|
||||
|
|
@ -137,6 +142,19 @@ func (p *StateProcessor) Process(ctx context.Context, block *types.Block, stated
|
|||
}, nil
|
||||
}
|
||||
|
||||
// isEIP7997Transition reports whether the given header belongs to the first block
|
||||
// on which the Amsterdam fork is active.
|
||||
func isEIP7997Transition(config *params.ChainConfig, chain ChainContext, header *types.Header) bool {
|
||||
if header.Number.Sign() == 0 || !config.IsAmsterdam(header.Number, header.Time) {
|
||||
return false
|
||||
}
|
||||
parent := chain.GetHeader(header.ParentHash, header.Number.Uint64()-1)
|
||||
if parent == nil {
|
||||
return false
|
||||
}
|
||||
return !config.IsAmsterdam(parent.Number, parent.Time)
|
||||
}
|
||||
|
||||
// PreExecution processes pre-execution system calls.
|
||||
func PreExecution(ctx context.Context, beaconRoot *common.Hash, parent common.Hash, config *params.ChainConfig, evm *vm.EVM, number *big.Int, time uint64) *bal.ConstructionBlockAccessList {
|
||||
_, _, spanEnd := telemetry.StartSpan(ctx, "core.preExecution")
|
||||
|
|
|
|||
|
|
@ -270,6 +270,10 @@ var (
|
|||
BuilderDepositCode = common.FromHex("0x3373fffffffffffffffffffffffffffffffffffffffe146101065760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461023457600182026001905f5b5f82111560695781019083028483029004916001019190604e565b90939004925050503660b814608957366102345734610234575f5260205ff35b8034106102345760383567ffffffffffffffff1680633b9aca001161023457633b9aca00029034031061023457600154600101600155600354806006026004015f358155600101602035815560010160403581556001016060358155600101608035815560010160a035905560b85f5f3760b85fa0600101600355005b600354600254808203806101001161011d57506101005b5f5b8181146101c3578281016006026004018160b8028154815260200181600101548152602001816002015480825260401c67ffffffffffffffff16816010018160381c81600701538160301c81600601538160281c81600501538160201c81600401538160181c81600301538160101c81600201538160081c81600101535360200181600301548152602001816004015481526020019060050154905260010161011f565b91018092146101d557906002556101e0565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561020d57505f5b6001546020828201116102225750505f610228565b01602090035b5f555f60015560b8025ff35b5f5ffd")
|
||||
BuilderExitAddress = common.HexToAddress("0x000014574A74c805590AFF9499fc7A690f008282")
|
||||
BuilderExitCode = common.FromHex("0x3373fffffffffffffffffffffffffffffffffffffffe1460cb5760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461018857600182026001905f5b5f82111560685781019083028483029004916001019190604d565b909390049250505036603014608857366101885734610188575f5260205ff35b341061018857600154600101600155600354806003026004013381556001015f35815560010160203590553360601b5f5260305f60143760445fa0600101600355005b6003546002548082038060101160df575060105b5f5b8181146101175782810160030260040181604402815460601b8152601401816001015481526020019060020154905260010160e1565b91018092146101295790600255610134565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561016157505f5b6001546002828201116101765750505f61017c565b01600290035b5f555f6001556044025ff35b5f5ffd")
|
||||
|
||||
// EIP-7997 - Deterministic deployment factory (keyless CREATE2 factory)
|
||||
DeterministicFactoryAddress = common.HexToAddress("0x4e59b44847b379578588920cA78FbF26c0B4956C")
|
||||
DeterministicFactoryCode = common.FromHex("0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3")
|
||||
)
|
||||
|
||||
// System log events.
|
||||
|
|
|
|||
Loading…
Reference in a new issue