Commit de9a9a16 authored by Mark Tyneway's avatar Mark Tyneway

op-chain-ops: cleanup

parent 5c224f2b
...@@ -14,7 +14,6 @@ import ( ...@@ -14,7 +14,6 @@ import (
"github.com/mattn/go-isatty" "github.com/mattn/go-isatty"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"github.com/ethereum-optimism/optimism/l2geth/common/hexutil"
"github.com/ethereum-optimism/optimism/op-bindings/bindings" "github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys" "github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum-optimism/optimism/op-chain-ops/crossdomain" "github.com/ethereum-optimism/optimism/op-chain-ops/crossdomain"
...@@ -22,6 +21,7 @@ import ( ...@@ -22,6 +21,7 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/eth/tracers"
...@@ -46,6 +46,8 @@ type callFrame struct { ...@@ -46,6 +46,8 @@ type callFrame struct {
Calls []callFrame `json:"calls,omitempty"` Calls []callFrame `json:"calls,omitempty"`
} }
// findWithdrawalCall will find the call frame for the call that
// represents the user's intent.
func findWithdrawalCall(trace *callFrame, wd *crossdomain.LegacyWithdrawal, l1xdm common.Address) *callFrame { func findWithdrawalCall(trace *callFrame, wd *crossdomain.LegacyWithdrawal, l1xdm common.Address) *callFrame {
isCall := trace.Type == "CALL" isCall := trace.Type == "CALL"
isTarget := common.HexToAddress(trace.To) == *wd.Target isTarget := common.HexToAddress(trace.To) == *wd.Target
...@@ -61,6 +63,8 @@ func findWithdrawalCall(trace *callFrame, wd *crossdomain.LegacyWithdrawal, l1xd ...@@ -61,6 +63,8 @@ func findWithdrawalCall(trace *callFrame, wd *crossdomain.LegacyWithdrawal, l1xd
return nil return nil
} }
// createOutput will create the data required to send a withdrawal
// transaction.
func createOutput( func createOutput(
withdrawal *crossdomain.Withdrawal, withdrawal *crossdomain.Withdrawal,
oracle *bindings.L2OutputOracle, oracle *bindings.L2OutputOracle,
...@@ -68,15 +72,18 @@ func createOutput( ...@@ -68,15 +72,18 @@ func createOutput(
l2Client bind.ContractBackend, l2Client bind.ContractBackend,
l2GethClient *gethclient.Client, l2GethClient *gethclient.Client,
) (*big.Int, bindings.TypesOutputRootProof, [][]byte, error) { ) (*big.Int, bindings.TypesOutputRootProof, [][]byte, error) {
// compute the storage slot that the withdrawal is stored in
slot, err := withdrawal.StorageSlot() slot, err := withdrawal.StorageSlot()
if err != nil { if err != nil {
return nil, bindings.TypesOutputRootProof{}, nil, err return nil, bindings.TypesOutputRootProof{}, nil, err
} }
// find the output index that the withdrawal was commited to in
l2OutputIndex, err := oracle.GetL2OutputIndexAfter(&bind.CallOpts{}, blockNumber) l2OutputIndex, err := oracle.GetL2OutputIndexAfter(&bind.CallOpts{}, blockNumber)
if err != nil { if err != nil {
return nil, bindings.TypesOutputRootProof{}, nil, err return nil, bindings.TypesOutputRootProof{}, nil, err
} }
// fetch the output the commits to the withdrawal using the index
l2Output, err := oracle.GetL2Output(&bind.CallOpts{}, l2OutputIndex) l2Output, err := oracle.GetL2Output(&bind.CallOpts{}, l2OutputIndex)
if err != nil { if err != nil {
return nil, bindings.TypesOutputRootProof{}, nil, err return nil, bindings.TypesOutputRootProof{}, nil, err
...@@ -90,11 +97,13 @@ func createOutput( ...@@ -90,11 +97,13 @@ func createOutput(
"timestamp", l2Output.Timestamp, "timestamp", l2Output.Timestamp,
) )
// get the block header committed to in the output
header, err := l2Client.HeaderByNumber(context.Background(), l2Output.L2BlockNumber) header, err := l2Client.HeaderByNumber(context.Background(), l2Output.L2BlockNumber)
if err != nil { if err != nil {
return nil, bindings.TypesOutputRootProof{}, nil, err return nil, bindings.TypesOutputRootProof{}, nil, err
} }
// get the storage proof for the withdrawal's storage slot
proof, err := l2GethClient.GetProof(context.Background(), predeploys.L2ToL1MessagePasserAddr, []string{slot.String()}, blockNumber) proof, err := l2GethClient.GetProof(context.Background(), predeploys.L2ToL1MessagePasserAddr, []string{slot.String()}, blockNumber)
if err != nil { if err != nil {
return nil, bindings.TypesOutputRootProof{}, nil, err return nil, bindings.TypesOutputRootProof{}, nil, err
...@@ -107,6 +116,7 @@ func createOutput( ...@@ -107,6 +116,7 @@ func createOutput(
trieNodes[i] = common.FromHex(s) trieNodes[i] = common.FromHex(s)
} }
// create an output root proof
outputRootProof := bindings.TypesOutputRootProof{ outputRootProof := bindings.TypesOutputRootProof{
Version: [32]byte{}, Version: [32]byte{},
StateRoot: header.Root, StateRoot: header.Root,
...@@ -114,6 +124,7 @@ func createOutput( ...@@ -114,6 +124,7 @@ func createOutput(
LatestBlockhash: header.Hash(), LatestBlockhash: header.Hash(),
} }
// compute a storage root hash locally
localOutputRootHash := crypto.Keccak256Hash( localOutputRootHash := crypto.Keccak256Hash(
outputRootProof.Version[:], outputRootProof.Version[:],
outputRootProof.StateRoot[:], outputRootProof.StateRoot[:],
...@@ -121,6 +132,7 @@ func createOutput( ...@@ -121,6 +132,7 @@ func createOutput(
outputRootProof.LatestBlockhash[:], outputRootProof.LatestBlockhash[:],
) )
// ensure that the locally computed hash matches
if l2Output.OutputRoot != localOutputRootHash { if l2Output.OutputRoot != localOutputRootHash {
return nil, bindings.TypesOutputRootProof{}, nil, fmt.Errorf("mismatch in output root hashes", "got", localOutputRootHash, "expect", l2Output.OutputRoot) return nil, bindings.TypesOutputRootProof{}, nil, fmt.Errorf("mismatch in output root hashes", "got", localOutputRootHash, "expect", l2Output.OutputRoot)
} }
...@@ -187,6 +199,7 @@ func main() { ...@@ -187,6 +199,7 @@ func main() {
}, },
}, },
Action: func(ctx *cli.Context) error { Action: func(ctx *cli.Context) error {
// set up the rpc clients
l1RpcURL := ctx.String("l1-rpc-url") l1RpcURL := ctx.String("l1-rpc-url")
l1Client, err := ethclient.Dial(l1RpcURL) l1Client, err := ethclient.Dial(l1RpcURL)
if err != nil { if err != nil {
...@@ -219,8 +232,11 @@ func main() { ...@@ -219,8 +232,11 @@ func main() {
if err != nil { if err != nil {
return err return err
} }
// this script requires geth's rpcs
gclient := gethclient.New(l2RpcClient) gclient := gethclient.New(l2RpcClient)
// get the evm and ovm messages witness files used as part of
// migration
ovmMsgs := ctx.String("ovm-messages") ovmMsgs := ctx.String("ovm-messages")
evmMsgs := ctx.String("evm-messages") evmMsgs := ctx.String("evm-messages")
...@@ -245,6 +261,7 @@ func main() { ...@@ -245,6 +261,7 @@ func main() {
EvmMessages: evmMessages, EvmMessages: evmMessages,
} }
// create the set of withdrawals
wds, err := migrationData.ToWithdrawals() wds, err := migrationData.ToWithdrawals()
if err != nil { if err != nil {
return err return err
...@@ -311,19 +328,21 @@ func main() { ...@@ -311,19 +328,21 @@ func main() {
badWithdrawals := make([]badWithdrawal, 0) badWithdrawals := make([]badWithdrawal, 0)
// iterate over all of the withdrawals and submit them
for i, wd := range wds { for i, wd := range wds {
log.Info("Processing withdrawal", "index", i) log.Info("Processing withdrawal", "index", i)
// migrate the withdrawal
withdrawal, err := crossdomain.MigrateWithdrawal(wd, &l1xdmAddr) withdrawal, err := crossdomain.MigrateWithdrawal(wd, &l1xdmAddr)
if err != nil { if err != nil {
return err return err
} }
// compute the withdrawal hash
hash, err := withdrawal.Hash() hash, err := withdrawal.Hash()
if err != nil { if err != nil {
return err return err
} }
// check to see if the withdrawal has already been successfully
// relayed or received
isSuccess, err := l1CrossDomainMessenger.SuccessfulMessages(&bind.CallOpts{}, hash) isSuccess, err := l1CrossDomainMessenger.SuccessfulMessages(&bind.CallOpts{}, hash)
if err != nil { if err != nil {
return err return err
...@@ -332,7 +351,7 @@ func main() { ...@@ -332,7 +351,7 @@ func main() {
if err != nil { if err != nil {
return err return err
} }
// compute the storage slot
slot, err := withdrawal.StorageSlot() slot, err := withdrawal.StorageSlot()
if err != nil { if err != nil {
return err return err
...@@ -340,11 +359,14 @@ func main() { ...@@ -340,11 +359,14 @@ func main() {
log.Info("cross domain messenger status", "hash", hash.Hex(), "success", isSuccess, "received", isReceived, "slot", slot.Hex()) log.Info("cross domain messenger status", "hash", hash.Hex(), "success", isSuccess, "received", isReceived, "slot", slot.Hex())
// successful messages can be skipped, received messages failed
// their execution and should be replayed
if isSuccess { if isSuccess {
log.Info("Message already relayed", "index", i, "hash", hash, "slot", slot) log.Info("Message already relayed", "index", i, "hash", hash, "slot", slot)
continue continue
} }
// create the values required for submitting a proof
l2OutputIndex, outputRootProof, trieNodes, err := createOutput(withdrawal, oracle, transitionBlockNumber, l2Client, gclient) l2OutputIndex, outputRootProof, trieNodes, err := createOutput(withdrawal, oracle, transitionBlockNumber, l2Client, gclient)
if err != nil { if err != nil {
return err return err
...@@ -355,6 +377,7 @@ func main() { ...@@ -355,6 +377,7 @@ func main() {
return err return err
} }
// check to see if its already been proven
proven, err := portal.ProvenWithdrawals(&bind.CallOpts{}, hash) proven, err := portal.ProvenWithdrawals(&bind.CallOpts{}, hash)
if err != nil { if err != nil {
return err return err
...@@ -410,6 +433,7 @@ func main() { ...@@ -410,6 +433,7 @@ func main() {
log.Info("Withdrawal already proven to OptimismPortal") log.Info("Withdrawal already proven to OptimismPortal")
} }
// check to see if the withdrawal has been finalized already
isFinalized, err := portal.FinalizedWithdrawals(&bind.CallOpts{}, hash) isFinalized, err := portal.FinalizedWithdrawals(&bind.CallOpts{}, hash)
if err != nil { if err != nil {
return err return err
...@@ -493,29 +517,30 @@ func main() { ...@@ -493,29 +517,30 @@ func main() {
switch method.Name { switch method.Name {
case "finalizeERC20Withdrawal": case "finalizeERC20Withdrawal":
// Handle logic for ERC20 withdrawals
l1Token, ok := args[0].(common.Address) l1Token, ok := args[0].(common.Address)
if !ok { if !ok {
return fmt.Errorf("") return fmt.Errorf("invalid abi")
} }
l2Token, ok := args[1].(common.Address) l2Token, ok := args[1].(common.Address)
if !ok { if !ok {
return fmt.Errorf("") return fmt.Errorf("invalid abi")
} }
from, ok := args[2].(common.Address) from, ok := args[2].(common.Address)
if !ok { if !ok {
return fmt.Errorf("") return fmt.Errorf("invalid abi")
} }
to, ok := args[3].(common.Address) to, ok := args[3].(common.Address)
if !ok { if !ok {
return fmt.Errorf("") return fmt.Errorf("invalid abi")
} }
amount, ok := args[4].(*big.Int) amount, ok := args[4].(*big.Int)
if !ok { if !ok {
return fmt.Errorf("") return fmt.Errorf("invalid abi")
} }
extraData, ok := args[5].([]byte) extraData, ok := args[5].([]byte)
if !ok { if !ok {
return fmt.Errorf("") return fmt.Errorf("invalid abi")
} }
log.Info( log.Info(
...@@ -533,14 +558,13 @@ func main() { ...@@ -533,14 +558,13 @@ func main() {
topic := l.Topics[0] topic := l.Topics[0]
if topic == transferEvent.ID { if topic == transferEvent.ID {
a, _ := transferEvent.Inputs.Unpack(l.Data) a, _ := transferEvent.Inputs.Unpack(l.Data)
// TODO: add a check here for balance diff as // TODO: add a check here for balance diff
// expected
log.Info("EVENT FOUND", "args", a) log.Info("EVENT FOUND", "args", a)
} }
log.Info("receipt topic", "hex", topic.Hex()) log.Info("receipt topic", "hex", topic.Hex())
} }
case "finalizeETHWithdrawal": case "finalizeETHWithdrawal":
// handle logic for ETH withdrawals
from, ok := args[0].(common.Address) from, ok := args[0].(common.Address)
if !ok { if !ok {
return fmt.Errorf("invalid type: from") return fmt.Errorf("invalid type: from")
...@@ -589,7 +613,7 @@ func main() { ...@@ -589,7 +613,7 @@ func main() {
}) })
} }
// check that the user's intents are actually executed
if common.HexToAddress(callFrame.To) != *wd.Target { if common.HexToAddress(callFrame.To) != *wd.Target {
badWithdrawals = append(badWithdrawals, badWithdrawal{ badWithdrawals = append(badWithdrawals, badWithdrawal{
Withdrawal: withdrawal, Withdrawal: withdrawal,
......
#!/bin/sh
# Get relative directory of this script
SCRIPT_DIR="$( dirname -- ${BASH_SOURCE[0]} )"
# -- RPCs --
L1_RPC="https://goerli-l1-8104952.optimism.io"
L2_RPC="https://goerli-3319642-sequencer.optimism.io"
# -- Message File Paths --
OVM_MESSAGES="$SCRIPT_DIR/data/messages/ovm-messages.json"
EVM_MESSAGES="$SCRIPT_DIR/data/messages/evm-messages.json"
# -- Contracts --
PORTAL="0x7db2f4b1f880257a99e024647cead4e3ad63b665"
L1XDM="0x5086d1eef304eb5284a0f6720f79403b4e9be294"
L1BRIDGE="0x636Af16bf2f682dD3109e60102b8E1A089FedAa8"
# -- Genesis Block --
L2GENESIS=3319643
# -- Account --
# Pub Key: 0x4F3278d9FF0426E4b60653bee23D0a768E700672
SECRET="$(cat $SCRIPT_DIR/.secret)"
# Extract messages tar
tar -xvf $SCRIPT_DIR/data/messages.tgz -C $SCRIPT_DIR/data
# Run built withdrawals binary
go run $SCRIPT_DIR/main.go \
--l1-rpc-url $L1_RPC \
--l2-rpc-url $L2_RPC \
--ovm-messages $OVM_MESSAGES \
--evm-messages $EVM_MESSAGES \
--optimism-portal-address $PORTAL \
--l1-crossdomain-messenger-address $L1XDM \
--l1-standard-bridge-address $L1BRIDGE \
--bedrock-transition-block-number $L2GENESIS \
--private-key $SECRET
# Delete message JSON files
rm -rf $SCRIPT_DIR/data/messages
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