Commit ec266098 authored by Mark Tyneway's avatar Mark Tyneway Committed by GitHub

Merge pull request #4306 from ethereum-optimism/fix/single-commit

op-chain-ops: single database commit
parents 13110f3b 3fd7b11f
......@@ -179,11 +179,30 @@ func main() {
dryRun := ctx.Bool("dry-run")
noCheck := ctx.Bool("no-check")
// Perform the migration
res, err := genesis.MigrateDB(ldb, config, block, &migrationData, !dryRun, noCheck)
if err != nil {
return err
}
// Close the database handle
if err := ldb.Close(); err != nil {
return err
}
postLDB, err := rawdb.NewLevelDBDatabaseWithFreezer(chaindataPath, dbCache, dbHandles, ancientPath, "", false)
if err != nil {
return err
}
if err := genesis.CheckMigratedDB(postLDB); err != nil {
return err
}
if err := postLDB.Close(); err != nil {
return err
}
opNodeConfig, err := config.RollupConfig(block, res.TransitionBlockHash, res.TransitionHeight)
if err != nil {
return err
......
......@@ -21,6 +21,10 @@ func getOVMETHTotalSupplySlot() common.Hash {
return key
}
func GetOVMETHTotalSupplySlot() common.Hash {
return getOVMETHTotalSupplySlot()
}
// getOVMETHBalance gets a user's OVM ETH balance from state by querying the
// appropriate storage slot directly.
func getOVMETHBalance(db *state.StateDB, addr common.Address) *big.Int {
......
......@@ -34,7 +34,7 @@ var (
}
)
func MigrateLegacyETH(db ethdb.Database, addresses []common.Address, allowances []*migration.Allowance, chainID int, commit, noCheck bool) (common.Hash, error) {
func MigrateLegacyETH(db ethdb.Database, stateDB *state.StateDB, addresses []common.Address, allowances []*migration.Allowance, chainID int, noCheck bool) error {
// Set of addresses that we will be migrating.
addressesToMigrate := make(map[common.Address]bool)
// Set of storage slots that we expect to see in the OVM ETH contract.
......@@ -42,7 +42,7 @@ func MigrateLegacyETH(db ethdb.Database, addresses []common.Address, allowances
// Chain params to use for integrity checking.
params := ParamsByChainID[chainID]
if params == nil {
return common.Hash{}, fmt.Errorf("no chain params for %d", chainID)
return fmt.Errorf("no chain params for %d", chainID)
}
log.Info("Chain params", "chain-id", chainID, "supply-delta", params.ExpectedSupplyDelta)
......@@ -85,7 +85,7 @@ func MigrateLegacyETH(db ethdb.Database, addresses []common.Address, allowances
return nil
})
if err != nil {
return common.Hash{}, wrapErr(err, "error reading mint events")
return wrapErr(err, "error reading mint events")
}
// Make sure all addresses are accounted for by iterating over
......@@ -96,9 +96,8 @@ func MigrateLegacyETH(db ethdb.Database, addresses []common.Address, allowances
backingStateDB := state.NewDatabaseWithConfig(db, &trie.Config{
Preimages: true,
})
stateDB, err := state.New(root, backingStateDB, nil)
if err != nil {
return common.Hash{}, wrapErr(err, "error opening state DB")
return wrapErr(err, "error opening state DB")
}
storageTrie := stateDB.StorageTrie(OVMETHAddress)
storageIt := trie.NewIterator(storageTrie.NodeIterator(nil))
......@@ -173,7 +172,7 @@ func MigrateLegacyETH(db ethdb.Database, addresses []common.Address, allowances
log.Info("trie dumping started", "root", root)
tr, err := backingStateDB.OpenTrie(root)
if err != nil {
return common.Hash{}, err
return err
}
it := trie.NewIterator(tr.NodeIterator(nil))
totalMigrated := new(big.Int)
......@@ -251,21 +250,5 @@ func MigrateLegacyETH(db ethdb.Database, addresses []common.Address, allowances
stateDB.SetState(predeploys.LegacyERC20ETHAddr, getOVMETHTotalSupplySlot(), common.Hash{})
log.Info("Set the totalSupply to 0")
if !commit {
log.Info("dry run, skipping commit")
return common.Hash{}, nil
}
log.Info("committing state DB")
newRoot, err := stateDB.Commit(true)
if err != nil {
return common.Hash{}, err
}
log.Info("committing trie DB")
if err := stateDB.Database().TrieDB().Commit(newRoot, true, nil); err != nil {
return common.Hash{}, err
}
return newRoot, nil
return nil
}
package genesis
import (
"errors"
"fmt"
"math/big"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum-optimism/optimism/op-chain-ops/ether"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/trie"
)
// CheckMigratedDB will check that the migration was performed correctly
func CheckMigratedDB(ldb ethdb.Database) error {
log.Info("Validating database migration")
hash := rawdb.ReadHeadHeaderHash(ldb)
log.Info("Reading chain tip from database", "hash", hash)
num := rawdb.ReadHeaderNumber(ldb, hash)
if num == nil {
return fmt.Errorf("cannot find header number for %s", hash)
}
header := rawdb.ReadHeader(ldb, hash, *num)
log.Info("Read header from database", "number", *num)
underlyingDB := state.NewDatabaseWithConfig(ldb, &trie.Config{
Preimages: true,
})
db, err := state.New(header.Root, underlyingDB, nil)
if err != nil {
return fmt.Errorf("cannot open StateDB: %w", err)
}
if err := CheckPredeploys(db); err != nil {
return err
}
if err := CheckLegacyETH(db); err != nil {
return err
}
return nil
}
// CheckPredeploys will check that there is code at each predeploy
// address
func CheckPredeploys(db vm.StateDB) error {
for i := uint64(0); i <= 2048; i++ {
// Compute the predeploy address
bigAddr := new(big.Int).Or(bigL2PredeployNamespace, new(big.Int).SetUint64(i))
addr := common.BigToAddress(bigAddr)
// Get the code for the predeploy
code := db.GetCode(addr)
// There must be code for the predeploy
if len(code) == 0 {
return fmt.Errorf("no code found at predeploy %s", addr)
}
// There must be an implementation
impl := db.GetState(addr, ImplementationSlot)
implAddr := common.BytesToAddress(impl.Bytes())
if implAddr == (common.Address{}) {
return fmt.Errorf("no implementation for %s", addr)
}
implCode := db.GetCode(implAddr)
if len(implCode) == 0 {
return fmt.Errorf("no code found at predeploy impl %s", addr)
}
// There must be an admin
admin := db.GetState(addr, AdminSlot)
adminAddr := common.BytesToAddress(admin.Bytes())
if adminAddr != predeploys.ProxyAdminAddr {
return fmt.Errorf("admin is %s when it should be % for %s", adminAddr, predeploys.ProxyAdminAddr, addr)
}
}
return nil
}
// CheckLegacyETH checks that the legacy eth migration was successful.
// It currently only checks that the total supply was set to 0.
func CheckLegacyETH(db vm.StateDB) error {
// Ensure total supply is set to 0
slot := db.GetState(predeploys.LegacyERC20ETHAddr, ether.GetOVMETHTotalSupplySlot())
if slot != (common.Hash{}) {
return errors.New("total supply not set to 0")
}
return nil
}
......@@ -121,11 +121,17 @@ func MigrateDB(ldb ethdb.Database, config *DeployConfig, l1Block *types.Block, m
log.Info("Starting to migrate ERC20 ETH")
addrs := migrationData.Addresses()
newRoot, err := ether.MigrateLegacyETH(ldb, addrs, migrationData.OvmAllowances, int(config.L1ChainID), commit, noCheck)
err = ether.MigrateLegacyETH(ldb, db, addrs, migrationData.OvmAllowances, int(config.L1ChainID), noCheck)
if err != nil {
return nil, fmt.Errorf("cannot migrate legacy eth: %w", err)
}
log.Info("Completed ERC20 ETH migration", "root", newRoot)
log.Info("Completed ERC20 ETH migration")
newRoot, err := db.Commit(true)
if err != nil {
return nil, err
}
log.Info("committing state DB", "root", newRoot)
// Set the amount of gas used so that EIP 1559 starts off stable
gasUsed := (uint64)(config.L2GenesisBlockGasLimit) * config.EIP1559Elasticity
......@@ -172,6 +178,11 @@ func MigrateDB(ldb ethdb.Database, config *DeployConfig, l1Block *types.Block, m
return res, nil
}
log.Info("committing trie DB")
if err := db.Database().TrieDB().Commit(newRoot, true, nil); err != nil {
return nil, err
}
rawdb.WriteTd(ldb, bedrockBlock.Hash(), bedrockBlock.NumberU64(), bedrockBlock.Difficulty())
rawdb.WriteBlock(ldb, bedrockBlock)
rawdb.WriteReceipts(ldb, bedrockBlock.Hash(), bedrockBlock.NumberU64(), nil)
......
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