From df2349bd559ddf1b79da73a38e2bac36f22cc72e Mon Sep 17 00:00:00 2001
From: Michael de Hoog <michael.dehoog@coinbase.com>
Date: Thu, 9 Nov 2023 20:40:23 -1000
Subject: [PATCH] Ensure genesis contains create2deployer if canyon is enabled

---
 op-chain-ops/genesis/helpers.go                       | 11 +++++++++++
 op-chain-ops/genesis/layer_two.go                     |  3 +++
 op-chain-ops/genesis/layer_two_test.go                |  8 ++++++--
 .../testdata/test-deploy-config-devnet-l1.json        |  5 ++++-
 4 files changed, 24 insertions(+), 3 deletions(-)

diff --git a/op-chain-ops/genesis/helpers.go b/op-chain-ops/genesis/helpers.go
index ab577e9f8..e099dffca 100644
--- a/op-chain-ops/genesis/helpers.go
+++ b/op-chain-ops/genesis/helpers.go
@@ -10,6 +10,7 @@ import (
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common/hexutil"
 	"github.com/ethereum/go-ethereum/core/types"
+	"github.com/ethereum/go-ethereum/core/vm"
 	"github.com/ethereum/go-ethereum/rpc"
 )
 
@@ -107,3 +108,13 @@ func newHexBig(in uint64) *hexutil.Big {
 	hb := hexutil.Big(*b)
 	return &hb
 }
+
+// CreateAccountOnSetCode is a vm.StateDB wrapper that optimistically creates an account on SetCode
+type CreateAccountOnSetCode struct {
+	vm.StateDB
+}
+
+func (s *CreateAccountOnSetCode) SetCode(addr common.Address, code []byte) {
+	s.CreateAccount(addr)
+	s.StateDB.SetCode(addr, code)
+}
diff --git a/op-chain-ops/genesis/layer_two.go b/op-chain-ops/genesis/layer_two.go
index a728d3013..b69a7046e 100644
--- a/op-chain-ops/genesis/layer_two.go
+++ b/op-chain-ops/genesis/layer_two.go
@@ -3,6 +3,7 @@ package genesis
 import (
 	"fmt"
 
+	"github.com/ethereum/go-ethereum/consensus/misc"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/log"
@@ -77,5 +78,7 @@ func BuildL2Genesis(config *DeployConfig, l1StartBlock *types.Block) (*core.Gene
 		}
 	}
 
+	misc.EnsureCreate2Deployer(genspec.Config, 0, &CreateAccountOnSetCode{db})
+
 	return db.Genesis(), nil
 }
diff --git a/op-chain-ops/genesis/layer_two_test.go b/op-chain-ops/genesis/layer_two_test.go
index f941a982f..115dc5d04 100644
--- a/op-chain-ops/genesis/layer_two_test.go
+++ b/op-chain-ops/genesis/layer_two_test.go
@@ -73,6 +73,10 @@ func testBuildL2Genesis(t *testing.T, config *genesis.DeployConfig) *core.Genesi
 		require.Equal(t, common.Big1, gen.Alloc[addr].Balance)
 	}
 
+	create2Deployer := gen.Alloc[common.HexToAddress("0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2")]
+	codeHash := crypto.Keccak256Hash(create2Deployer.Code)
+	require.Equal(t, codeHash, common.HexToHash("0xb0550b5b431e30d38000efb7107aaa0ade03d48a7198a140edda9d27134468b2"))
+
 	if writeFile {
 		file, _ := json.MarshalIndent(gen, "", " ")
 		_ = os.WriteFile("genesis.json", file, 0644)
@@ -86,7 +90,7 @@ func TestBuildL2MainnetGenesis(t *testing.T) {
 	config.EnableGovernance = true
 	config.FundDevAccounts = false
 	gen := testBuildL2Genesis(t, config)
-	require.Equal(t, 2322, len(gen.Alloc))
+	require.Equal(t, 2323, len(gen.Alloc))
 }
 
 func TestBuildL2MainnetNoGovernanceGenesis(t *testing.T) {
@@ -95,5 +99,5 @@ func TestBuildL2MainnetNoGovernanceGenesis(t *testing.T) {
 	config.EnableGovernance = false
 	config.FundDevAccounts = false
 	gen := testBuildL2Genesis(t, config)
-	require.Equal(t, 2322, len(gen.Alloc))
+	require.Equal(t, 2323, len(gen.Alloc))
 }
diff --git a/op-chain-ops/genesis/testdata/test-deploy-config-devnet-l1.json b/op-chain-ops/genesis/testdata/test-deploy-config-devnet-l1.json
index 063306869..b1a11aee2 100644
--- a/op-chain-ops/genesis/testdata/test-deploy-config-devnet-l1.json
+++ b/op-chain-ops/genesis/testdata/test-deploy-config-devnet-l1.json
@@ -41,5 +41,8 @@
   "enableGovernance": true,
   "governanceTokenSymbol": "OP",
   "governanceTokenName": "Optimism",
-  "governanceTokenOwner": "0x0000000000000000000000000000000000000333"
+  "governanceTokenOwner": "0x0000000000000000000000000000000000000333",
+
+  "l2GenesisRegolithTimeOffset": "0x0",
+  "l2GenesisCanyonTimeOffset": "0x0"
 }
-- 
2.23.0