Commit 00345067 authored by Mark Tyneway's avatar Mark Tyneway

op-chain-ops: prevent invalid decoding errors

Invalid decoding errors should not stop the script from
progressing. This fix ensures that all possible errors
are handled in a way that they can be skipped. The panic
conditions should never happen, so we do not need to worry
about them. It is permissionless to insert data into the
set that is parsed through this function, so errors cannot
break it.

Also adds unit tests for the parsing, ensures to cover
each relevant branch.
parent 3ac5fa09
......@@ -41,6 +41,40 @@ func NewSentMessageFromJSON(path string) ([]*SentMessage, error) {
return j, nil
}
// decodeWitnessCalldata abi decodes the calldata encoded in the input witness
// file. It errors if the 4 byte selector is not specifically for `passMessageToL1`.
// It also errors if the abi decoding fails.
func decodeWitnessCalldata(msg []byte) ([]byte, error) {
abi, err := bindings.LegacyMessagePasserMetaData.GetAbi()
if err != nil {
panic("should always be able to get message passer abi")
}
if size := len(msg); size < 4 {
return nil, fmt.Errorf("message too short: %d", size)
}
method, err := abi.MethodById(msg[:4])
if err != nil {
return nil, err
}
if method.Sig != "passMessageToL1(bytes)" {
return nil, fmt.Errorf("unknown method: %s", method.Name)
}
out, err := method.Inputs.Unpack(msg[4:])
if err != nil {
return nil, err
}
cast, ok := out[0].([]byte)
if !ok {
panic("should always be able to cast type []byte")
}
return cast, nil
}
// ReadWitnessData will read messages and addresses from a raw l2geth state
// dump file.
func ReadWitnessData(path string) ([]*SentMessage, OVMETHAddresses, error) {
......@@ -72,30 +106,18 @@ func ReadWitnessData(path string) ([]*SentMessage, OVMETHAddresses, error) {
msg = "0x" + msg
}
abi, err := bindings.LegacyMessagePasserMetaData.GetAbi()
if err != nil {
return nil, nil, fmt.Errorf("failed to get abi: %w", err)
}
msgB := hexutil.MustDecode(msg)
method, err := abi.MethodById(msgB[:4])
if err != nil {
return nil, nil, fmt.Errorf("failed to get method: %w", err)
}
out, err := method.Inputs.Unpack(msgB[4:])
// Skip any errors
calldata, err := decodeWitnessCalldata(msgB)
if err != nil {
return nil, nil, fmt.Errorf("failed to unpack: %w", err)
}
cast, ok := out[0].([]byte)
if !ok {
return nil, nil, fmt.Errorf("failed to cast to bytes")
log.Warn("cannot decode witness calldata", "err", err)
continue
}
witnesses = append(witnesses, &SentMessage{
Who: common.HexToAddress(splits[1]),
Msg: cast,
Msg: calldata,
})
case "ETH":
addresses[common.HexToAddress(splits[1])] = true
......
......@@ -41,3 +41,67 @@ func TestRead(t *testing.T) {
common.HexToAddress("0x6340d44c5174588B312F545eEC4a42f8a514eF50"): true,
}, addresses)
}
// TestDecodeWitnessCallData tests that the witness data is parsed correctly
// from an input bytes slice.
func TestDecodeWitnessCallData(t *testing.T) {
tests := []struct {
name string
err bool
msg []byte
want []byte
}{
{
name: "too-small",
err: true,
msg: common.FromHex("0x0000"),
},
{
name: "unknown-selector",
err: true,
msg: common.FromHex("0x00000000"),
},
{
name: "wrong-selector",
err: true,
// 0x54fd4d50 is the selector for `version()`
msg: common.FromHex("0x54fd4d50"),
},
{
name: "invalid-calldata-only-selector",
err: true,
// 0xcafa81dc is the selector for `passMessageToL1(bytes)`
msg: common.FromHex("0xcafa81dc"),
},
{
name: "invalid-calldata-invalid-bytes",
err: true,
// 0xcafa81dc is the selector for passMessageToL1(bytes)
msg: common.FromHex("0xcafa81dc0000"),
},
{
name: "valid-calldata",
msg: common.FromHex(
"0xcafa81dc" +
"0000000000000000000000000000000000000000000000000000000000000020" +
"0000000000000000000000000000000000000000000000000000000000000002" +
"1234000000000000000000000000000000000000000000000000000000000000",
),
want: common.FromHex("0x1234"),
},
}
for _, tt := range tests {
test := tt
t.Run(test.name, func(t *testing.T) {
if test.err {
_, err := decodeWitnessCalldata(test.msg)
require.Error(t, err)
} else {
want, err := decodeWitnessCalldata(test.msg)
require.NoError(t, err)
require.Equal(t, test.want, want)
}
})
}
}
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