diff --git a/consensus/misc/create2deployer.go b/consensus/misc/create2deployer.go index a8970eebeb..40724a2019 100644 --- a/consensus/misc/create2deployer.go +++ b/consensus/misc/create2deployer.go @@ -5,10 +5,18 @@ import ( "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" ) -// create2Deployer is already deployed to Base goerli at 0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2, +// 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 goerli at 0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2, // so we deploy it to 0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF1 for hardfork testing purposes var create2DeployerAddresses = map[uint64]common.Address{ params.BaseGoerliChainID: common.HexToAddress("0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF1"), @@ -33,5 +41,6 @@ func EnsureCreate2Deployer(c *params.ChainConfig, timestamp uint64, db vm.StateD 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 +}