From 650bb2f2b1dcfe30d9b1fa6f7dc9608055ed60e1 Mon Sep 17 00:00:00 2001 From: Michael de Hoog Date: Fri, 20 Oct 2023 08:21:32 -1000 Subject: [PATCH] Deploy create2deployer in the next hardfork (#126) * Deploy create2deployer in the next hardfork * Switch to superchain bytecode * Also deploy to Base goerli * Add comment, log, and test * Add additional base testnets / devnets --- consensus/misc/create2deployer.go | 49 ++++++++++++ consensus/misc/create2deployer_test.go | 103 +++++++++++++++++++++++++ core/state_processor.go | 1 + miner/worker.go | 3 + params/config.go | 14 ++-- 5 files changed, 165 insertions(+), 5 deletions(-) create mode 100644 consensus/misc/create2deployer.go create mode 100644 consensus/misc/create2deployer_test.go diff --git a/consensus/misc/create2deployer.go b/consensus/misc/create2deployer.go new file mode 100644 index 0000000000..47e0554faa --- /dev/null +++ b/consensus/misc/create2deployer.go @@ -0,0 +1,49 @@ +package misc + +import ( + "github.com/ethereum-optimism/superchain-registry/superchain" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/params" +) + +// The original create2deployer contract could not be deployed to Base mainnet at +// the canonical address of 0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2 due to +// an accidental nonce increment from a deposit transaction. See +// https://github.com/pcaversaccio/create2deployer/issues/128 for context. This +// file applies the contract code to the canonical address manually in the Canyon +// hardfork. + +// create2deployer is already deployed to Base testnets at 0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2, +// so we deploy it to 0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF1 for hardfork testing purposes +var create2DeployerAddresses = map[uint64]common.Address{ + 11763071: common.HexToAddress("0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF1"), // Base Goerli devnet + params.BaseGoerliChainID: common.HexToAddress("0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF1"), // Base Goerli testnet + 11763072: common.HexToAddress("0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF1"), // Base Sepolia devnet + 84532: common.HexToAddress("0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF1"), // Base Sepolia testnet + params.BaseMainnetChainID: common.HexToAddress("0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2"), // Base mainnet +} +var create2DeployerCodeHash = common.HexToHash("0xb0550b5b431e30d38000efb7107aaa0ade03d48a7198a140edda9d27134468b2") +var create2DeployerCode []byte + +func init() { + code, err := superchain.LoadContractBytecode(superchain.Hash(create2DeployerCodeHash)) + if err != nil { + panic(err) + } + create2DeployerCode = code +} + +func EnsureCreate2Deployer(c *params.ChainConfig, timestamp uint64, db vm.StateDB) { + if !c.IsOptimism() || c.CanyonTime == nil || *c.CanyonTime != timestamp { + return + } + address, ok := create2DeployerAddresses[c.ChainID.Uint64()] + if !ok || db.GetCodeSize(address) > 0 { + return + } + log.Info("Setting Create2Deployer code", "address", address, "codeHash", create2DeployerCodeHash) + db.SetCode(address, create2DeployerCode) +} diff --git a/consensus/misc/create2deployer_test.go b/consensus/misc/create2deployer_test.go new file mode 100644 index 0000000000..3e58856989 --- /dev/null +++ b/consensus/misc/create2deployer_test.go @@ -0,0 +1,103 @@ +package misc + +import ( + "math/big" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/params" +) + +func TestEnsureCreate2Deployer(t *testing.T) { + canyonTime := uint64(1000) + var tests = []struct { + name string + override func(cfg *params.ChainConfig) + timestamp uint64 + codeExists bool + applied bool + }{ + { + name: "at hardfork", + timestamp: canyonTime, + applied: true, + }, + { + name: "non-optimism chain", + override: func(cfg *params.ChainConfig) { + cfg.Optimism = nil + }, + timestamp: canyonTime, + applied: false, + }, + { + name: "non-base chain", + override: func(cfg *params.ChainConfig) { + cfg.ChainID = big.NewInt(params.OPMainnetChainID) + }, + timestamp: canyonTime, + applied: false, + }, + { + name: "pre canyon", + timestamp: canyonTime - 1, + applied: false, + }, + { + name: "post hardfork", + timestamp: canyonTime + 1, + applied: false, + }, + { + name: "canyon not configured", + override: func(cfg *params.ChainConfig) { + cfg.CanyonTime = nil + }, + timestamp: canyonTime, + applied: false, + }, + { + name: "code already exists", + timestamp: canyonTime, + codeExists: true, + applied: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cfg := params.ChainConfig{ + ChainID: big.NewInt(params.BaseMainnetChainID), + Optimism: ¶ms.OptimismConfig{}, + CanyonTime: &canyonTime, + } + if tt.override != nil { + tt.override(&cfg) + } + state := &stateDb{ + codeExists: tt.codeExists, + } + EnsureCreate2Deployer(&cfg, tt.timestamp, state) + assert.Equal(t, tt.applied, state.codeSet) + }) + } +} + +type stateDb struct { + vm.StateDB + codeExists bool + codeSet bool +} + +func (s *stateDb) GetCodeSize(_ common.Address) int { + if s.codeExists { + return 1 + } + return 0 +} + +func (s *stateDb) SetCode(_ common.Address, _ []byte) { + s.codeSet = true +} diff --git a/core/state_processor.go b/core/state_processor.go index 136b7e183e..b674731a34 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -71,6 +71,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { misc.ApplyDAOHardFork(statedb) } + misc.EnsureCreate2Deployer(p.config, block.Time(), statedb) var ( context = NewEVMBlockContext(header, p.bc, nil, p.config, statedb) vmenv = vm.NewEVM(context, vm.TxContext{}, statedb, p.config, cfg) diff --git a/miner/worker.go b/miner/worker.go index fbe9d1c53e..433399b68b 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -27,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/consensus/misc/eip1559" "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core" @@ -1071,6 +1072,8 @@ func (w *worker) generateWork(genParams *generateParams) *newPayloadResult { work.gasPool = new(core.GasPool).AddGas(work.header.GasLimit) } + misc.EnsureCreate2Deployer(w.chainConfig, work.header.Time, work.state) + for _, tx := range genParams.txs { from, _ := types.Sender(work.signer, tx) work.state.SetTxContext(tx.Hash(), work.tcount) diff --git a/params/config.go b/params/config.go index 415700dfbb..f1fcf08b91 100644 --- a/params/config.go +++ b/params/config.go @@ -32,11 +32,12 @@ var ( ) const ( - OPMainnetChainID = 10 - OPGoerliChainID = 420 - BaseGoerliChainID = 84531 - devnetChainID = 997 - chaosnetChainID = 888 + OPMainnetChainID = 10 + OPGoerliChainID = 420 + BaseMainnetChainID = 8453 + BaseGoerliChainID = 84531 + devnetChainID = 997 + chaosnetChainID = 888 ) // OP Stack chain config @@ -495,6 +496,9 @@ func (c *ChainConfig) Description() string { if c.RegolithTime != nil { banner += fmt.Sprintf(" - Regolith: @%-10v\n", *c.RegolithTime) } + if c.CanyonTime != nil { + banner += fmt.Sprintf(" - Canyon: @%-10v\n", *c.CanyonTime) + } return banner }