Commit b1266611 authored by mergify[bot]'s avatar mergify[bot] Committed by GitHub

Merge branch 'develop' into fix/deposit-eth-task

parents 758c50d3 73f98724
...@@ -7,10 +7,15 @@ import ( ...@@ -7,10 +7,15 @@ import (
"errors" "errors"
"fmt" "fmt"
"math/big" "math/big"
"math/rand"
"os" "os"
"strings" "strings"
"sync/atomic"
"time" "time"
"github.com/ethereum/go-ethereum/consensus/misc"
"github.com/ethereum/go-ethereum/params"
"github.com/mattn/go-isatty" "github.com/mattn/go-isatty"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
...@@ -37,6 +42,9 @@ import ( ...@@ -37,6 +42,9 @@ import (
// value true. // value true.
var abiTrue = common.Hash{31: 0x01} var abiTrue = common.Hash{31: 0x01}
// batchSize represents the number of withdrawals to prove/finalize at a time.
var batchSize = 25
// callFrame represents the response returned from geth's // callFrame represents the response returned from geth's
// `debug_traceTransaction` callTracer // `debug_traceTransaction` callTracer
type callFrame struct { type callFrame struct {
...@@ -71,7 +79,8 @@ type suspiciousWithdrawal struct { ...@@ -71,7 +79,8 @@ type suspiciousWithdrawal struct {
} }
func main() { func main() {
log.Root().SetHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(isatty.IsTerminal(os.Stderr.Fd())))) lvlHdlr := log.StreamHandler(os.Stderr, log.TerminalFormat(isatty.IsTerminal(os.Stderr.Fd())))
log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, lvlHdlr))
app := &cli.App{ app := &cli.App{
Name: "withdrawals", Name: "withdrawals",
...@@ -212,51 +221,67 @@ func main() { ...@@ -212,51 +221,67 @@ func main() {
} }
} }
// iterate over all of the withdrawals and submit them nonce, err := clients.L1Client.NonceAt(context.Background(), opts.From, nil)
for i, wd := range wds { if err != nil {
log.Info("Processing withdrawal", "index", i) return err
}
// The goroutines below use an atomic increment-and-get, so we need
// to subtract one here to make the initial value correct.
nonce--
log.Info("starting nonce", "nonce", nonce)
proveWithdrawals := func(wd *crossdomain.LegacyWithdrawal, bf *big.Int, i int) {
// migrate the withdrawal // migrate the withdrawal
withdrawal, err := crossdomain.MigrateWithdrawal(wd, &l1xdmAddr, l2ChainID) withdrawal, err := crossdomain.MigrateWithdrawal(wd, &l1xdmAddr, l2ChainID)
if err != nil { if err != nil {
return err log.Error("error migrating withdrawal", "err", err)
return
} }
// Pass to Portal // Pass to Portal
hash, err := withdrawal.Hash() hash, err := withdrawal.Hash()
if err != nil { if err != nil {
return err log.Error("error hashing withdrawal", "err", err)
return
} }
lcdm := wd.CrossDomainMessage() lcdm := wd.CrossDomainMessage()
legacyXdmHash, err := lcdm.Hash() legacyXdmHash, err := lcdm.Hash()
if err != nil { if err != nil {
return err log.Error("error hashing legacy withdrawal", "err", err)
return
} }
// check to see if the withdrawal has already been successfully // check to see if the withdrawal has already been successfully
// relayed or received // relayed or received
isSuccess, err := contracts.L1CrossDomainMessenger.SuccessfulMessages(&bind.CallOpts{}, legacyXdmHash) isSuccess, err := contracts.L1CrossDomainMessenger.SuccessfulMessages(&bind.CallOpts{}, legacyXdmHash)
if err != nil { if err != nil {
return err log.Error("error checking legacy withdrawal status", "err", err)
return
} }
isFailed, err := contracts.L1CrossDomainMessenger.FailedMessages(&bind.CallOpts{}, legacyXdmHash) isFailed, err := contracts.L1CrossDomainMessenger.FailedMessages(&bind.CallOpts{}, legacyXdmHash)
if err != nil { if err != nil {
return err log.Error("error checking legacy withdrawal status", "err", err)
return
} }
xdmHash := crypto.Keccak256Hash(withdrawal.Data) xdmHash := crypto.Keccak256Hash(withdrawal.Data)
if err != nil { if err != nil {
return err log.Error("error hashing crossdomain message", "err", err)
return
} }
isSuccessNew, err := contracts.L1CrossDomainMessenger.SuccessfulMessages(&bind.CallOpts{}, xdmHash) isSuccessNew, err := contracts.L1CrossDomainMessenger.SuccessfulMessages(&bind.CallOpts{}, xdmHash)
if err != nil { if err != nil {
return err log.Error("error checking withdrawal status", "err", err)
return
} }
isFailedNew, err := contracts.L1CrossDomainMessenger.FailedMessages(&bind.CallOpts{}, xdmHash) isFailedNew, err := contracts.L1CrossDomainMessenger.FailedMessages(&bind.CallOpts{}, xdmHash)
if err != nil { if err != nil {
return err log.Error("error checking withdrawal status", "err", err)
return
} }
log.Info("cross domain messenger status", "hash", legacyXdmHash.Hex(), "success", isSuccess, "failed", isFailed, "is-success-new", isSuccessNew, "is-failed-new", isFailedNew) log.Info("cross domain messenger status", "hash", legacyXdmHash.Hex(), "success", isSuccess, "failed", isFailed, "is-success-new", isSuccessNew, "is-failed-new", isFailedNew)
...@@ -264,89 +289,212 @@ func main() { ...@@ -264,89 +289,212 @@ func main() {
// compute the storage slot // compute the storage slot
slot, err := withdrawal.StorageSlot() slot, err := withdrawal.StorageSlot()
if err != nil { if err != nil {
return err log.Error("error computing storage slot", "err", err)
return
} }
// successful messages can be skipped, received messages failed // successful messages can be skipped, received messages failed their execution and should be replayed
// their execution and should be replayed
if isSuccessNew { if isSuccessNew {
log.Info("Message already relayed", "index", i, "hash", hash.Hex(), "slot", slot.Hex()) log.Info("Message already relayed", "index", i, "hash", hash.Hex(), "slot", slot.Hex())
continue return
} }
// check the storage value of the slot to ensure that it is in // check the storage value of the slot to ensure that it is in
// the L2 storage. Without this check, the proof will fail // the L2 storage. Without this check, the proof will fail
storageValue, err := clients.L2Client.StorageAt(context.Background(), predeploys.L2ToL1MessagePasserAddr, slot, nil) storageValue, err := clients.L2Client.StorageAt(context.Background(), predeploys.L2ToL1MessagePasserAddr, slot, nil)
if err != nil { if err != nil {
return err log.Error("error fetching storage slot value", "err", err)
return
} }
log.Debug("L2ToL1MessagePasser status", "value", common.Bytes2Hex(storageValue)) log.Debug("L2ToL1MessagePasser status", "value", common.Bytes2Hex(storageValue))
// the value should be set to a boolean in storage // the value should be set to a boolean in storage
if !bytes.Equal(storageValue, abiTrue.Bytes()) { if !bytes.Equal(storageValue, abiTrue.Bytes()) {
return fmt.Errorf("storage slot %x not found in state", slot.Hex()) log.Error(
"storage slot not found in state",
"slot", slot.Hex(),
"xTarget", wd.XDomainTarget,
"xData", wd.XDomainData,
"xNonce", wd.XDomainNonce,
"xSender", wd.XDomainSender,
"sender", wd.MessageSender,
"success", isSuccess,
"failed", isFailed,
"failed-new", isFailedNew,
)
return
} }
legacySlot, err := wd.StorageSlot() legacySlot, err := wd.StorageSlot()
if err != nil { if err != nil {
return err log.Error("error computing legacy storage slot", "err", err)
return
} }
legacyStorageValue, err := clients.L2Client.StorageAt(context.Background(), predeploys.LegacyMessagePasserAddr, legacySlot, nil) legacyStorageValue, err := clients.L2Client.StorageAt(context.Background(), predeploys.LegacyMessagePasserAddr, legacySlot, nil)
if err != nil { if err != nil {
return err log.Error("error fetching legacy storage slot value", "err", err)
return
} }
log.Debug("LegacyMessagePasser status", "value", common.Bytes2Hex(legacyStorageValue)) log.Debug("LegacyMessagePasser status", "value", common.Bytes2Hex(legacyStorageValue))
// check to see if its already been proven // check to see if its already been proven
proven, err := contracts.OptimismPortal.ProvenWithdrawals(&bind.CallOpts{}, hash) proven, err := contracts.OptimismPortal.ProvenWithdrawals(&bind.CallOpts{}, hash)
if err != nil { if err != nil {
return err log.Error("error fetching proven withdrawal status", "err", err)
return
} }
// if it has not been proven, then prove it // if it has not been proven, then prove it
if proven.Timestamp.Cmp(common.Big0) == 0 { if proven.Timestamp.Cmp(common.Big0) == 0 {
log.Info("Proving withdrawal to OptimismPortal") log.Info("Proving withdrawal to OptimismPortal")
if err := proveWithdrawalTransaction(contracts, clients, opts, withdrawal, bedrockStartingBlockNumber, period); err != nil {
return err // create a transactor
optsCopy, err := newTransactor(ctx)
if err != nil {
log.Crit("error creating transactor", "err", err)
return
}
optsCopy.Nonce = new(big.Int).SetUint64(atomic.AddUint64(&nonce, 1))
optsCopy.GasTipCap = big.NewInt(2_500_000_000)
optsCopy.GasFeeCap = bf
if err := proveWithdrawalTransaction(contracts, clients, optsCopy, withdrawal, bedrockStartingBlockNumber); err != nil {
log.Error("error proving withdrawal", "err", err)
return
}
proven, err = contracts.OptimismPortal.ProvenWithdrawals(&bind.CallOpts{}, hash)
if err != nil {
log.Error("error fetching proven withdrawal status", "err", err)
return
}
if proven.Timestamp.Cmp(common.Big0) == 0 {
log.Error("error proving withdrawal", "wdHash", hash)
} }
} else { } else {
log.Info("Withdrawal already proven to OptimismPortal") log.Info("Withdrawal already proven to OptimismPortal")
} }
}
finalizeWithdrawals := func(wd *crossdomain.LegacyWithdrawal, bf *big.Int, i int) {
// migrate the withdrawal
withdrawal, err := crossdomain.MigrateWithdrawal(wd, &l1xdmAddr, l2ChainID)
if err != nil {
log.Error("error migrating withdrawal", "err", err)
return
}
// Pass to Portal
hash, err := withdrawal.Hash()
if err != nil {
log.Error("error hashing withdrawal", "err", err)
return
}
lcdm := wd.CrossDomainMessage()
legacyXdmHash, err := lcdm.Hash()
if err != nil {
log.Error("error hashing legacy withdrawal", "err", err)
return
}
// check to see if the withdrawal has already been successfully
// relayed or received
isSuccess, err := contracts.L1CrossDomainMessenger.SuccessfulMessages(&bind.CallOpts{}, legacyXdmHash)
if err != nil {
log.Error("error checking legacy withdrawal status", "err", err)
return
}
xdmHash := crypto.Keccak256Hash(withdrawal.Data)
if err != nil {
log.Error("error hashing crossdomain message", "err", err)
return
}
// check to see if its already been proven
proven, err := contracts.OptimismPortal.ProvenWithdrawals(&bind.CallOpts{}, hash)
if err != nil {
log.Error("error fetching proven withdrawal status", "err", err)
return
}
// check to see if the withdrawal has been finalized already // check to see if the withdrawal has been finalized already
isFinalized, err := contracts.OptimismPortal.FinalizedWithdrawals(&bind.CallOpts{}, hash) isFinalized, err := contracts.OptimismPortal.FinalizedWithdrawals(&bind.CallOpts{}, hash)
if err != nil { if err != nil {
return err log.Error("error fetching finalized withdrawal status", "err", err)
return
}
// Log an error if the withdrawal has not been proven
// It should have been proven in the previous loop
if proven.Timestamp.Cmp(common.Big0) == 0 {
log.Error("withdrawal has not been proven", "wdHash", hash)
return
} }
if !isFinalized { if !isFinalized {
initialTime := proven.Timestamp.Uint64()
var block *types.Block
for {
log.Info("Waiting for finalization")
block, err = clients.L1Client.BlockByNumber(context.Background(), nil)
if err != nil {
log.Error("error fetching block", "err", err)
}
if block.Time() >= initialTime+period.Uint64() {
log.Info("can be finalized")
break
}
time.Sleep(1 * time.Second)
}
// Get the ETH balance of the withdrawal target *before* the finalization // Get the ETH balance of the withdrawal target *before* the finalization
targetBalBefore, err := clients.L1Client.BalanceAt(context.Background(), wd.XDomainTarget, nil) targetBalBefore, err := clients.L1Client.BalanceAt(context.Background(), wd.XDomainTarget, nil)
if err != nil { if err != nil {
return err log.Error("error fetching target balance before", "err", err)
return
} }
log.Debug("Balance before finalization", "balance", targetBalBefore, "account", wd.XDomainTarget) log.Debug("Balance before finalization", "balance", targetBalBefore, "account", wd.XDomainTarget)
log.Info("Finalizing withdrawal") log.Info("Finalizing withdrawal")
receipt, err := finalizeWithdrawalTransaction(contracts, clients, opts, wd, withdrawal)
// make a copy of opts
optsCopy, err := newTransactor(ctx)
if err != nil { if err != nil {
return err log.Crit("error creating transactor", "err", err)
return
}
optsCopy.Nonce = new(big.Int).SetUint64(atomic.AddUint64(&nonce, 1))
optsCopy.GasTipCap = big.NewInt(2_500_000_000)
optsCopy.GasFeeCap = bf
receipt, err := finalizeWithdrawalTransaction(contracts, clients, optsCopy, wd, withdrawal)
if err != nil {
log.Error("error finalizing withdrawal", "err", err)
return
} }
log.Info("withdrawal finalized", "tx-hash", receipt.TxHash, "withdrawal-hash", hash) log.Info("withdrawal finalized", "tx-hash", receipt.TxHash, "withdrawal-hash", hash)
finalizationTrace, err := callTrace(clients, receipt) finalizationTrace, err := callTrace(clients, receipt)
if err != nil { if err != nil {
return nil log.Error("error fetching finalization trace", "err", err)
return
} }
isSuccessNewPost, err := contracts.L1CrossDomainMessenger.SuccessfulMessages(&bind.CallOpts{}, xdmHash) isSuccessNewPost, err := contracts.L1CrossDomainMessenger.SuccessfulMessages(&bind.CallOpts{}, xdmHash)
if err != nil { if err != nil {
return err log.Error("error fetching new post success status", "err", err)
return
} }
// This would indicate that there is a replayability problem // This would indicate that there is a replayability problem
if isSuccess && isSuccessNewPost { if isSuccess && isSuccessNewPost {
if err := writeSuspicious(f, withdrawal, wd, finalizationTrace, i, "should revert"); err != nil { if err := writeSuspicious(f, withdrawal, wd, finalizationTrace, i, "should revert"); err != nil {
return err log.Error("error writing suspicious withdrawal", "err", err)
return
} }
panic("DOUBLE PLAYED DEPOSIT ALLOWED") panic("DOUBLE PLAYED DEPOSIT ALLOWED")
} }
...@@ -354,20 +502,23 @@ func main() { ...@@ -354,20 +502,23 @@ func main() {
callFrame := findWithdrawalCall(&finalizationTrace, wd, l1xdmAddr) callFrame := findWithdrawalCall(&finalizationTrace, wd, l1xdmAddr)
if callFrame == nil { if callFrame == nil {
if err := writeSuspicious(f, withdrawal, wd, finalizationTrace, i, "cannot find callframe"); err != nil { if err := writeSuspicious(f, withdrawal, wd, finalizationTrace, i, "cannot find callframe"); err != nil {
return err log.Error("error writing suspicious withdrawal", "err", err)
return
} }
continue return
} }
traceJson, err := json.MarshalIndent(callFrame, "", " ") traceJson, err := json.MarshalIndent(callFrame, "", " ")
if err != nil { if err != nil {
return err log.Error("error marshalling callframe", "err", err)
return
} }
log.Debug(fmt.Sprintf("%v", string(traceJson))) log.Debug(fmt.Sprintf("%v", string(traceJson)))
abi, err := bindings.L1StandardBridgeMetaData.GetAbi() abi, err := bindings.L1StandardBridgeMetaData.GetAbi()
if err != nil { if err != nil {
return err log.Error("error getting abi of the L1StandardBridge", "err", err)
return
} }
calldata := hexutil.MustDecode(callFrame.Input) calldata := hexutil.MustDecode(callFrame.Input)
...@@ -378,7 +529,8 @@ func main() { ...@@ -378,7 +529,8 @@ func main() {
if err == nil { if err == nil {
args, err := method.Inputs.Unpack(calldata[4:]) args, err := method.Inputs.Unpack(calldata[4:])
if err != nil { if err != nil {
return err log.Error("error unpacking calldata", "err", err)
return
} }
log.Info("decoded calldata", "name", method.Name) log.Info("decoded calldata", "name", method.Name)
...@@ -386,11 +538,13 @@ func main() { ...@@ -386,11 +538,13 @@ func main() {
switch method.Name { switch method.Name {
case "finalizeERC20Withdrawal": case "finalizeERC20Withdrawal":
if err := handleFinalizeERC20Withdrawal(args, receipt, l1StandardBridgeAddress); err != nil { if err := handleFinalizeERC20Withdrawal(args, receipt, l1StandardBridgeAddress); err != nil {
return err log.Error("error handling finalizeERC20Withdrawal", "err", err)
return
} }
case "finalizeETHWithdrawal": case "finalizeETHWithdrawal":
if err := handleFinalizeETHWithdrawal(args); err != nil { if err := handleFinalizeETHWithdrawal(args); err != nil {
return err log.Error("error handling finalizeETHWithdrawal", "err", err)
return
} }
default: default:
log.Info("Unhandled method", "name", method.Name) log.Info("Unhandled method", "name", method.Name)
...@@ -400,14 +554,16 @@ func main() { ...@@ -400,14 +554,16 @@ func main() {
// Ensure that the target's balance was increasedData correctly // Ensure that the target's balance was increasedData correctly
wdValue, err := wd.Value() wdValue, err := wd.Value()
if err != nil { if err != nil {
return err log.Error("error getting withdrawal value", "err", err)
return
} }
if method != nil { if method != nil {
log.Info("withdrawal action", "function", method.Name, "value", wdValue) log.Info("withdrawal action", "function", method.Name, "value", wdValue)
} else { } else {
log.Info("unknown method", "to", wd.XDomainTarget, "data", hexutil.Encode(wd.XDomainData)) log.Info("unknown method", "to", wd.XDomainTarget, "data", hexutil.Encode(wd.XDomainData))
if err := writeSuspicious(f, withdrawal, wd, finalizationTrace, i, "unknown method"); err != nil { if err := writeSuspicious(f, withdrawal, wd, finalizationTrace, i, "unknown method"); err != nil {
return err log.Error("error writing suspicious withdrawal", "err", err)
return
} }
} }
...@@ -416,30 +572,33 @@ func main() { ...@@ -416,30 +572,33 @@ func main() {
log.Info("target mismatch", "index", i) log.Info("target mismatch", "index", i)
if err := writeSuspicious(f, withdrawal, wd, finalizationTrace, i, "target mismatch"); err != nil { if err := writeSuspicious(f, withdrawal, wd, finalizationTrace, i, "target mismatch"); err != nil {
return err log.Error("error writing suspicious withdrawal", "err", err)
return
} }
continue
} }
if !bytes.Equal(hexutil.MustDecode(callFrame.Input), wd.XDomainData) { if !bytes.Equal(hexutil.MustDecode(callFrame.Input), wd.XDomainData) {
log.Info("calldata mismatch", "index", i) log.Info("calldata mismatch", "index", i)
if err := writeSuspicious(f, withdrawal, wd, finalizationTrace, i, "calldata mismatch"); err != nil { if err := writeSuspicious(f, withdrawal, wd, finalizationTrace, i, "calldata mismatch"); err != nil {
return err log.Error("error writing suspicious withdrawal", "err", err)
return
} }
continue return
} }
if callFrame.BigValue().Cmp(wdValue) != 0 { if callFrame.BigValue().Cmp(wdValue) != 0 {
log.Info("value mismatch", "index", i) log.Info("value mismatch", "index", i)
if err := writeSuspicious(f, withdrawal, wd, finalizationTrace, i, "value mismatch"); err != nil { if err := writeSuspicious(f, withdrawal, wd, finalizationTrace, i, "value mismatch"); err != nil {
return err log.Error("error writing suspicious withdrawal", "err", err)
return
} }
continue return
} }
// Get the ETH balance of the withdrawal target *after* the finalization // Get the ETH balance of the withdrawal target *after* the finalization
targetBalAfter, err := clients.L1Client.BalanceAt(context.Background(), wd.XDomainTarget, nil) targetBalAfter, err := clients.L1Client.BalanceAt(context.Background(), wd.XDomainTarget, nil)
if err != nil { if err != nil {
return err log.Error("error getting target balance after", "err", err)
return
} }
diff := new(big.Int).Sub(targetBalAfter, targetBalBefore) diff := new(big.Int).Sub(targetBalAfter, targetBalBefore)
...@@ -447,20 +606,79 @@ func main() { ...@@ -447,20 +606,79 @@ func main() {
isSuccessNewPost, err = contracts.L1CrossDomainMessenger.SuccessfulMessages(&bind.CallOpts{}, xdmHash) isSuccessNewPost, err = contracts.L1CrossDomainMessenger.SuccessfulMessages(&bind.CallOpts{}, xdmHash)
if err != nil { if err != nil {
return err log.Error("error getting success", "err", err)
return
} }
if diff.Cmp(wdValue) != 0 && isSuccessNewPost && isSuccess { if diff.Cmp(wdValue) != 0 && isSuccessNewPost && isSuccess {
log.Info("native eth balance diff mismatch", "index", i, "diff", diff, "val", wdValue) log.Info("native eth balance diff mismatch", "index", i, "diff", diff, "val", wdValue)
if err := writeSuspicious(f, withdrawal, wd, finalizationTrace, i, "balance mismatch"); err != nil { if err := writeSuspicious(f, withdrawal, wd, finalizationTrace, i, "balance mismatch"); err != nil {
return err log.Error("error writing suspicious withdrawal", "err", err)
return
} }
continue return
} }
} else { } else {
log.Info("Already finalized") log.Info("Already finalized")
} }
} }
getBaseFee := func() (*big.Int, error) {
block, err := clients.L1Client.BlockByNumber(context.Background(), nil)
if err != nil {
return nil, err
}
baseFee := misc.CalcBaseFee(params.MainnetChainConfig, block.Header())
baseFee = baseFee.Add(baseFee, big.NewInt(10_000_000_000))
return baseFee, nil
}
batchTxs := func(cb func(*crossdomain.LegacyWithdrawal, *big.Int, int)) error {
sem := make(chan struct{}, batchSize)
var bf *big.Int
var err error
for i, wd := range wds {
if i == 0 || i%batchSize == 0 {
bf, err = getBaseFee()
if err != nil {
return err
}
}
if i%5 == 0 {
log.Info("kicking off batch transaction", "i", i, "len", len(wds))
}
sem <- struct{}{}
go func(wd *crossdomain.LegacyWithdrawal, bf *big.Int, i int) {
defer func() { <-sem }()
cb(wd, bf, i)
// Avoid hammering Cloudflare/our infrastructure too much
time.Sleep(50*time.Millisecond + time.Duration(rand.Intn(100))*time.Millisecond)
}(wd, bf, i)
}
return nil
}
if err := batchTxs(proveWithdrawals); err != nil {
return err
}
// Now that all of the withdrawals have been proven, we can finalize them.
// Note that we assume that the finalization period is low enough that
// we can finalize all of the withdrawals shortly after they have been proven.
log.Info("All withdrawals have been proven! Moving on to finalization.")
// Loop through withdrawals (`batchSize` wds at a time) and finalize each batch in parallel.
if err := batchTxs(finalizeWithdrawals); err != nil {
return err
}
return nil return nil
}, },
} }
...@@ -634,7 +852,7 @@ func handleFinalizeERC20Withdrawal(args []any, receipt *types.Receipt, l1Standar ...@@ -634,7 +852,7 @@ func handleFinalizeERC20Withdrawal(args []any, receipt *types.Receipt, l1Standar
// proveWithdrawalTransaction will build the data required for proving a // proveWithdrawalTransaction will build the data required for proving a
// withdrawal and then send the transaction and make sure that it is included // withdrawal and then send the transaction and make sure that it is included
// and successful and then wait for the finalization period to elapse. // and successful and then wait for the finalization period to elapse.
func proveWithdrawalTransaction(c *contracts, cl *util.Clients, opts *bind.TransactOpts, withdrawal *crossdomain.Withdrawal, bn, finalizationPeriod *big.Int) error { func proveWithdrawalTransaction(c *contracts, cl *util.Clients, opts *bind.TransactOpts, withdrawal *crossdomain.Withdrawal, bn *big.Int) error {
l2OutputIndex, outputRootProof, trieNodes, err := createOutput(withdrawal, c.L2OutputOracle, bn, cl) l2OutputIndex, outputRootProof, trieNodes, err := createOutput(withdrawal, c.L2OutputOracle, bn, cl)
if err != nil { if err != nil {
return err return err
...@@ -653,11 +871,12 @@ func proveWithdrawalTransaction(c *contracts, cl *util.Clients, opts *bind.Trans ...@@ -653,11 +871,12 @@ func proveWithdrawalTransaction(c *contracts, cl *util.Clients, opts *bind.Trans
outputRootProof, outputRootProof,
trieNodes, trieNodes,
) )
if err != nil { if err != nil {
return err return err
} }
log.Info("proving withdrawal", "tx-hash", tx.Hash(), "nonce", tx.Nonce())
receipt, err := bind.WaitMined(context.Background(), cl.L1Client, tx) receipt, err := bind.WaitMined(context.Background(), cl.L1Client, tx)
if err != nil { if err != nil {
return err return err
...@@ -667,24 +886,6 @@ func proveWithdrawalTransaction(c *contracts, cl *util.Clients, opts *bind.Trans ...@@ -667,24 +886,6 @@ func proveWithdrawalTransaction(c *contracts, cl *util.Clients, opts *bind.Trans
} }
log.Info("withdrawal proved", "tx-hash", tx.Hash(), "withdrawal-hash", hash) log.Info("withdrawal proved", "tx-hash", tx.Hash(), "withdrawal-hash", hash)
block, err := cl.L1Client.BlockByHash(context.Background(), receipt.BlockHash)
if err != nil {
return err
}
initialTime := block.Time()
for {
log.Info("waiting for finalization")
if block.Time() >= initialTime+finalizationPeriod.Uint64() {
log.Info("can be finalized")
break
}
time.Sleep(1 * time.Second)
block, err = cl.L1Client.BlockByNumber(context.Background(), nil)
if err != nil {
return err
}
}
return nil return nil
} }
...@@ -696,6 +897,14 @@ func finalizeWithdrawalTransaction( ...@@ -696,6 +897,14 @@ func finalizeWithdrawalTransaction(
withdrawal *crossdomain.Withdrawal, withdrawal *crossdomain.Withdrawal,
) (*types.Receipt, error) { ) (*types.Receipt, error) {
if wd.XDomainTarget == (common.Address{}) { if wd.XDomainTarget == (common.Address{}) {
log.Warn(
"nil withdrawal target",
"xTarget", wd.XDomainTarget,
"xData", wd.XDomainData,
"xNonce", wd.XDomainNonce,
"xSender", wd.XDomainSender,
"sender", wd.MessageSender,
)
return nil, errors.New("withdrawal target is nil, should never happen") return nil, errors.New("withdrawal target is nil, should never happen")
} }
......
...@@ -27,24 +27,22 @@ var Mainnet = rollup.Config{ ...@@ -27,24 +27,22 @@ var Mainnet = rollup.Config{
// moose: Update this during migration // moose: Update this during migration
L2Time: 0, L2Time: 0,
SystemConfig: eth.SystemConfig{ SystemConfig: eth.SystemConfig{
BatcherAddr: common.HexToAddress("0x70997970C51812dc3A010C7d01b50e0d17dc79C8"), BatcherAddr: common.HexToAddress("0x6887246668a3b87f54deb3b94ba47a6f63f32985"),
Overhead: eth.Bytes32(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000834")), Overhead: eth.Bytes32(common.HexToHash("0x00000000000000000000000000000000000000000000000000000000000000bc")),
Scalar: eth.Bytes32(common.HexToHash("0x00000000000000000000000000000000000000000000000000000000000f4240")), Scalar: eth.Bytes32(common.HexToHash("0x00000000000000000000000000000000000000000000000000000000000a6fe0")),
GasLimit: 25_000_000, GasLimit: 30_000_000,
}, },
}, },
BlockTime: 2, BlockTime: 2,
MaxSequencerDrift: 600, MaxSequencerDrift: 600,
SeqWindowSize: 3600, SeqWindowSize: 3600,
ChannelTimeout: 300, ChannelTimeout: 300,
L1ChainID: big.NewInt(1), L1ChainID: big.NewInt(1),
L2ChainID: big.NewInt(10), L2ChainID: big.NewInt(10),
BatchInboxAddress: common.HexToAddress("0xff00000000000000000000000000000000000010"), BatchInboxAddress: common.HexToAddress("0xff00000000000000000000000000000000000010"),
// moose: Update this during migration DepositContractAddress: common.HexToAddress("0xbEb5Fc579115071764c7423A4f12eDde41f106Ed"),
DepositContractAddress: common.HexToAddress("0x"), L1SystemConfigAddress: common.HexToAddress("0x229047fed2591dbec1eF1118d64F7aF3dB9EB290"),
// moose: Update this during migration RegolithTime: u64Ptr(0),
L1SystemConfigAddress: common.HexToAddress("0x"),
RegolithTime: u64Ptr(0),
} }
var Goerli = rollup.Config{ var Goerli = rollup.Config{
......
...@@ -22,6 +22,5 @@ import mainnetJson from './mainnet.json' ...@@ -22,6 +22,5 @@ import mainnetJson from './mainnet.json'
// //
// The following role is assigned to the Mint Manager contract: // The following role is assigned to the Mint Manager contract:
// - governanceTokenOwner // - governanceTokenOwner
const config: DeployConfig = mainnetJson
export default config export default mainnetJson satisfies DeployConfig
...@@ -9,13 +9,9 @@ const deployFn: DeployFunction = async (hre) => { ...@@ -9,13 +9,9 @@ const deployFn: DeployFunction = async (hre) => {
throw new Error( throw new Error(
'L2OutputOracle deployment: l2BlockTime must be greater than 0' 'L2OutputOracle deployment: l2BlockTime must be greater than 0'
) )
} else if ( }
hre.deployConfig.l2OutputOracleSubmissionInterval <= if (hre.deployConfig.l2OutputOracleSubmissionInterval === 0) {
hre.deployConfig.l2BlockTime throw new Error('L2OutputOracle deployment: submissionInterval cannot be 0')
) {
throw new Error(
'L2OutputOracle deployment: submissionInterval must be greater than the l2BlockTime'
)
} }
await deploy({ await deploy({
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -38,10 +38,15 @@ const checkPredeploys = async ( ...@@ -38,10 +38,15 @@ const checkPredeploys = async (
predeploys.ProxyAdmin, predeploys.ProxyAdmin,
]) ])
// We only check predeploys 0x420..00 through 0x420..FF on the mainnet network to
// reduce the probability of an RPC timeout. After the migration, all predeploys
// from 0x420..00 through 0x420..07FF should be checked.
const maxCheck = hre.network.name === 'mainnet' ? 256 : 2048
const codeReq = [] const codeReq = []
const slotReq = [] const slotReq = []
// First loop for requests // First loop for requests
for (let i = 0; i < 2048; i++) { for (let i = 0; i < maxCheck; i++) {
const num = hre.ethers.utils.hexZeroPad('0x' + i.toString(16), 2) const num = hre.ethers.utils.hexZeroPad('0x' + i.toString(16), 2)
const addr = hre.ethers.utils.getAddress( const addr = hre.ethers.utils.getAddress(
hre.ethers.utils.hexConcat([prefix, num]) hre.ethers.utils.hexConcat([prefix, num])
...@@ -57,7 +62,7 @@ const checkPredeploys = async ( ...@@ -57,7 +62,7 @@ const checkPredeploys = async (
const slotRes = await Promise.all(slotReq) const slotRes = await Promise.all(slotReq)
// Second loop for response checks // Second loop for response checks
for (let i = 0; i < 2048; i++) { for (let i = 0; i < maxCheck; i++) {
const num = hre.ethers.utils.hexZeroPad('0x' + i.toString(16), 2) const num = hre.ethers.utils.hexZeroPad('0x' + i.toString(16), 2)
const addr = hre.ethers.utils.getAddress( const addr = hre.ethers.utils.getAddress(
hre.ethers.utils.hexConcat([prefix, num]) hre.ethers.utils.hexConcat([prefix, num])
...@@ -79,7 +84,7 @@ const checkPredeploys = async ( ...@@ -79,7 +84,7 @@ const checkPredeploys = async (
throw new Error(`incorrect admin slot in ${addr}`) throw new Error(`incorrect admin slot in ${addr}`)
} }
if (i % 200 === 0) { if (i % (maxCheck / 4) === 0) {
console.log(`Checked through ${addr}`) console.log(`Checked through ${addr}`)
} }
} }
...@@ -186,7 +191,16 @@ const checkGenesisMagic = async ( ...@@ -186,7 +191,16 @@ const checkGenesisMagic = async (
const L2OutputOracle = new hre.ethers.Contract(address, [abi], l1Provider) const L2OutputOracle = new hre.ethers.Contract(address, [abi], l1Provider)
startingBlockNumber = await L2OutputOracle.startingBlockNumber() // In the migration, the L2OutputOracle proxy is not yet initialized when we
// want to run this script. Fall back on the local config if we get an error
// fetching the starting block number.
try {
startingBlockNumber = await L2OutputOracle.startingBlockNumber()
} catch (e) {
console.log(`Error fetching startingBlockNumber:\n${e.message}`)
console.log('Falling back to local config.')
startingBlockNumber = hre.deployConfig.l2OutputOracleStartingBlockNumber
}
} else { } else {
// We do not have a connection to the L1 chain, use the local config // We do not have a connection to the L1 chain, use the local config
// The `--network` flag must be set to the L1 network // The `--network` flag must be set to the L1 network
...@@ -200,7 +214,9 @@ const checkGenesisMagic = async ( ...@@ -200,7 +214,9 @@ const checkGenesisMagic = async (
const extradata = block.extraData const extradata = block.extraData
if (extradata !== magic) { if (extradata !== magic) {
throw new Error('magic value in extradata does not match') throw new Error(
`magic value in extradata does not match: got ${extradata}, expected ${magic}`
)
} }
} }
......
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