Commit f08501a0 authored by Matthew Slipper's avatar Matthew Slipper

op-chain-ops: Correctly filter withdrawal hashes

Since we're checking every slot in the legacy message passer, we need to pass in the full list of messages to the message passer for verification purposes then filter out messages from senders other than the L2XDM prior to executing the withdrawals migration. This PR fixes the filtering, and adds a check in the withdrawals post-check step to make sure that no potentially fraudulent withdrawals get migrated.

Fixes CLI-3379
parent 73e4bf88
...@@ -284,11 +284,11 @@ func main() { ...@@ -284,11 +284,11 @@ func main() {
if !isFinalized { if !isFinalized {
// 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.Target, nil) targetBalBefore, err := clients.L1Client.BalanceAt(context.Background(), wd.XDomainTarget, nil)
if err != nil { if err != nil {
return err return err
} }
log.Debug("Balance before finalization", "balance", targetBalBefore, "account", *wd.Target) 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) receipt, err := finalizeWithdrawalTransaction(contracts, clients, opts, wd, withdrawal)
...@@ -369,14 +369,14 @@ func main() { ...@@ -369,14 +369,14 @@ func main() {
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.Target, "data", hexutil.Encode(wd.Data)) 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 return err
} }
} }
// check that the user's intents are actually executed // check that the user's intents are actually executed
if common.HexToAddress(callFrame.To) != *wd.Target { if common.HexToAddress(callFrame.To) != wd.XDomainTarget {
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 {
...@@ -384,7 +384,7 @@ func main() { ...@@ -384,7 +384,7 @@ func main() {
} }
continue continue
} }
if !bytes.Equal(hexutil.MustDecode(callFrame.Input), wd.Data) { 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 {
...@@ -401,7 +401,7 @@ func main() { ...@@ -401,7 +401,7 @@ func main() {
} }
// 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.Target, nil) targetBalAfter, err := clients.L1Client.BalanceAt(context.Background(), wd.XDomainTarget, nil)
if err != nil { if err != nil {
return err return err
} }
...@@ -621,7 +621,7 @@ func finalizeWithdrawalTransaction( ...@@ -621,7 +621,7 @@ func finalizeWithdrawalTransaction(
wd *crossdomain.LegacyWithdrawal, wd *crossdomain.LegacyWithdrawal,
withdrawal *crossdomain.Withdrawal, withdrawal *crossdomain.Withdrawal,
) (*types.Receipt, error) { ) (*types.Receipt, error) {
if wd.Target == nil { if wd.XDomainTarget == (common.Address{}) {
return nil, errors.New("withdrawal target is nil, should never happen") return nil, errors.New("withdrawal target is nil, should never happen")
} }
...@@ -833,7 +833,7 @@ func newTransactor(ctx *cli.Context) (*bind.TransactOpts, error) { ...@@ -833,7 +833,7 @@ func newTransactor(ctx *cli.Context) (*bind.TransactOpts, error) {
// represents the user's intent. // 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.XDomainTarget
isFrom := common.HexToAddress(trace.From) == l1xdm isFrom := common.HexToAddress(trace.From) == l1xdm
if isCall && isTarget && isFrom { if isCall && isTarget && isFrom {
return trace return trace
......
...@@ -37,8 +37,8 @@ func init() { ...@@ -37,8 +37,8 @@ func init() {
// EncodeCrossDomainMessageV0 will encode the calldata for // EncodeCrossDomainMessageV0 will encode the calldata for
// "relayMessage(address,address,bytes,uint256)", // "relayMessage(address,address,bytes,uint256)",
func EncodeCrossDomainMessageV0( func EncodeCrossDomainMessageV0(
target *common.Address, target common.Address,
sender *common.Address, sender common.Address,
message []byte, message []byte,
nonce *big.Int, nonce *big.Int,
) ([]byte, error) { ) ([]byte, error) {
...@@ -49,8 +49,8 @@ func EncodeCrossDomainMessageV0( ...@@ -49,8 +49,8 @@ func EncodeCrossDomainMessageV0(
// "relayMessage(uint256,address,address,uint256,uint256,bytes)", // "relayMessage(uint256,address,address,uint256,uint256,bytes)",
func EncodeCrossDomainMessageV1( func EncodeCrossDomainMessageV1(
nonce *big.Int, nonce *big.Int,
sender *common.Address, sender common.Address,
target *common.Address, target common.Address,
value *big.Int, value *big.Int,
gasLimit *big.Int, gasLimit *big.Int,
data []byte, data []byte,
......
...@@ -10,8 +10,8 @@ import ( ...@@ -10,8 +10,8 @@ import (
// HashCrossDomainMessageV0 computes the pre bedrock cross domain messaging // HashCrossDomainMessageV0 computes the pre bedrock cross domain messaging
// hashing scheme. // hashing scheme.
func HashCrossDomainMessageV0( func HashCrossDomainMessageV0(
target *common.Address, target common.Address,
sender *common.Address, sender common.Address,
data []byte, data []byte,
nonce *big.Int, nonce *big.Int,
) (common.Hash, error) { ) (common.Hash, error) {
...@@ -27,8 +27,8 @@ func HashCrossDomainMessageV0( ...@@ -27,8 +27,8 @@ func HashCrossDomainMessageV0(
// messaging hashing scheme. // messaging hashing scheme.
func HashCrossDomainMessageV1( func HashCrossDomainMessageV1(
nonce *big.Int, nonce *big.Int,
sender *common.Address, sender common.Address,
target *common.Address, target common.Address,
value *big.Int, value *big.Int,
gasLimit *big.Int, gasLimit *big.Int,
data []byte, data []byte,
......
...@@ -16,21 +16,28 @@ import ( ...@@ -16,21 +16,28 @@ import (
// LegacyWithdrawal represents a pre bedrock upgrade withdrawal. // LegacyWithdrawal represents a pre bedrock upgrade withdrawal.
type LegacyWithdrawal struct { type LegacyWithdrawal struct {
Target *common.Address `json:"target"` // MessageSender is the caller of the message passer
Sender *common.Address `json:"sender"` MessageSender common.Address `json:"who"`
Data hexutil.Bytes `json:"data"` // XDomainTarget is the L1 target of the withdrawal message
Nonce *big.Int `json:"nonce"` XDomainTarget common.Address `json:"target"`
// XDomainSender is the L2 withdrawing account
XDomainSender common.Address `json:"sender"`
// XDomainData represents the calldata of the withdrawal message
XDomainData hexutil.Bytes `json:"data"`
// XDomainNonce represents the nonce of the withdrawal
XDomainNonce *big.Int `json:"nonce"`
} }
var _ WithdrawalMessage = (*LegacyWithdrawal)(nil) var _ WithdrawalMessage = (*LegacyWithdrawal)(nil)
// NewLegacyWithdrawal will construct a LegacyWithdrawal // NewLegacyWithdrawal will construct a LegacyWithdrawal
func NewLegacyWithdrawal(target, sender *common.Address, data []byte, nonce *big.Int) *LegacyWithdrawal { func NewLegacyWithdrawal(msgSender, target, sender common.Address, data []byte, nonce *big.Int) *LegacyWithdrawal {
return &LegacyWithdrawal{ return &LegacyWithdrawal{
Target: target, MessageSender: msgSender,
Sender: sender, XDomainTarget: target,
Data: data, XDomainSender: sender,
Nonce: nonce, XDomainData: data,
XDomainNonce: nonce,
} }
} }
...@@ -39,7 +46,7 @@ func NewLegacyWithdrawal(target, sender *common.Address, data []byte, nonce *big ...@@ -39,7 +46,7 @@ func NewLegacyWithdrawal(target, sender *common.Address, data []byte, nonce *big
// through the standard optimism cross domain messaging system by hashing in // through the standard optimism cross domain messaging system by hashing in
// the L2CrossDomainMessenger address. // the L2CrossDomainMessenger address.
func (w *LegacyWithdrawal) Encode() ([]byte, error) { func (w *LegacyWithdrawal) Encode() ([]byte, error) {
enc, err := EncodeCrossDomainMessageV0(w.Target, w.Sender, []byte(w.Data), w.Nonce) enc, err := EncodeCrossDomainMessageV0(w.XDomainTarget, w.XDomainSender, []byte(w.XDomainData), w.XDomainNonce)
if err != nil { if err != nil {
return nil, fmt.Errorf("cannot encode LegacyWithdrawal: %w", err) return nil, fmt.Errorf("cannot encode LegacyWithdrawal: %w", err)
} }
...@@ -62,9 +69,6 @@ func (w *LegacyWithdrawal) Decode(data []byte) error { ...@@ -62,9 +69,6 @@ func (w *LegacyWithdrawal) Decode(data []byte) error {
} }
msgSender := data[len(data)-len(predeploys.L2CrossDomainMessengerAddr):] msgSender := data[len(data)-len(predeploys.L2CrossDomainMessengerAddr):]
if !bytes.Equal(msgSender, predeploys.L2CrossDomainMessengerAddr.Bytes()) {
return errors.New("invalid msg.sender")
}
raw := data[4 : len(data)-len(predeploys.L2CrossDomainMessengerAddr)] raw := data[4 : len(data)-len(predeploys.L2CrossDomainMessengerAddr)]
...@@ -97,10 +101,11 @@ func (w *LegacyWithdrawal) Decode(data []byte) error { ...@@ -97,10 +101,11 @@ func (w *LegacyWithdrawal) Decode(data []byte) error {
return errors.New("cannot abi decode nonce") return errors.New("cannot abi decode nonce")
} }
w.Target = &target w.MessageSender = common.BytesToAddress(msgSender)
w.Sender = &sender w.XDomainTarget = target
w.Data = hexutil.Bytes(msgData) w.XDomainSender = sender
w.Nonce = nonce w.XDomainData = msgData
w.XDomainNonce = nonce
return nil return nil
} }
...@@ -142,19 +147,15 @@ func (w *LegacyWithdrawal) Value() (*big.Int, error) { ...@@ -142,19 +147,15 @@ func (w *LegacyWithdrawal) Value() (*big.Int, error) {
value := new(big.Int) value := new(big.Int)
// Parse the 4byte selector // Parse the 4byte selector
method, err := abi.MethodById(w.Data) method, err := abi.MethodById(w.XDomainData)
// If it is an unknown selector, there is no value // If it is an unknown selector, there is no value
if err != nil { if err != nil {
return value, nil return value, nil
} }
if w.Sender == nil { isFromL2StandardBridge := w.XDomainSender == predeploys.L2StandardBridgeAddr
return nil, errors.New("sender is nil")
}
isFromL2StandardBridge := *w.Sender == predeploys.L2StandardBridgeAddr
if isFromL2StandardBridge && method.Name == "finalizeETHWithdrawal" { if isFromL2StandardBridge && method.Name == "finalizeETHWithdrawal" {
data, err := method.Inputs.Unpack(w.Data[4:]) data, err := method.Inputs.Unpack(w.XDomainData[4:])
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -177,11 +178,11 @@ func (w *LegacyWithdrawal) Value() (*big.Int, error) { ...@@ -177,11 +178,11 @@ func (w *LegacyWithdrawal) Value() (*big.Int, error) {
// the concept of value or gaslimit, so set them to 0. // the concept of value or gaslimit, so set them to 0.
func (w *LegacyWithdrawal) CrossDomainMessage() *CrossDomainMessage { func (w *LegacyWithdrawal) CrossDomainMessage() *CrossDomainMessage {
return &CrossDomainMessage{ return &CrossDomainMessage{
Nonce: w.Nonce, Nonce: w.XDomainNonce,
Sender: w.Sender, Sender: w.XDomainSender,
Target: w.Target, Target: w.XDomainTarget,
Value: new(big.Int), Value: new(big.Int),
GasLimit: new(big.Int), GasLimit: new(big.Int),
Data: []byte(w.Data), Data: []byte(w.XDomainData),
} }
} }
...@@ -133,8 +133,7 @@ func TestWithdrawalLegacyStorageSlot(t *testing.T) { ...@@ -133,8 +133,7 @@ func TestWithdrawalLegacyStorageSlot(t *testing.T) {
// Cast the cross domain message to a withdrawal. Note that // Cast the cross domain message to a withdrawal. Note that
// this only works for legacy style messages // this only works for legacy style messages
withdrawal, err := msg.ToWithdrawal() withdrawal := toWithdrawal(t, common.HexToAddress(call.From), msg)
require.Nil(t, err)
// Compute the legacy storage slot for the withdrawal // Compute the legacy storage slot for the withdrawal
slot, err := withdrawal.StorageSlot() slot, err := withdrawal.StorageSlot()
...@@ -160,12 +159,13 @@ func TestWithdrawalLegacyStorageSlot(t *testing.T) { ...@@ -160,12 +159,13 @@ func TestWithdrawalLegacyStorageSlot(t *testing.T) {
} }
func FuzzEncodeDecodeLegacyWithdrawal(f *testing.F) { func FuzzEncodeDecodeLegacyWithdrawal(f *testing.F) {
f.Fuzz(func(t *testing.T, _target, _sender, _nonce, data []byte) { f.Fuzz(func(t *testing.T, _msgSender, _target, _sender, _nonce, data []byte) {
msgSender := common.BytesToAddress(_msgSender)
target := common.BytesToAddress(_target) target := common.BytesToAddress(_target)
sender := common.BytesToAddress(_sender) sender := common.BytesToAddress(_sender)
nonce := new(big.Int).SetBytes(_nonce) nonce := new(big.Int).SetBytes(_nonce)
withdrawal := crossdomain.NewLegacyWithdrawal(&target, &sender, data, nonce) withdrawal := crossdomain.NewLegacyWithdrawal(msgSender, target, sender, data, nonce)
encoded, err := withdrawal.Encode() encoded, err := withdrawal.Encode()
require.Nil(t, err) require.Nil(t, err)
...@@ -174,10 +174,10 @@ func FuzzEncodeDecodeLegacyWithdrawal(f *testing.F) { ...@@ -174,10 +174,10 @@ func FuzzEncodeDecodeLegacyWithdrawal(f *testing.F) {
err = w.Decode(encoded) err = w.Decode(encoded)
require.Nil(t, err) require.Nil(t, err)
require.Equal(t, withdrawal.Nonce.Uint64(), w.Nonce.Uint64()) require.Equal(t, withdrawal.XDomainNonce.Uint64(), w.XDomainNonce.Uint64())
require.Equal(t, withdrawal.Sender, w.Sender) require.Equal(t, withdrawal.XDomainSender, w.XDomainSender)
require.Equal(t, withdrawal.Target, w.Target) require.Equal(t, withdrawal.XDomainTarget, w.XDomainTarget)
require.Equal(t, withdrawal.Data, w.Data) require.Equal(t, withdrawal.XDomainData, w.XDomainData)
}) })
} }
...@@ -221,8 +221,8 @@ func findCrossDomainMessage(receipt *types.Receipt) (*crossdomain.CrossDomainMes ...@@ -221,8 +221,8 @@ func findCrossDomainMessage(receipt *types.Receipt) (*crossdomain.CrossDomainMes
// Parse the legacy event // Parse the legacy event
if event.Name == "SentMessage" { if event.Name == "SentMessage" {
e, _ := l2xdm.ParseSentMessage(*log) e, _ := l2xdm.ParseSentMessage(*log)
msg.Target = &e.Target msg.Target = e.Target
msg.Sender = &e.Sender msg.Sender = e.Sender
msg.Data = e.Message msg.Data = e.Message
msg.Nonce = e.MessageNonce msg.Nonce = e.MessageNonce
msg.GasLimit = e.GasLimit msg.GasLimit = e.GasLimit
...@@ -336,3 +336,30 @@ func readStateDiff(hash string) (stateDiff, error) { ...@@ -336,3 +336,30 @@ func readStateDiff(hash string) (stateDiff, error) {
} }
return diff, nil return diff, nil
} }
// ToWithdrawal will turn a CrossDomainMessage into a Withdrawal.
// This only works for version 0 CrossDomainMessages as not all of
// the data is present for version 1 CrossDomainMessages to be turned
// into Withdrawals.
func toWithdrawal(t *testing.T, msgSender common.Address, c *crossdomain.CrossDomainMessage) *crossdomain.LegacyWithdrawal {
version := c.Version()
switch version {
case 0:
if c.Value != nil && c.Value.Cmp(common.Big0) != 0 {
t.Fatalf("version 0 messages must have 0 value")
}
w := &crossdomain.LegacyWithdrawal{
MessageSender: msgSender,
XDomainTarget: c.Target,
XDomainSender: c.Sender,
XDomainData: c.Data,
XDomainNonce: c.Nonce,
}
return w
case 1:
t.Fatalf("cannot convert version 1 messages to withdrawals")
default:
t.Fatalf("unknown message version: %d", version)
}
return nil
}
package crossdomain package crossdomain
import ( import (
"errors"
"fmt" "fmt"
"math/big" "math/big"
...@@ -14,18 +13,18 @@ import ( ...@@ -14,18 +13,18 @@ import (
// version 1 messages have a value and the most significant // version 1 messages have a value and the most significant
// byte of the nonce is a 1 // byte of the nonce is a 1
type CrossDomainMessage struct { type CrossDomainMessage struct {
Nonce *big.Int `json:"nonce"` Nonce *big.Int `json:"nonce"`
Sender *common.Address `json:"sender"` Sender common.Address `json:"sender"`
Target *common.Address `json:"target"` Target common.Address `json:"target"`
Value *big.Int `json:"value"` Value *big.Int `json:"value"`
GasLimit *big.Int `json:"gasLimit"` GasLimit *big.Int `json:"gasLimit"`
Data []byte `json:"data"` Data []byte `json:"data"`
} }
// NewCrossDomainMessage creates a CrossDomainMessage. // NewCrossDomainMessage creates a CrossDomainMessage.
func NewCrossDomainMessage( func NewCrossDomainMessage(
nonce *big.Int, nonce *big.Int,
sender, target *common.Address, sender, target common.Address,
value, gasLimit *big.Int, value, gasLimit *big.Int,
data []byte, data []byte,
) *CrossDomainMessage { ) *CrossDomainMessage {
...@@ -77,23 +76,3 @@ func (c *CrossDomainMessage) Hash() (common.Hash, error) { ...@@ -77,23 +76,3 @@ func (c *CrossDomainMessage) Hash() (common.Hash, error) {
func (c *CrossDomainMessage) HashV1() (common.Hash, error) { func (c *CrossDomainMessage) HashV1() (common.Hash, error) {
return HashCrossDomainMessageV1(c.Nonce, c.Sender, c.Target, c.Value, c.GasLimit, c.Data) return HashCrossDomainMessageV1(c.Nonce, c.Sender, c.Target, c.Value, c.GasLimit, c.Data)
} }
// ToWithdrawal will turn a CrossDomainMessage into a Withdrawal.
// This only works for version 0 CrossDomainMessages as not all of
// the data is present for version 1 CrossDomainMessages to be turned
// into Withdrawals.
func (c *CrossDomainMessage) ToWithdrawal() (WithdrawalMessage, error) {
version := c.Version()
switch version {
case 0:
if c.Value != nil && c.Value.Cmp(common.Big0) != 0 {
return nil, errors.New("version 0 messages must have 0 value")
}
w := NewLegacyWithdrawal(c.Target, c.Sender, c.Data, c.Nonce)
return w, nil
case 1:
return nil, errors.New("version 1 messages cannot be turned into withdrawals")
default:
return nil, fmt.Errorf("unknown version %d", version)
}
}
...@@ -18,8 +18,8 @@ func TestEncode(t *testing.T) { ...@@ -18,8 +18,8 @@ func TestEncode(t *testing.T) {
t.Run("V0", func(t *testing.T) { t.Run("V0", func(t *testing.T) {
msg := crossdomain.NewCrossDomainMessage( msg := crossdomain.NewCrossDomainMessage(
crossdomain.EncodeVersionedNonce(common.Big0, common.Big0), crossdomain.EncodeVersionedNonce(common.Big0, common.Big0),
&common.Address{}, common.Address{},
&common.Address{19: 0x01}, common.Address{19: 0x01},
big.NewInt(0), big.NewInt(0),
big.NewInt(5), big.NewInt(5),
[]byte{}, []byte{},
...@@ -37,8 +37,8 @@ func TestEncode(t *testing.T) { ...@@ -37,8 +37,8 @@ func TestEncode(t *testing.T) {
t.Run("V1", func(t *testing.T) { t.Run("V1", func(t *testing.T) {
msg := crossdomain.NewCrossDomainMessage( msg := crossdomain.NewCrossDomainMessage(
crossdomain.EncodeVersionedNonce(common.Big1, common.Big1), crossdomain.EncodeVersionedNonce(common.Big1, common.Big1),
&common.Address{19: 0x01}, common.Address{19: 0x01},
&common.Address{19: 0x02}, common.Address{19: 0x02},
big.NewInt(100), big.NewInt(100),
big.NewInt(555), big.NewInt(555),
[]byte{}, []byte{},
...@@ -63,8 +63,8 @@ func TestHash(t *testing.T) { ...@@ -63,8 +63,8 @@ func TestHash(t *testing.T) {
t.Run("V0", func(t *testing.T) { t.Run("V0", func(t *testing.T) {
msg := crossdomain.NewCrossDomainMessage( msg := crossdomain.NewCrossDomainMessage(
crossdomain.EncodeVersionedNonce(common.Big0, common.Big0), crossdomain.EncodeVersionedNonce(common.Big0, common.Big0),
&common.Address{}, common.Address{},
&common.Address{19: 0x01}, common.Address{19: 0x01},
big.NewInt(10), big.NewInt(10),
big.NewInt(5), big.NewInt(5),
[]byte{}, []byte{},
...@@ -82,8 +82,8 @@ func TestHash(t *testing.T) { ...@@ -82,8 +82,8 @@ func TestHash(t *testing.T) {
t.Run("V1", func(t *testing.T) { t.Run("V1", func(t *testing.T) {
msg := crossdomain.NewCrossDomainMessage( msg := crossdomain.NewCrossDomainMessage(
crossdomain.EncodeVersionedNonce(common.Big0, common.Big1), crossdomain.EncodeVersionedNonce(common.Big0, common.Big1),
&common.Address{}, common.Address{},
&common.Address{19: 0x01}, common.Address{19: 0x01},
big.NewInt(0), big.NewInt(0),
big.NewInt(5), big.NewInt(5),
[]byte{}, []byte{},
......
...@@ -19,7 +19,7 @@ var ( ...@@ -19,7 +19,7 @@ var (
) )
// MigrateWithdrawals will migrate a list of pending withdrawals given a StateDB. // MigrateWithdrawals will migrate a list of pending withdrawals given a StateDB.
func MigrateWithdrawals(withdrawals []*LegacyWithdrawal, db vm.StateDB, l1CrossDomainMessenger *common.Address, noCheck bool) error { func MigrateWithdrawals(withdrawals SafeFilteredWithdrawals, db vm.StateDB, l1CrossDomainMessenger *common.Address, noCheck bool) error {
for i, legacy := range withdrawals { for i, legacy := range withdrawals {
legacySlot, err := legacy.StorageSlot() legacySlot, err := legacy.StorageSlot()
if err != nil { if err != nil {
...@@ -66,17 +66,17 @@ func MigrateWithdrawal(withdrawal *LegacyWithdrawal, l1CrossDomainMessenger *com ...@@ -66,17 +66,17 @@ func MigrateWithdrawal(withdrawal *LegacyWithdrawal, l1CrossDomainMessenger *com
// Migrated withdrawals are specified as version 0. Both the // Migrated withdrawals are specified as version 0. Both the
// L2ToL1MessagePasser and the CrossDomainMessenger use the same // L2ToL1MessagePasser and the CrossDomainMessenger use the same
// versioning scheme. Both should be set to version 0 // versioning scheme. Both should be set to version 0
versionedNonce := EncodeVersionedNonce(withdrawal.Nonce, new(big.Int)) versionedNonce := EncodeVersionedNonce(withdrawal.XDomainNonce, new(big.Int))
// Encode the call to `relayMessage` on the `CrossDomainMessenger`. // Encode the call to `relayMessage` on the `CrossDomainMessenger`.
// The minGasLimit can safely be 0 here. // The minGasLimit can safely be 0 here.
data, err := abi.Pack( data, err := abi.Pack(
"relayMessage", "relayMessage",
versionedNonce, versionedNonce,
withdrawal.Sender, withdrawal.XDomainSender,
withdrawal.Target, withdrawal.XDomainTarget,
value, value,
new(big.Int), new(big.Int),
[]byte(withdrawal.Data), []byte(withdrawal.XDomainData),
) )
if err != nil { if err != nil {
return nil, fmt.Errorf("cannot abi encode relayMessage: %w", err) return nil, fmt.Errorf("cannot abi encode relayMessage: %w", err)
......
...@@ -17,10 +17,7 @@ func TestMigrateWithdrawal(t *testing.T) { ...@@ -17,10 +17,7 @@ func TestMigrateWithdrawal(t *testing.T) {
for _, receipt := range receipts { for _, receipt := range receipts {
msg, err := findCrossDomainMessage(receipt) msg, err := findCrossDomainMessage(receipt)
require.Nil(t, err) require.Nil(t, err)
withdrawal, err := msg.ToWithdrawal() legacyWithdrawal := toWithdrawal(t, predeploys.L2CrossDomainMessengerAddr, msg)
require.Nil(t, err)
legacyWithdrawal, ok := withdrawal.(*crossdomain.LegacyWithdrawal)
require.True(t, ok)
withdrawals = append(withdrawals, legacyWithdrawal) withdrawals = append(withdrawals, legacyWithdrawal)
} }
...@@ -31,7 +28,7 @@ func TestMigrateWithdrawal(t *testing.T) { ...@@ -31,7 +28,7 @@ func TestMigrateWithdrawal(t *testing.T) {
require.Nil(t, err) require.Nil(t, err)
require.NotNil(t, withdrawal) require.NotNil(t, withdrawal)
require.Equal(t, legacy.Nonce.Uint64(), withdrawal.Nonce.Uint64()) require.Equal(t, legacy.XDomainNonce.Uint64(), withdrawal.Nonce.Uint64())
require.Equal(t, *withdrawal.Sender, predeploys.L2CrossDomainMessengerAddr) require.Equal(t, *withdrawal.Sender, predeploys.L2CrossDomainMessengerAddr)
require.Equal(t, *withdrawal.Target, l1CrossDomainMessenger) require.Equal(t, *withdrawal.Target, l1CrossDomainMessenger)
}) })
......
package crossdomain package crossdomain
import ( import (
"errors"
"fmt" "fmt"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys" "github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
) )
var (
ErrUnknownSlotInMessagePasser = errors.New("unknown slot in legacy message passer")
ErrMissingSlotInWitness = errors.New("missing storage slot in witness data")
)
// PreCheckWithdrawals checks that the given list of withdrawals represents all withdrawals made // PreCheckWithdrawals checks that the given list of withdrawals represents all withdrawals made
// in the legacy system and filters out any extra withdrawals not included in the legacy system. // in the legacy system and filters out any extra withdrawals not included in the legacy system.
func PreCheckWithdrawals(db *state.StateDB, withdrawals []*LegacyWithdrawal) ([]*LegacyWithdrawal, error) { func PreCheckWithdrawals(db *state.StateDB, withdrawals DangerousUnfilteredWithdrawals) (SafeFilteredWithdrawals, error) {
// Convert each withdrawal into a storage slot, and build a map of those slots. // Convert each withdrawal into a storage slot, and build a map of those slots.
slotsInp := make(map[common.Hash]*LegacyWithdrawal) slotsInp := make(map[common.Hash]*LegacyWithdrawal)
for _, wd := range withdrawals { for _, wd := range withdrawals {
...@@ -26,6 +31,7 @@ func PreCheckWithdrawals(db *state.StateDB, withdrawals []*LegacyWithdrawal) ([] ...@@ -26,6 +31,7 @@ func PreCheckWithdrawals(db *state.StateDB, withdrawals []*LegacyWithdrawal) ([]
// Build a mapping of the slots of all messages actually sent in the legacy system. // Build a mapping of the slots of all messages actually sent in the legacy system.
var count int var count int
var innerErr error
slotsAct := make(map[common.Hash]bool) slotsAct := make(map[common.Hash]bool)
err := db.ForEachStorage(predeploys.LegacyMessagePasserAddr, func(key, value common.Hash) bool { err := db.ForEachStorage(predeploys.LegacyMessagePasserAddr, func(key, value common.Hash) bool {
// When a message is inserted into the LegacyMessagePasser, it is stored with the value // When a message is inserted into the LegacyMessagePasser, it is stored with the value
...@@ -33,7 +39,7 @@ func PreCheckWithdrawals(db *state.StateDB, withdrawals []*LegacyWithdrawal) ([] ...@@ -33,7 +39,7 @@ func PreCheckWithdrawals(db *state.StateDB, withdrawals []*LegacyWithdrawal) ([]
// can safely ignore anything that is not "true". // can safely ignore anything that is not "true".
if value != abiTrue { if value != abiTrue {
// Should not happen! // Should not happen!
log.Error("found unknown slot in LegacyMessagePasser", "key", key.String(), "val", value.String()) innerErr = fmt.Errorf("%w: key: %s, val: %s", ErrUnknownSlotInMessagePasser, key.String(), value.String())
return true return true
} }
...@@ -45,6 +51,9 @@ func PreCheckWithdrawals(db *state.StateDB, withdrawals []*LegacyWithdrawal) ([] ...@@ -45,6 +51,9 @@ func PreCheckWithdrawals(db *state.StateDB, withdrawals []*LegacyWithdrawal) ([]
if err != nil { if err != nil {
return nil, fmt.Errorf("cannot iterate over LegacyMessagePasser: %w", err) return nil, fmt.Errorf("cannot iterate over LegacyMessagePasser: %w", err)
} }
if innerErr != nil {
return nil, innerErr
}
// Log the number of messages we found. // Log the number of messages we found.
log.Info("Iterated legacy messages", "count", count) log.Info("Iterated legacy messages", "count", count)
...@@ -53,13 +62,13 @@ func PreCheckWithdrawals(db *state.StateDB, withdrawals []*LegacyWithdrawal) ([] ...@@ -53,13 +62,13 @@ func PreCheckWithdrawals(db *state.StateDB, withdrawals []*LegacyWithdrawal) ([]
for slot := range slotsAct { for slot := range slotsAct {
_, ok := slotsInp[slot] _, ok := slotsInp[slot]
if !ok { if !ok {
return nil, fmt.Errorf("unknown storage slot in state: %s", slot) return nil, ErrMissingSlotInWitness
} }
} }
// Iterate over the list of input messages and check that we have a known slot for each one. // Iterate over the list of input messages and check that we have a known slot for each one.
// We'll filter out any extra messages that are not in the legacy system. // We'll filter out any extra messages that are not in the legacy system.
filtered := make([]*LegacyWithdrawal, 0) filtered := make(SafeFilteredWithdrawals, 0)
for slot := range slotsInp { for slot := range slotsInp {
_, ok := slotsAct[slot] _, ok := slotsAct[slot]
if !ok { if !ok {
...@@ -67,7 +76,13 @@ func PreCheckWithdrawals(db *state.StateDB, withdrawals []*LegacyWithdrawal) ([] ...@@ -67,7 +76,13 @@ func PreCheckWithdrawals(db *state.StateDB, withdrawals []*LegacyWithdrawal) ([]
continue continue
} }
filtered = append(filtered, slotsInp[slot]) wd := slotsInp[slot]
if wd.MessageSender != predeploys.L2CrossDomainMessengerAddr {
log.Info("filtering out message from sender other than the L2XDM", "sender", wd.MessageSender)
continue
}
filtered = append(filtered, wd)
} }
// At this point, we know that the list of filtered withdrawals MUST be exactly the same as the // At this point, we know that the list of filtered withdrawals MUST be exactly the same as the
......
package crossdomain
import (
"math/big"
"testing"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"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/trie"
"github.com/stretchr/testify/require"
)
func TestPreCheckWithdrawals_Filtering(t *testing.T) {
dbWds := []*LegacyWithdrawal{
// Random legacy WD to something other than the L2XDM.
{
MessageSender: common.Address{19: 0xFF},
XDomainTarget: common.Address{19: 0x01},
XDomainSender: common.Address{19: 0x02},
XDomainData: []byte{0x01, 0x02, 0x03},
XDomainNonce: big.NewInt(0),
},
// Random legacy WD to the L2XDM. Should be the only thing
// returned by the prechecker.
{
MessageSender: predeploys.L2CrossDomainMessengerAddr,
XDomainTarget: common.Address{19: 0x01},
XDomainSender: common.Address{19: 0x02},
XDomainData: []byte{0x01, 0x02, 0x03},
XDomainNonce: big.NewInt(1),
},
}
// Add an additional witness to the witnesses list to
// test how the prechecker handles witness data that
// isn't in state.
witnessWds := append([]*LegacyWithdrawal{
{
MessageSender: common.Address{19: 0xAA},
XDomainTarget: common.Address{19: 0x03},
XDomainSender: predeploys.L2CrossDomainMessengerAddr,
XDomainData: []byte{0x01, 0x02, 0x03},
XDomainNonce: big.NewInt(0),
},
}, dbWds...)
filteredWds, err := runPrecheck(t, dbWds, witnessWds)
require.NoError(t, err)
require.EqualValues(t, []*LegacyWithdrawal{dbWds[1]}, filteredWds)
}
func TestPreCheckWithdrawals_InvalidSlotInStorage(t *testing.T) {
rawDB := rawdb.NewMemoryDatabase()
rawStateDB := state.NewDatabaseWithConfig(rawDB, &trie.Config{
Preimages: true,
Cache: 1024,
})
stateDB, err := state.New(common.Hash{}, rawStateDB, nil)
require.NoError(t, err)
// Create account, and set a random storage slot to a value
// other than abiTrue.
stateDB.CreateAccount(predeploys.LegacyMessagePasserAddr)
stateDB.SetState(predeploys.LegacyMessagePasserAddr, common.Hash{0: 0xff}, common.Hash{0: 0xff})
root, err := stateDB.Commit(false)
require.NoError(t, err)
err = stateDB.Database().TrieDB().Commit(root, true, nil)
require.NoError(t, err)
_, err = PreCheckWithdrawals(stateDB, nil)
require.ErrorIs(t, err, ErrUnknownSlotInMessagePasser)
}
func TestPreCheckWithdrawals_MissingStorageSlot(t *testing.T) {
// Add a legacy WD to state that does not appear in witness data.
dbWds := []*LegacyWithdrawal{
{
XDomainTarget: common.Address{19: 0x01},
XDomainSender: predeploys.L2CrossDomainMessengerAddr,
XDomainData: []byte{0x01, 0x02, 0x03},
XDomainNonce: big.NewInt(1),
},
}
// Create some witness data that includes both a valid
// and an invalid witness, but neither of which correspond
// to the value above in state.
witnessWds := []*LegacyWithdrawal{
{
XDomainTarget: common.Address{19: 0x01},
XDomainSender: common.Address{19: 0x02},
XDomainData: []byte{0x01, 0x02, 0x03},
XDomainNonce: big.NewInt(0),
},
{
XDomainTarget: common.Address{19: 0x03},
XDomainSender: predeploys.L2CrossDomainMessengerAddr,
XDomainData: []byte{0x01, 0x02, 0x03},
XDomainNonce: big.NewInt(0),
},
}
_, err := runPrecheck(t, dbWds, witnessWds)
require.ErrorIs(t, err, ErrMissingSlotInWitness)
}
func runPrecheck(t *testing.T, dbWds []*LegacyWithdrawal, witnessWds []*LegacyWithdrawal) ([]*LegacyWithdrawal, error) {
rawDB := rawdb.NewMemoryDatabase()
rawStateDB := state.NewDatabaseWithConfig(rawDB, &trie.Config{
Preimages: true,
Cache: 1024,
})
stateDB, err := state.New(common.Hash{}, rawStateDB, nil)
require.NoError(t, err)
stateDB.CreateAccount(predeploys.LegacyMessagePasserAddr)
for _, wd := range dbWds {
slot, err := wd.StorageSlot()
require.NoError(t, err)
stateDB.SetState(predeploys.LegacyMessagePasserAddr, slot, abiTrue)
}
root, err := stateDB.Commit(false)
require.NoError(t, err)
err = stateDB.Database().TrieDB().Commit(root, true, nil)
require.NoError(t, err)
return PreCheckWithdrawals(stateDB, witnessWds)
}
...@@ -5,6 +5,15 @@ import ( ...@@ -5,6 +5,15 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
) )
// DangerousUnfilteredWithdrawals is a list of raw withdrawal witness
// data. It has not been filtered for messages from sources other than
// the
type DangerousUnfilteredWithdrawals []*LegacyWithdrawal
// SafeFilteredWithdrawals is a list of withdrawals that have been filtered to only include
// withdrawals that were from the L2XDM.
type SafeFilteredWithdrawals []*LegacyWithdrawal
var ( var (
// Standard ABI types // Standard ABI types
Uint256Type, _ = abi.NewType("uint256", "", nil) Uint256Type, _ = abi.NewType("uint256", "", nil)
......
...@@ -87,8 +87,8 @@ func GetPendingWithdrawals(messengers *Messengers, version *big.Int, start, end ...@@ -87,8 +87,8 @@ func GetPendingWithdrawals(messengers *Messengers, version *big.Int, start, end
msg := NewCrossDomainMessage( msg := NewCrossDomainMessage(
event.MessageNonce, event.MessageNonce,
&event.Sender, event.Sender,
&event.Target, event.Target,
common.Big0, common.Big0,
event.GasLimit, event.GasLimit,
event.Message, event.Message,
...@@ -116,10 +116,10 @@ func GetPendingWithdrawals(messengers *Messengers, version *big.Int, start, end ...@@ -116,10 +116,10 @@ func GetPendingWithdrawals(messengers *Messengers, version *big.Int, start, end
withdrawal := PendingWithdrawal{ withdrawal := PendingWithdrawal{
LegacyWithdrawal: LegacyWithdrawal{ LegacyWithdrawal: LegacyWithdrawal{
Target: &event.Target, XDomainTarget: event.Target,
Sender: &event.Sender, XDomainSender: event.Sender,
Data: event.Message, XDomainData: event.Message,
Nonce: event.MessageNonce, XDomainNonce: event.MessageNonce,
}, },
TransactionHash: event.Raw.TxHash, TransactionHash: event.Raw.TxHash,
} }
......
...@@ -146,8 +146,8 @@ func sendCrossDomainMessage( ...@@ -146,8 +146,8 @@ func sendCrossDomainMessage(
// Parse the legacy event // Parse the legacy event
if event.Name == "SentMessage" { if event.Name == "SentMessage" {
e, _ := l2xdm.ParseSentMessage(*log) e, _ := l2xdm.ParseSentMessage(*log)
msg.Target = &e.Target msg.Target = e.Target
msg.Sender = &e.Sender msg.Sender = e.Sender
msg.Data = e.Message msg.Data = e.Message
msg.Nonce = e.MessageNonce msg.Nonce = e.MessageNonce
msg.GasLimit = e.GasLimit msg.GasLimit = e.GasLimit
...@@ -272,7 +272,7 @@ func TestGetPendingWithdrawals(t *testing.T) { ...@@ -272,7 +272,7 @@ func TestGetPendingWithdrawals(t *testing.T) {
for i, msg := range msgs[3:] { for i, msg := range msgs[3:] {
withdrawal := withdrawals[i] withdrawal := withdrawals[i]
require.Equal(t, msg.Target, *withdrawal.Target) require.Equal(t, msg.Target, withdrawal.XDomainTarget)
require.Equal(t, msg.Message, []byte(withdrawal.Data)) require.Equal(t, msg.Message, []byte(withdrawal.XDomainData))
} }
} }
...@@ -461,7 +461,8 @@ func CheckWithdrawalsAfter(db vm.StateDB, data migration.MigrationData, l1CrossD ...@@ -461,7 +461,8 @@ func CheckWithdrawalsAfter(db vm.StateDB, data migration.MigrationData, l1CrossD
// First, make a mapping between old withdrawal slots and new ones. // First, make a mapping between old withdrawal slots and new ones.
// This list can be a superset of what was actually migrated, since // This list can be a superset of what was actually migrated, since
// some witness data may references withdrawals that reverted. // some witness data may references withdrawals that reverted.
oldToNew := make(map[common.Hash]common.Hash) oldToNewSlots := make(map[common.Hash]common.Hash)
wdsByOldSlot := make(map[common.Hash]*crossdomain.LegacyWithdrawal)
for _, wd := range wds { for _, wd := range wds {
migrated, err := crossdomain.MigrateWithdrawal(wd, l1CrossDomainMessenger) migrated, err := crossdomain.MigrateWithdrawal(wd, l1CrossDomainMessenger)
if err != nil { if err != nil {
...@@ -477,7 +478,8 @@ func CheckWithdrawalsAfter(db vm.StateDB, data migration.MigrationData, l1CrossD ...@@ -477,7 +478,8 @@ func CheckWithdrawalsAfter(db vm.StateDB, data migration.MigrationData, l1CrossD
return fmt.Errorf("cannot compute migrated storage slot: %w", err) return fmt.Errorf("cannot compute migrated storage slot: %w", err)
} }
oldToNew[legacySlot] = migratedSlot oldToNewSlots[legacySlot] = migratedSlot
wdsByOldSlot[legacySlot] = wd
} }
// Now, iterate over each legacy withdrawal and check if there is a corresponding // Now, iterate over each legacy withdrawal and check if there is a corresponding
...@@ -498,17 +500,29 @@ func CheckWithdrawalsAfter(db vm.StateDB, data migration.MigrationData, l1CrossD ...@@ -498,17 +500,29 @@ func CheckWithdrawalsAfter(db vm.StateDB, data migration.MigrationData, l1CrossD
} }
// Grab the migrated slot. // Grab the migrated slot.
migratedSlot := oldToNew[key] migratedSlot := oldToNewSlots[key]
if migratedSlot == (common.Hash{}) { if migratedSlot == (common.Hash{}) {
innerErr = fmt.Errorf("no migrated slot found for legacy slot %s", key) innerErr = fmt.Errorf("no migrated slot found for legacy slot %s", key)
return false return false
} }
// Look up the migrated slot in the DB, and make sure it is abiTrue. // Look up the migrated slot in the DB.
migratedValue := db.GetState(predeploys.L2ToL1MessagePasserAddr, migratedSlot) migratedValue := db.GetState(predeploys.L2ToL1MessagePasserAddr, migratedSlot)
if migratedValue != abiTrue {
innerErr = fmt.Errorf("expected migrated value to be true, but got %s", migratedValue) // If the sender is _not_ the L2XDM, the value should not be migrated.
return false wd := wdsByOldSlot[key]
if wd.XDomainSender == predeploys.L2CrossDomainMessengerAddr {
// Make sure the value is abiTrue if this withdrawal should be migrated.
if migratedValue != abiTrue {
innerErr = fmt.Errorf("expected migrated value to be true, but got %s", migratedValue)
return false
}
} else {
// Otherwise, ensure that withdrawals from senders other than the L2XDM are _not_ migrated.
if migratedValue != abiFalse {
innerErr = fmt.Errorf("a migration from a sender other than the L2XDM was migrated")
return false
}
} }
return true return true
......
...@@ -20,7 +20,8 @@ import ( ...@@ -20,7 +20,8 @@ import (
) )
var ( var (
abiTrue = common.Hash{31: 0x01} abiTrue = common.Hash{31: 0x01}
abiFalse = common.Hash{}
// BedrockTransitionBlockExtraData represents the extradata // BedrockTransitionBlockExtraData represents the extradata
// set in the very first bedrock block. This value must be // set in the very first bedrock block. This value must be
// less than 32 bytes long or it will create an invalid block. // less than 32 bytes long or it will create an invalid block.
...@@ -120,7 +121,7 @@ func MigrateDB(ldb ethdb.Database, config *DeployConfig, l1Block *types.Block, m ...@@ -120,7 +121,7 @@ func MigrateDB(ldb ethdb.Database, config *DeployConfig, l1Block *types.Block, m
// We now need to check that we have all of the withdrawals that we expect to have. An error // We now need to check that we have all of the withdrawals that we expect to have. An error
// will be thrown if there are any missing messages, and any extra messages will be removed. // will be thrown if there are any missing messages, and any extra messages will be removed.
var filteredWithdrawals []*crossdomain.LegacyWithdrawal var filteredWithdrawals crossdomain.SafeFilteredWithdrawals
if !noCheck { if !noCheck {
log.Info("Checking withdrawals...") log.Info("Checking withdrawals...")
filteredWithdrawals, err = crossdomain.PreCheckWithdrawals(db, unfilteredWithdrawals) filteredWithdrawals, err = crossdomain.PreCheckWithdrawals(db, unfilteredWithdrawals)
...@@ -129,7 +130,7 @@ func MigrateDB(ldb ethdb.Database, config *DeployConfig, l1Block *types.Block, m ...@@ -129,7 +130,7 @@ func MigrateDB(ldb ethdb.Database, config *DeployConfig, l1Block *types.Block, m
} }
} else { } else {
log.Info("Skipping checking withdrawals") log.Info("Skipping checking withdrawals")
filteredWithdrawals = unfilteredWithdrawals filteredWithdrawals = crossdomain.SafeFilteredWithdrawals(unfilteredWithdrawals)
} }
// We also need to verify that we have all of the storage slots for the LegacyERC20ETH contract // We also need to verify that we have all of the storage slots for the LegacyERC20ETH contract
......
...@@ -5,8 +5,6 @@ import ( ...@@ -5,8 +5,6 @@ import (
"fmt" "fmt"
"os" "os"
"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"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
...@@ -119,12 +117,9 @@ type MigrationData struct { ...@@ -119,12 +117,9 @@ type MigrationData struct {
EvmMessages []*SentMessage EvmMessages []*SentMessage
} }
func (m *MigrationData) ToWithdrawals() ([]*crossdomain.LegacyWithdrawal, error) { func (m *MigrationData) ToWithdrawals() (crossdomain.DangerousUnfilteredWithdrawals, error) {
messages := make([]*crossdomain.LegacyWithdrawal, 0) messages := make(crossdomain.DangerousUnfilteredWithdrawals, 0)
for _, msg := range m.OvmMessages { for _, msg := range m.OvmMessages {
if msg.Who != predeploys.L2CrossDomainMessengerAddr {
continue
}
wd, err := msg.ToLegacyWithdrawal() wd, err := msg.ToLegacyWithdrawal()
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -135,9 +130,6 @@ func (m *MigrationData) ToWithdrawals() ([]*crossdomain.LegacyWithdrawal, error) ...@@ -135,9 +130,6 @@ func (m *MigrationData) ToWithdrawals() ([]*crossdomain.LegacyWithdrawal, error)
} }
} }
for _, msg := range m.EvmMessages { for _, msg := range m.EvmMessages {
if msg.Who != predeploys.L2CrossDomainMessengerAddr {
continue
}
wd, err := msg.ToLegacyWithdrawal() wd, err := msg.ToLegacyWithdrawal()
if err != nil { if err != nil {
return nil, err return nil, 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