Commit 528ee87d authored by Matthew Slipper's avatar Matthew Slipper Committed by GitHub

Merge pull request #4749 from ethereum-optimism/feat/fix-nonce-wipe

op-chain-ops: Preserve predeploy nonces
parents 117e5746 9b3cbbd8
...@@ -119,6 +119,11 @@ func PostCheckMigratedDB( ...@@ -119,6 +119,11 @@ func PostCheckMigratedDB(
Preimages: true, Preimages: true,
}) })
prevDB, err := state.New(prevHeader.Root, underlyingDB, nil)
if err != nil {
return fmt.Errorf("cannot open historical StateDB: %w", err)
}
db, err := state.New(header.Root, underlyingDB, nil) db, err := state.New(header.Root, underlyingDB, nil)
if err != nil { if err != nil {
return fmt.Errorf("cannot open StateDB: %w", err) return fmt.Errorf("cannot open StateDB: %w", err)
...@@ -134,7 +139,7 @@ func PostCheckMigratedDB( ...@@ -134,7 +139,7 @@ func PostCheckMigratedDB(
} }
log.Info("checked untouchables") log.Info("checked untouchables")
if err := PostCheckPredeploys(db); err != nil { if err := PostCheckPredeploys(prevDB, db); err != nil {
return err return err
} }
log.Info("checked predeploys") log.Info("checked predeploys")
...@@ -209,13 +214,13 @@ func PostCheckUntouchables(udb state.Database, currDB *state.StateDB, prevRoot c ...@@ -209,13 +214,13 @@ func PostCheckUntouchables(udb state.Database, currDB *state.StateDB, prevRoot c
// PostCheckPredeploys will check that there is code at each predeploy // PostCheckPredeploys will check that there is code at each predeploy
// address // address
func PostCheckPredeploys(db *state.StateDB) error { func PostCheckPredeploys(prevDB, currDB *state.StateDB) error {
for i := uint64(0); i <= 2048; i++ { for i := uint64(0); i <= 2048; i++ {
// Compute the predeploy address // Compute the predeploy address
bigAddr := new(big.Int).Or(bigL2PredeployNamespace, new(big.Int).SetUint64(i)) bigAddr := new(big.Int).Or(bigL2PredeployNamespace, new(big.Int).SetUint64(i))
addr := common.BigToAddress(bigAddr) addr := common.BigToAddress(bigAddr)
// Get the code for the predeploy // Get the code for the predeploy
code := db.GetCode(addr) code := currDB.GetCode(addr)
// There must be code for the predeploy // There must be code for the predeploy
if len(code) == 0 { if len(code) == 0 {
return fmt.Errorf("no code found at predeploy %s", addr) return fmt.Errorf("no code found at predeploy %s", addr)
...@@ -227,11 +232,23 @@ func PostCheckPredeploys(db *state.StateDB) error { ...@@ -227,11 +232,23 @@ func PostCheckPredeploys(db *state.StateDB) error {
} }
// There must be an admin // There must be an admin
admin := db.GetState(addr, AdminSlot) admin := currDB.GetState(addr, AdminSlot)
adminAddr := common.BytesToAddress(admin.Bytes()) adminAddr := common.BytesToAddress(admin.Bytes())
if addr != predeploys.ProxyAdminAddr && addr != predeploys.GovernanceTokenAddr && adminAddr != predeploys.ProxyAdminAddr { if addr != predeploys.ProxyAdminAddr && addr != predeploys.GovernanceTokenAddr && adminAddr != predeploys.ProxyAdminAddr {
return fmt.Errorf("expected admin for %s to be %s but got %s", addr, predeploys.ProxyAdminAddr, adminAddr) return fmt.Errorf("expected admin for %s to be %s but got %s", addr, predeploys.ProxyAdminAddr, adminAddr)
} }
// Balances and nonces should match legacy
oldNonce := prevDB.GetNonce(addr)
oldBalance := prevDB.GetBalance(addr)
newNonce := currDB.GetNonce(addr)
newBalance := currDB.GetBalance(addr)
if oldNonce != newNonce {
return fmt.Errorf("expected nonce for %s to be %d but got %d", addr, oldNonce, newNonce)
}
if oldBalance.Cmp(newBalance) != 0 {
return fmt.Errorf("expected balance for %s to be %d but got %d", addr, oldBalance, newBalance)
}
} }
// For each predeploy, check that we've set the implementation correctly when // For each predeploy, check that we've set the implementation correctly when
...@@ -248,7 +265,7 @@ func PostCheckPredeploys(db *state.StateDB) error { ...@@ -248,7 +265,7 @@ func PostCheckPredeploys(db *state.StateDB) error {
} }
if *proxyAddr == predeploys.ProxyAdminAddr { if *proxyAddr == predeploys.ProxyAdminAddr {
implCode := db.GetCode(*proxyAddr) implCode := currDB.GetCode(*proxyAddr)
if len(implCode) == 0 { if len(implCode) == 0 {
return errors.New("no code found at proxy admin") return errors.New("no code found at proxy admin")
} }
...@@ -260,12 +277,12 @@ func PostCheckPredeploys(db *state.StateDB) error { ...@@ -260,12 +277,12 @@ func PostCheckPredeploys(db *state.StateDB) error {
return fmt.Errorf("error converting to code namespace: %w", err) return fmt.Errorf("error converting to code namespace: %w", err)
} }
implCode := db.GetCode(expImplAddr) implCode := currDB.GetCode(expImplAddr)
if len(implCode) == 0 { if len(implCode) == 0 {
return fmt.Errorf("no code found at predeploy impl %s", *proxyAddr) return fmt.Errorf("no code found at predeploy impl %s", *proxyAddr)
} }
impl := db.GetState(*proxyAddr, ImplementationSlot) impl := currDB.GetState(*proxyAddr, ImplementationSlot)
actImplAddr := common.BytesToAddress(impl.Bytes()) actImplAddr := common.BytesToAddress(impl.Bytes())
if expImplAddr != actImplAddr { if expImplAddr != actImplAddr {
return fmt.Errorf("expected implementation for %s to be at %s, but got %s", *proxyAddr, expImplAddr, actImplAddr) return fmt.Errorf("expected implementation for %s to be at %s, but got %s", *proxyAddr, expImplAddr, actImplAddr)
......
...@@ -92,7 +92,17 @@ func WipePredeployStorage(db vm.StateDB) error { ...@@ -92,7 +92,17 @@ func WipePredeployStorage(db vm.StateDB) error {
} }
log.Info("wiping storage", "name", name, "address", *addr) log.Info("wiping storage", "name", name, "address", *addr)
// We need to make sure that we preserve nonces.
oldNonce := db.GetNonce(*addr)
oldBalance := db.GetBalance(*addr)
db.CreateAccount(*addr) db.CreateAccount(*addr)
if oldNonce > 0 {
db.SetNonce(*addr, oldNonce)
}
if oldBalance.Cmp(common.Big0) != 0 {
db.AddBalance(*addr, oldBalance)
}
} }
return nil return 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