mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-21 20:26:41 +00:00
core, consensus/misc, params: implement EIP-7997
This commit is contained in:
parent
4387f433c9
commit
47c1f0d390
6 changed files with 175 additions and 0 deletions
45
consensus/misc/eip7997.go
Normal file
45
consensus/misc/eip7997.go
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
// 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"
|
||||
)
|
||||
|
||||
// deterministicFactoryCodeHash is the keccak256 of the canonical factory code,
|
||||
// used to detect an already-deployed factory.
|
||||
var deterministicFactoryCodeHash = crypto.Keccak256Hash(params.DeterministicFactoryCode)
|
||||
|
||||
// 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) {
|
||||
// If the canonical factory is already in place there is nothing to do.
|
||||
if statedb.GetCodeHash(params.DeterministicFactoryAddress) == deterministicFactoryCodeHash {
|
||||
return
|
||||
}
|
||||
if !statedb.Exist(params.DeterministicFactoryAddress) {
|
||||
statedb.CreateAccount(params.DeterministicFactoryAddress)
|
||||
}
|
||||
statedb.CreateContract(params.DeterministicFactoryAddress)
|
||||
statedb.SetCode(params.DeterministicFactoryAddress, params.DeterministicFactoryCode, tracing.CodeChangeUnspecified)
|
||||
statedb.SetNonce(params.DeterministicFactoryAddress, params.DeterministicFactoryNonce, 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
|
||||
|
|
|
|||
96
core/eip7997_test.go
Normal file
96
core/eip7997_test.go
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
// 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 != params.DeterministicFactoryNonce {
|
||||
t.Fatalf("factory nonce = %d, want %d", got, params.DeterministicFactoryNonce)
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
|
@ -721,6 +721,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: params.DeterministicFactoryNonce, 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")
|
||||
|
|
|
|||
|
|
@ -246,6 +246,15 @@ 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")
|
||||
|
||||
// DeterministicFactoryNonce is the nonce the factory account carries, matching
|
||||
// the keyless deployment transaction that originally created it (nonce 0 of the
|
||||
// deployer, leaving the factory itself at nonce 1).
|
||||
DeterministicFactoryNonce = uint64(1)
|
||||
)
|
||||
|
||||
// System log events.
|
||||
|
|
|
|||
Loading…
Reference in a new issue