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):
'DEPLOY_CONFIG_PATH': paths.devnet_config_path,
}, cwd=paths.contracts_bedrock_dir)
forge_dump = read_json(paths.forge_l1_dump_path)
write_json(paths.allocs_l1_path, { "accounts": forge_dump })
os.remove(paths.forge_l1_dump_path)
shutil.move(src=paths.forge_l1_dump_path, dst=paths.allocs_l1_path)
shutil.copy(paths.l1_deployments_path, paths.addresses_json_path)
......@@ -171,10 +169,8 @@ def devnet_l2_allocs(paths):
# move the forge-dumps into place as .devnet allocs.
for suffix in ["-delta", ""]:
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')
write_json(output_path, { "accounts": forge_dump })
os.remove(input_path)
shutil.move(src=input_path, dst=output_path)
log.info("Generated L2 allocs: "+output_path)
......
......@@ -10,11 +10,11 @@ import (
"path/filepath"
"reflect"
"github.com/holiman/uint256"
"golang.org/x/exp/maps"
"github.com/ethereum/go-ethereum/common"
"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/log"
"github.com/ethereum/go-ethereum/params"
......@@ -759,65 +759,8 @@ func NewL1Deployments(path string) (*L1Deployments, error) {
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 {
Accounts types.GenesisAlloc `json:"accounts"`
Accounts types.GenesisAlloc
}
func (d *ForgeAllocs) Copy() *ForgeAllocs {
......@@ -829,25 +772,22 @@ func (d *ForgeAllocs) Copy() *ForgeAllocs {
func (d *ForgeAllocs) UnmarshalJSON(b []byte) error {
// forge, since integrating Alloy, likes to hex-encode everything.
type forgeAllocAccount struct {
Balance hexutil.Big `json:"balance"`
Balance hexutil.U256 `json:"balance"`
Nonce hexutil.Uint64 `json:"nonce"`
Code hexutil.Bytes `json:"code,omitempty"`
Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
}
type forgeAllocs struct {
Accounts map[common.Address]forgeAllocAccount `json:"accounts"`
}
var allocs forgeAllocs
var allocs map[common.Address]forgeAllocAccount
if err := json.Unmarshal(b, &allocs); err != nil {
return err
}
d.Accounts = make(types.GenesisAlloc, len(allocs.Accounts))
for addr, acc := range allocs.Accounts {
d.Accounts = make(types.GenesisAlloc, len(allocs))
for addr, acc := range allocs {
acc := acc
d.Accounts[addr] = types.Account{
Code: acc.Code,
Storage: acc.Storage,
Balance: acc.Balance.ToInt(),
Balance: (*uint256.Int)(&acc.Balance).ToBig(),
Nonce: (uint64)(acc.Nonce),
PrivateKey: nil,
}
......
......@@ -8,7 +8,6 @@ import (
"github.com/ethereum/go-ethereum/common"
"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/log"
"github.com/ethereum/go-ethereum/params"
......@@ -50,50 +49,30 @@ func init() {
// 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
// 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")
genesis, err := NewL1Genesis(config)
if err != nil {
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)
FundDevAccounts(memDB)
SetPrecompileBalances(memDB)
if dump != nil {
for addrstr, account := range dump.Accounts {
if !common.IsHexAddress(addrstr) {
// Changes in https://github.com/ethereum/go-ethereum/pull/28504
// add accounts to the Dump with "pre(<AddressHash>)" as key
// if the address itself is nil.
// 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))
}
l1Deployments.ForEach(func(name string, addr common.Address) {
acc := memDB.GetAccount(addr)
if acc != nil {
log.Info("Included L1 deployment", "name", name, "address", addr, "balance", acc.Balance, "storage", len(acc.Storage), "nonce", acc.Nonce)
} else {
log.Info("Excluded L1 deployment", "name", name, "address", addr)
}
}
})
return memDB.Genesis(), nil
}
......
......@@ -41,9 +41,9 @@ func BuildL2Genesis(config *DeployConfig, dump *ForgeAllocs, l1StartBlock *types
if err != nil {
return nil, err
}
genspec.Alloc = dump.Accounts
genspec.Alloc = dump.Copy().Accounts
// 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)
} else if hasDevAccounts != config.FundDevAccounts {
return nil, fmt.Errorf("deploy config mismatch with allocs. Deploy config fundDevAccounts: %v, actual allocs: %v", config.FundDevAccounts, hasDevAccounts)
......
......@@ -13,7 +13,6 @@ import (
"golang.org/x/exp/slog"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum-optimism/optimism/op-chain-ops/genesis"
......@@ -40,7 +39,7 @@ var (
// in end to end tests.
// L1Allocs represents the L1 genesis block state.
L1Allocs *state.Dump
L1Allocs *genesis.ForgeAllocs
// L1Deployments maps contract names to accounts in the L1
// genesis block state.
L1Deployments *genesis.L1Deployments
......@@ -108,7 +107,7 @@ func init() {
return
}
L1Allocs, err = genesis.NewStateDump(l1AllocsPath)
L1Allocs, err = genesis.LoadForgeAllocs(l1AllocsPath)
if err != nil {
panic(err)
}
......
......@@ -11,7 +11,6 @@ import (
"github.com/urfave/cli/v2"
"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/ethclient"
"github.com/ethereum/go-ethereum/log"
......@@ -113,9 +112,9 @@ var Subcommands = cli.Commands{
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 != "" {
dump, err = genesis.NewStateDump(l1Allocs)
dump, err = genesis.LoadForgeAllocs(l1Allocs)
if err != nil {
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