Commit 91a6fca3 authored by protolambda's avatar protolambda Committed by GitHub

op-chain-ops: unwrap l1 and l2 allocs (#10387)

parent 40421e86
...@@ -149,9 +149,7 @@ def devnet_l1_allocs(paths): ...@@ -149,9 +149,7 @@ def devnet_l1_allocs(paths):
'DEPLOY_CONFIG_PATH': paths.devnet_config_path, 'DEPLOY_CONFIG_PATH': paths.devnet_config_path,
}, cwd=paths.contracts_bedrock_dir) }, cwd=paths.contracts_bedrock_dir)
forge_dump = read_json(paths.forge_l1_dump_path) shutil.move(src=paths.forge_l1_dump_path, dst=paths.allocs_l1_path)
write_json(paths.allocs_l1_path, { "accounts": forge_dump })
os.remove(paths.forge_l1_dump_path)
shutil.copy(paths.l1_deployments_path, paths.addresses_json_path) shutil.copy(paths.l1_deployments_path, paths.addresses_json_path)
...@@ -171,10 +169,8 @@ def devnet_l2_allocs(paths): ...@@ -171,10 +169,8 @@ def devnet_l2_allocs(paths):
# move the forge-dumps into place as .devnet allocs. # move the forge-dumps into place as .devnet allocs.
for suffix in ["-delta", ""]: for suffix in ["-delta", ""]:
input_path = pjoin(paths.contracts_bedrock_dir, f"state-dump-901{suffix}.json") input_path = pjoin(paths.contracts_bedrock_dir, f"state-dump-901{suffix}.json")
forge_dump = read_json(input_path)
output_path = pjoin(paths.devnet_dir, f'allocs-l2{suffix}.json') output_path = pjoin(paths.devnet_dir, f'allocs-l2{suffix}.json')
write_json(output_path, { "accounts": forge_dump }) shutil.move(src=input_path, dst=output_path)
os.remove(input_path)
log.info("Generated L2 allocs: "+output_path) log.info("Generated L2 allocs: "+output_path)
......
...@@ -10,11 +10,11 @@ import ( ...@@ -10,11 +10,11 @@ import (
"path/filepath" "path/filepath"
"reflect" "reflect"
"github.com/holiman/uint256"
"golang.org/x/exp/maps" "golang.org/x/exp/maps"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
gstate "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
...@@ -759,65 +759,8 @@ func NewL1Deployments(path string) (*L1Deployments, error) { ...@@ -759,65 +759,8 @@ func NewL1Deployments(path string) (*L1Deployments, error) {
return &deployments, nil return &deployments, nil
} }
// NewStateDump will read a Dump JSON file from disk
func NewStateDump(path string) (*gstate.Dump, error) {
file, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("dump at %s not found: %w", path, err)
}
var fdump ForgeDump
if err := json.Unmarshal(file, &fdump); err != nil {
return nil, fmt.Errorf("cannot unmarshal dump: %w", err)
}
dump := (gstate.Dump)(fdump)
return &dump, nil
}
// ForgeDump is a simple alias for state.Dump that can read "nonce" as a hex string.
// It appears as if updates to foundry have changed the serialization of the state dump.
type ForgeDump gstate.Dump
func (d *ForgeDump) UnmarshalJSON(b []byte) error {
type forgeDumpAccount struct {
Balance string `json:"balance"`
Nonce hexutil.Uint64 `json:"nonce"`
Root hexutil.Bytes `json:"root"`
CodeHash hexutil.Bytes `json:"codeHash"`
Code hexutil.Bytes `json:"code,omitempty"`
Storage map[common.Hash]string `json:"storage,omitempty"`
Address *common.Address `json:"address,omitempty"`
AddressHash hexutil.Bytes `json:"key,omitempty"`
}
type forgeDump struct {
Root string `json:"root"`
Accounts map[common.Address]forgeDumpAccount `json:"accounts"`
}
var dump forgeDump
if err := json.Unmarshal(b, &dump); err != nil {
return err
}
d.Root = dump.Root
d.Accounts = make(map[string]gstate.DumpAccount)
for addr, acc := range dump.Accounts {
acc := acc
d.Accounts[addr.String()] = gstate.DumpAccount{
Balance: acc.Balance,
Nonce: (uint64)(acc.Nonce),
Root: acc.Root,
CodeHash: acc.CodeHash,
Code: acc.Code,
Storage: acc.Storage,
Address: acc.Address,
AddressHash: acc.AddressHash,
}
}
return nil
}
type ForgeAllocs struct { type ForgeAllocs struct {
Accounts types.GenesisAlloc `json:"accounts"` Accounts types.GenesisAlloc
} }
func (d *ForgeAllocs) Copy() *ForgeAllocs { func (d *ForgeAllocs) Copy() *ForgeAllocs {
...@@ -829,25 +772,22 @@ func (d *ForgeAllocs) Copy() *ForgeAllocs { ...@@ -829,25 +772,22 @@ func (d *ForgeAllocs) Copy() *ForgeAllocs {
func (d *ForgeAllocs) UnmarshalJSON(b []byte) error { func (d *ForgeAllocs) UnmarshalJSON(b []byte) error {
// forge, since integrating Alloy, likes to hex-encode everything. // forge, since integrating Alloy, likes to hex-encode everything.
type forgeAllocAccount struct { type forgeAllocAccount struct {
Balance hexutil.Big `json:"balance"` Balance hexutil.U256 `json:"balance"`
Nonce hexutil.Uint64 `json:"nonce"` Nonce hexutil.Uint64 `json:"nonce"`
Code hexutil.Bytes `json:"code,omitempty"` Code hexutil.Bytes `json:"code,omitempty"`
Storage map[common.Hash]common.Hash `json:"storage,omitempty"` Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
} }
type forgeAllocs struct { var allocs map[common.Address]forgeAllocAccount
Accounts map[common.Address]forgeAllocAccount `json:"accounts"`
}
var allocs forgeAllocs
if err := json.Unmarshal(b, &allocs); err != nil { if err := json.Unmarshal(b, &allocs); err != nil {
return err return err
} }
d.Accounts = make(types.GenesisAlloc, len(allocs.Accounts)) d.Accounts = make(types.GenesisAlloc, len(allocs))
for addr, acc := range allocs.Accounts { for addr, acc := range allocs {
acc := acc acc := acc
d.Accounts[addr] = types.Account{ d.Accounts[addr] = types.Account{
Code: acc.Code, Code: acc.Code,
Storage: acc.Storage, Storage: acc.Storage,
Balance: acc.Balance.ToInt(), Balance: (*uint256.Int)(&acc.Balance).ToBig(),
Nonce: (uint64)(acc.Nonce), Nonce: (uint64)(acc.Nonce),
PrivateKey: nil, PrivateKey: nil,
} }
......
...@@ -8,7 +8,6 @@ import ( ...@@ -8,7 +8,6 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
gstate "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
...@@ -50,50 +49,30 @@ func init() { ...@@ -50,50 +49,30 @@ func init() {
// all of the state required for an Optimism network to function. // all of the state required for an Optimism network to function.
// It is expected that the dump contains all of the required state to bootstrap // It is expected that the dump contains all of the required state to bootstrap
// the L1 chain. // the L1 chain.
func BuildL1DeveloperGenesis(config *DeployConfig, dump *gstate.Dump, l1Deployments *L1Deployments) (*core.Genesis, error) { func BuildL1DeveloperGenesis(config *DeployConfig, dump *ForgeAllocs, l1Deployments *L1Deployments) (*core.Genesis, error) {
log.Info("Building developer L1 genesis block") log.Info("Building developer L1 genesis block")
genesis, err := NewL1Genesis(config) genesis, err := NewL1Genesis(config)
if err != nil { if err != nil {
return nil, fmt.Errorf("cannot create L1 developer genesis: %w", err) return nil, fmt.Errorf("cannot create L1 developer genesis: %w", err)
} }
if genesis.Alloc != nil && len(genesis.Alloc) != 0 {
panic("Did not expect NewL1Genesis to generate non-empty state") // sanity check for dev purposes.
}
// copy, for safety when the dump is reused (like in e2e testing)
genesis.Alloc = dump.Copy().Accounts
memDB := state.NewMemoryStateDB(genesis) memDB := state.NewMemoryStateDB(genesis)
FundDevAccounts(memDB) FundDevAccounts(memDB)
SetPrecompileBalances(memDB) SetPrecompileBalances(memDB)
if dump != nil { l1Deployments.ForEach(func(name string, addr common.Address) {
for addrstr, account := range dump.Accounts { acc := memDB.GetAccount(addr)
if !common.IsHexAddress(addrstr) { if acc != nil {
// Changes in https://github.com/ethereum/go-ethereum/pull/28504 log.Info("Included L1 deployment", "name", name, "address", addr, "balance", acc.Balance, "storage", len(acc.Storage), "nonce", acc.Nonce)
// add accounts to the Dump with "pre(<AddressHash>)" as key } else {
// if the address itself is nil. log.Info("Excluded L1 deployment", "name", name, "address", addr)
// So depending on how `dump` was created, this might be a
// pre-image key, which we skip.
continue
}
address := common.HexToAddress(addrstr)
name := "<unknown>"
if l1Deployments != nil {
if n := l1Deployments.GetName(address); n != "" {
name = n
}
}
log.Info("Setting account", "name", name, "address", address.Hex())
memDB.CreateAccount(address)
memDB.SetNonce(address, account.Nonce)
balance := &uint256.Int{}
if err := balance.UnmarshalText([]byte(account.Balance)); err != nil {
return nil, fmt.Errorf("failed to parse balance for %s: %w", address, err)
}
memDB.AddBalance(address, balance)
memDB.SetCode(address, account.Code)
for key, value := range account.Storage {
log.Info("Setting storage", "name", name, "key", key.Hex(), "value", value)
memDB.SetState(address, key, common.HexToHash(value))
}
} }
} })
return memDB.Genesis(), nil return memDB.Genesis(), nil
} }
......
...@@ -41,9 +41,9 @@ func BuildL2Genesis(config *DeployConfig, dump *ForgeAllocs, l1StartBlock *types ...@@ -41,9 +41,9 @@ func BuildL2Genesis(config *DeployConfig, dump *ForgeAllocs, l1StartBlock *types
if err != nil { if err != nil {
return nil, err return nil, err
} }
genspec.Alloc = dump.Accounts genspec.Alloc = dump.Copy().Accounts
// ensure the dev accounts are not funded unintentionally // ensure the dev accounts are not funded unintentionally
if hasDevAccounts, err := HasAnyDevAccounts(dump.Accounts); err != nil { if hasDevAccounts, err := HasAnyDevAccounts(genspec.Alloc); err != nil {
return nil, fmt.Errorf("failed to check dev accounts: %w", err) return nil, fmt.Errorf("failed to check dev accounts: %w", err)
} else if hasDevAccounts != config.FundDevAccounts { } else if hasDevAccounts != config.FundDevAccounts {
return nil, fmt.Errorf("deploy config mismatch with allocs. Deploy config fundDevAccounts: %v, actual allocs: %v", config.FundDevAccounts, hasDevAccounts) return nil, fmt.Errorf("deploy config mismatch with allocs. Deploy config fundDevAccounts: %v, actual allocs: %v", config.FundDevAccounts, hasDevAccounts)
......
...@@ -13,7 +13,6 @@ import ( ...@@ -13,7 +13,6 @@ import (
"golang.org/x/exp/slog" "golang.org/x/exp/slog"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum-optimism/optimism/op-chain-ops/genesis" "github.com/ethereum-optimism/optimism/op-chain-ops/genesis"
...@@ -40,7 +39,7 @@ var ( ...@@ -40,7 +39,7 @@ var (
// in end to end tests. // in end to end tests.
// L1Allocs represents the L1 genesis block state. // L1Allocs represents the L1 genesis block state.
L1Allocs *state.Dump L1Allocs *genesis.ForgeAllocs
// L1Deployments maps contract names to accounts in the L1 // L1Deployments maps contract names to accounts in the L1
// genesis block state. // genesis block state.
L1Deployments *genesis.L1Deployments L1Deployments *genesis.L1Deployments
...@@ -108,7 +107,7 @@ func init() { ...@@ -108,7 +107,7 @@ func init() {
return return
} }
L1Allocs, err = genesis.NewStateDump(l1AllocsPath) L1Allocs, err = genesis.LoadForgeAllocs(l1AllocsPath)
if err != nil { if err != nil {
panic(err) panic(err)
} }
......
...@@ -11,7 +11,6 @@ import ( ...@@ -11,7 +11,6 @@ import (
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
...@@ -113,9 +112,9 @@ var Subcommands = cli.Commands{ ...@@ -113,9 +112,9 @@ var Subcommands = cli.Commands{
return fmt.Errorf("deploy config at %s invalid: %w", deployConfig, err) return fmt.Errorf("deploy config at %s invalid: %w", deployConfig, err)
} }
var dump *state.Dump var dump *genesis.ForgeAllocs
if l1Allocs := ctx.String("l1-allocs"); l1Allocs != "" { if l1Allocs := ctx.String("l1-allocs"); l1Allocs != "" {
dump, err = genesis.NewStateDump(l1Allocs) dump, err = genesis.LoadForgeAllocs(l1Allocs)
if err != nil { if err != nil {
return err return err
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment