Commit c3980e9a authored by Mark Tyneway's avatar Mark Tyneway Committed by GitHub

op-chain-ops: implement withdrawal hashing (#3469)

* op-chain-ops: implement withdrawal hashing

Implement both the new hashing scheme and the legacy
hashing for withdrawals so that the withdrawals can
be migrated.

Also implement encoding and decoding of the withdrawals

* more tests

* op-chain-ops: code review fixes

* op-chain-ops: fix message passer

Now that the old message passer is being kept in the L2
state, be sure to the use legacy address. The new message
passer is at a different address.
parent 71eeed8f
package crossdomain
import (
"bytes"
"errors"
"fmt"
"math/big"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
)
// LegacyWithdrawal represents a pre bedrock upgrade withdrawal.
type LegacyWithdrawal struct {
Target *common.Address
Sender *common.Address
Data []byte
Nonce *big.Int
}
var _ WithdrawalMessage = (*LegacyWithdrawal)(nil)
// NewLegacyWithdrawal will construct a LegacyWithdrawal
func NewLegacyWithdrawal(target, sender *common.Address, data []byte, nonce *big.Int) *LegacyWithdrawal {
return &LegacyWithdrawal{
Target: target,
Sender: sender,
Data: data,
Nonce: nonce,
}
}
// Encode will serialze the Withdrawal in the legacy format so that it
// is suitable for hashing. This assumes that the message is being withdrawn
// through the standard optimism cross domain messaging system by hashing in
// the L2CrossDomainMessenger address.
func (w *LegacyWithdrawal) Encode() ([]byte, error) {
enc, err := EncodeCrossDomainMessageV0(w.Target, w.Sender, w.Data, w.Nonce)
if err != nil {
return nil, err
}
out := make([]byte, len(enc)+len(predeploys.L2CrossDomainMessengerAddr.Bytes()))
copy(out, enc)
copy(out[len(enc):], predeploys.L2CrossDomainMessengerAddr.Bytes())
return out, nil
}
// Decode will decode a serialized LegacyWithdrawal
func (w *LegacyWithdrawal) Decode(data []byte) error {
if len(data) < len(predeploys.L2CrossDomainMessengerAddr)+4 {
return fmt.Errorf("withdrawal data too short: %d", len(data))
}
selector := crypto.Keccak256([]byte("relayMessage(address,address,bytes,uint256)"))[0:4]
if !bytes.Equal(data[0:4], selector) {
return fmt.Errorf("invalid selector: 0x%x", data[0:4])
}
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)]
args := abi.Arguments{
{Name: "target", Type: AddressType},
{Name: "sender", Type: AddressType},
{Name: "data", Type: BytesType},
{Name: "nonce", Type: Uint256Type},
}
decoded, err := args.Unpack(raw)
if err != nil {
return err
}
target, ok := decoded[0].(common.Address)
if !ok {
return errors.New("cannot abi decode target")
}
sender, ok := decoded[1].(common.Address)
if !ok {
return errors.New("cannot abi decode sender")
}
msgData, ok := decoded[2].([]byte)
if !ok {
return errors.New("cannot abi decode data")
}
nonce, ok := decoded[3].(*big.Int)
if !ok {
return errors.New("cannot abi decode nonce")
}
w.Target = &target
w.Sender = &sender
w.Data = msgData
w.Nonce = nonce
return nil
}
// Hash will compute the legacy style hash that is computed in the
// OVM_L2ToL1MessagePasser.
func (w *LegacyWithdrawal) Hash() (common.Hash, error) {
encoded, err := w.Encode()
if err != nil {
return common.Hash{}, nil
}
hash := crypto.Keccak256(encoded)
return common.BytesToHash(hash), nil
}
// StorageSlot will compute the storage slot that is set
// to true in the legacy L2ToL1MessagePasser.
func (w *LegacyWithdrawal) StorageSlot() (common.Hash, error) {
hash, err := w.Hash()
if err != nil {
return common.Hash{}, err
}
preimage := make([]byte, 64)
copy(preimage, hash.Bytes())
slot := crypto.Keccak256(preimage)
return common.BytesToHash(slot), nil
}
This diff is collapsed.
package crossdomain
import (
"errors"
"fmt"
"math/big"
......@@ -54,7 +55,7 @@ func (c *CrossDomainMessage) Encode() ([]byte, error) {
case 1:
return EncodeCrossDomainMessageV1(c.Nonce, c.Sender, c.Target, c.Value, c.GasLimit, c.Data)
default:
return nil, fmt.Errorf("unknown nonce version %d", version)
return nil, fmt.Errorf("unknown version %d", version)
}
}
......@@ -67,6 +68,26 @@ func (c *CrossDomainMessage) Hash() (common.Hash, error) {
case 1:
return HashCrossDomainMessageV1(c.Nonce, c.Sender, c.Target, c.Value, c.GasLimit, c.Data)
default:
return common.Hash{}, fmt.Errorf("unknown nonce version %d", version)
return common.Hash{}, fmt.Errorf("unknown version %d", version)
}
}
// 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)
}
}
# crossdomain/testdata
Real world test data is used to generate test vectors for the withdrawal
hashing. The `trace.sh` script will generate artifacts used as part of the
tests. It accepts a single argument, being the transaction hash to fetch
artifacts for. It will fetch a receipt, a call trace and a state diff.
The tests require that a file named after the transaction hash exists
in each of the directories `call-traces`, `receipts` and `state-diffs`.
The `trace.sh` script will ensure that the files are created correctly.
{
"calls": [
{
"from": "0x4200000000000000000000000000000000000010",
"gas": "0x1647d",
"gasUsed": "0x341b",
"input": "0x9dc29fac0000000000000000000000009c8f005ab27adb94f3d49020a15722db2fcd9f2700000000000000000000000000000000000000000000000000232bff5f46c000",
"output": "0x",
"to": "0xdeaddeaddeaddeaddeaddeaddeaddeaddead0000",
"type": "CALL",
"value": "0x0"
},
{
"from": "0x4200000000000000000000000000000000000010",
"gas": "0x12fe8",
"gasUsed": "0x94b",
"input": "0xc01e1bd6",
"output": "0x0000000000000000000000000000000000000000000000000000000000000000",
"to": "0xdeaddeaddeaddeaddeaddeaddeaddeaddead0000",
"type": "CALL",
"value": "0x0"
},
{
"calls": [
{
"from": "0x4200000000000000000000000000000000000007",
"gas": "0x8ea6",
"gasUsed": "0x5e1e",
"input": "0xcafa81dc00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000164cbd4ece900000000000000000000000099c9fc46f92e8a1c0dec1b1747d010903e884be100000000000000000000000042000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000001b04d00000000000000000000000000000000000000000000000000000000000000a41532ec340000000000000000000000009c8f005ab27adb94f3d49020a15722db2fcd9f270000000000000000000000009c8f005ab27adb94f3d49020a15722db2fcd9f2700000000000000000000000000000000000000000000000000232bff5f46c000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"output": "0x",
"to": "0x4200000000000000000000000000000000000000",
"type": "CALL",
"value": "0x0"
}
],
"from": "0x4200000000000000000000000000000000000010",
"gas": "0x10644",
"gasUsed": "0xf29d",
"input": "0x3dbb202b00000000000000000000000099c9fc46f92e8a1c0dec1b1747d010903e884be10000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a41532ec340000000000000000000000009c8f005ab27adb94f3d49020a15722db2fcd9f270000000000000000000000009c8f005ab27adb94f3d49020a15722db2fcd9f2700000000000000000000000000000000000000000000000000232bff5f46c0000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"output": "0x",
"to": "0x4200000000000000000000000000000000000007",
"type": "CALL",
"value": "0x0"
}
],
"from": "0x9c8f005ab27adb94f3d49020a15722db2fcd9f27",
"gas": "0x177d2",
"gasUsed": "0x16ce2",
"input": "0x32b7006d000000000000000000000000deaddeaddeaddeaddeaddeaddeaddeaddead000000000000000000000000000000000000000000000000000000232bff5f46c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000",
"output": "0x",
"time": "112.522948ms",
"to": "0x4200000000000000000000000000000000000010",
"type": "CALL",
"value": "0x0"
}
{
"calls": [
{
"from": "0x4200000000000000000000000000000000000010",
"gas": "0x318ce",
"gasUsed": "0x427b",
"input": "0x9dc29fac0000000000000000000000003178490d60b5cceaa5a79fd4d9050c7405bab80c0000000000000000000000000000000000000000000000a3b61828488b117259",
"output": "0x",
"to": "0x76fb31fb4af56892a25e32cfc43de717950c9278",
"type": "CALL",
"value": "0x0"
},
{
"from": "0x4200000000000000000000000000000000000010",
"gas": "0x2d612",
"gasUsed": "0xa14",
"input": "0xc01e1bd6",
"output": "0x0000000000000000000000007fc66500c84a76ad7e9c93437bfc5ac33e2ddae9",
"to": "0x76fb31fb4af56892a25e32cfc43de717950c9278",
"type": "CALL",
"value": "0x0"
},
{
"calls": [
{
"from": "0x4200000000000000000000000000000000000007",
"gas": "0x22b8c",
"gasUsed": "0x5ecf",
"input": "0xcafa81dc000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001a4cbd4ece900000000000000000000000099c9fc46f92e8a1c0dec1b1747d010903e884be100000000000000000000000042000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000001b04f00000000000000000000000000000000000000000000000000000000000000e4a9f9e6750000000000000000000000007fc66500c84a76ad7e9c93437bfc5ac33e2ddae900000000000000000000000076fb31fb4af56892a25e32cfc43de717950c92780000000000000000000000003178490d60b5cceaa5a79fd4d9050c7405bab80c0000000000000000000000003178490d60b5cceaa5a79fd4d9050c7405bab80c0000000000000000000000000000000000000000000000a3b61828488b11725900000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"output": "0x",
"to": "0x4200000000000000000000000000000000000000",
"type": "CALL",
"value": "0x0"
}
],
"from": "0x4200000000000000000000000000000000000010",
"gas": "0x2aae9",
"gasUsed": "0xf705",
"input": "0x3dbb202b00000000000000000000000099c9fc46f92e8a1c0dec1b1747d010903e884be10000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e4a9f9e6750000000000000000000000007fc66500c84a76ad7e9c93437bfc5ac33e2ddae900000000000000000000000076fb31fb4af56892a25e32cfc43de717950c92780000000000000000000000003178490d60b5cceaa5a79fd4d9050c7405bab80c0000000000000000000000003178490d60b5cceaa5a79fd4d9050c7405bab80c0000000000000000000000000000000000000000000000a3b61828488b11725900000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"output": "0x",
"to": "0x4200000000000000000000000000000000000007",
"type": "CALL",
"value": "0x0"
}
],
"from": "0x3178490d60b5cceaa5a79fd4d9050c7405bab80c",
"gas": "0x33310",
"gasUsed": "0x18136",
"input": "0x32b7006d00000000000000000000000076fb31fb4af56892a25e32cfc43de717950c92780000000000000000000000000000000000000000000000a3b61828488b117259000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000",
"output": "0x",
"time": "40.447524ms",
"to": "0x4200000000000000000000000000000000000010",
"type": "CALL",
"value": "0x0"
}
{
"calls": [
{
"from": "0x467194771dae2967aef3ecbedd3bf9a310c76c65",
"gas": "0x150b9",
"gasUsed": "0x395f",
"input": "0x9dc29fac0000000000000000000000006659612eb0e2464ccadf7a5e851bcd12873f6e040000000000000000000000000000000000000000000211654585005212800000",
"output": "0x",
"to": "0xda10009cbd5d07dd0cecc66161fc93d7c9000da1",
"type": "CALL",
"value": "0x0"
},
{
"calls": [
{
"from": "0x4200000000000000000000000000000000000007",
"gas": "0x86e2",
"gasUsed": "0x5ecf",
"input": "0xcafa81dc000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001a4cbd4ece900000000000000000000000010e6593cdda8c58a1d0f14c5164b376352a55f2f000000000000000000000000467194771dae2967aef3ecbedd3bf9a310c76c650000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000001b05e00000000000000000000000000000000000000000000000000000000000000e4a9f9e6750000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000da10009cbd5d07dd0cecc66161fc93d7c9000da10000000000000000000000006659612eb0e2464ccadf7a5e851bcd12873f6e040000000000000000000000006659612eb0e2464ccadf7a5e851bcd12873f6e04000000000000000000000000000000000000000000021165458500521280000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"output": "0x",
"to": "0x4200000000000000000000000000000000000000",
"type": "CALL",
"value": "0x0"
}
],
"from": "0x467194771dae2967aef3ecbedd3bf9a310c76c65",
"gas": "0xff92",
"gasUsed": "0xf705",
"input": "0x3dbb202b00000000000000000000000010e6593cdda8c58a1d0f14c5164b376352a55f2f0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e4a9f9e6750000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000da10009cbd5d07dd0cecc66161fc93d7c9000da10000000000000000000000006659612eb0e2464ccadf7a5e851bcd12873f6e040000000000000000000000006659612eb0e2464ccadf7a5e851bcd12873f6e04000000000000000000000000000000000000000000021165458500521280000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"output": "0x",
"to": "0x4200000000000000000000000000000000000007",
"type": "CALL",
"value": "0x0"
}
],
"from": "0x6659612eb0e2464ccadf7a5e851bcd12873f6e04",
"gas": "0x16bb3",
"gasUsed": "0x16bb3",
"input": "0x32b7006d000000000000000000000000da10009cbd5d07dd0cecc66161fc93d7c9000da10000000000000000000000000000000000000000000211654585005212800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000",
"output": "0x",
"time": "30.357952ms",
"to": "0x467194771dae2967aef3ecbedd3bf9a310c76c65",
"type": "CALL",
"value": "0x0"
}
{
"blockHash": "0x4f5fdc9747712cb61871d6d35618a6580671d5ddb85796c9d0790453509cf4cc",
"blockNumber": "0x169900c",
"contractAddress": null,
"cumulativeGasUsed": "0x1c2ca",
"from": "0x9c8f005ab27adb94f3d49020a15722db2fcd9f27",
"gasUsed": "0x1c2ca",
"logs": [
{
"address": "0xdeaddeaddeaddeaddeaddeaddeaddeaddead0000",
"blockHash": "0x4f5fdc9747712cb61871d6d35618a6580671d5ddb85796c9d0790453509cf4cc",
"blockNumber": "0x169900c",
"data": "0x00000000000000000000000000000000000000000000000000232bff5f46c000",
"logIndex": "0x0",
"removed": false,
"topics": [
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"0x0000000000000000000000009c8f005ab27adb94f3d49020a15722db2fcd9f27",
"0x0000000000000000000000000000000000000000000000000000000000000000"
],
"transactionHash": "0x26b854fe0b8f0c5ad15d5c3c1291107cc870f5d7351cfc399e23e68f22231fbe",
"transactionIndex": "0x0"
},
{
"address": "0xdeaddeaddeaddeaddeaddeaddeaddeaddead0000",
"blockHash": "0x4f5fdc9747712cb61871d6d35618a6580671d5ddb85796c9d0790453509cf4cc",
"blockNumber": "0x169900c",
"data": "0x00000000000000000000000000000000000000000000000000232bff5f46c000",
"logIndex": "0x1",
"removed": false,
"topics": [
"0xcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5",
"0x0000000000000000000000009c8f005ab27adb94f3d49020a15722db2fcd9f27"
],
"transactionHash": "0x26b854fe0b8f0c5ad15d5c3c1291107cc870f5d7351cfc399e23e68f22231fbe",
"transactionIndex": "0x0"
},
{
"address": "0x4200000000000000000000000000000000000007",
"blockHash": "0x4f5fdc9747712cb61871d6d35618a6580671d5ddb85796c9d0790453509cf4cc",
"blockNumber": "0x169900c",
"data": "0x00000000000000000000000042000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000001b04d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a41532ec340000000000000000000000009c8f005ab27adb94f3d49020a15722db2fcd9f270000000000000000000000009c8f005ab27adb94f3d49020a15722db2fcd9f2700000000000000000000000000000000000000000000000000232bff5f46c0000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"logIndex": "0x2",
"removed": false,
"topics": [
"0xcb0f7ffd78f9aee47a248fae8db181db6eee833039123e026dcbff529522e52a",
"0x00000000000000000000000099c9fc46f92e8a1c0dec1b1747d010903e884be1"
],
"transactionHash": "0x26b854fe0b8f0c5ad15d5c3c1291107cc870f5d7351cfc399e23e68f22231fbe",
"transactionIndex": "0x0"
},
{
"address": "0x4200000000000000000000000000000000000010",
"blockHash": "0x4f5fdc9747712cb61871d6d35618a6580671d5ddb85796c9d0790453509cf4cc",
"blockNumber": "0x169900c",
"data": "0x0000000000000000000000009c8f005ab27adb94f3d49020a15722db2fcd9f2700000000000000000000000000000000000000000000000000232bff5f46c00000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000",
"logIndex": "0x3",
"removed": false,
"topics": [
"0x73d170910aba9e6d50b102db522b1dbcd796216f5128b445aa2135272886497e",
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x000000000000000000000000deaddeaddeaddeaddeaddeaddeaddeaddead0000",
"0x0000000000000000000000009c8f005ab27adb94f3d49020a15722db2fcd9f27"
],
"transactionHash": "0x26b854fe0b8f0c5ad15d5c3c1291107cc870f5d7351cfc399e23e68f22231fbe",
"transactionIndex": "0x0"
}
],
"logsBloom": "0x00000000000000000010000000000000000000000000001000100000001000000000000000000080000000000000008000000800000000000000000000000240000000000000000040000008000000000000000000000000000000004000000100000000020000000000000000000800080000000000000000000010000000000001000000000000000000000000000000800000000000000020000000200000000000000000000001000000000000000000200000000000000000000000000000000002010000000000000400000000000002100000000008000004000020001000000000000000000000000000000100000000000000000000000000000000",
"status": "0x1",
"to": "0x4200000000000000000000000000000000000010",
"transactionHash": "0x26b854fe0b8f0c5ad15d5c3c1291107cc870f5d7351cfc399e23e68f22231fbe",
"transactionIndex": "0x0"
}
{
"blockHash": "0x13bf6e592e572c0a021488b6f2d910114be3491fc08a35f2ee2b38063df24abf",
"blockNumber": "0x169a45d",
"contractAddress": null,
"cumulativeGasUsed": "0x1c49a",
"from": "0x3178490d60b5cceaa5a79fd4d9050c7405bab80c",
"gasUsed": "0x1c49a",
"logs": [
{
"address": "0x76fb31fb4af56892a25e32cfc43de717950c9278",
"blockHash": "0x13bf6e592e572c0a021488b6f2d910114be3491fc08a35f2ee2b38063df24abf",
"blockNumber": "0x169a45d",
"data": "0x0000000000000000000000000000000000000000000000a3b61828488b117259",
"logIndex": "0x0",
"removed": false,
"topics": [
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"0x0000000000000000000000003178490d60b5cceaa5a79fd4d9050c7405bab80c",
"0x0000000000000000000000000000000000000000000000000000000000000000"
],
"transactionHash": "0x32d3b5a0178a33cfbf904cfd36f66a13ff8576f409f15aae86dc3ff0e101c93a",
"transactionIndex": "0x0"
},
{
"address": "0x76fb31fb4af56892a25e32cfc43de717950c9278",
"blockHash": "0x13bf6e592e572c0a021488b6f2d910114be3491fc08a35f2ee2b38063df24abf",
"blockNumber": "0x169a45d",
"data": "0x0000000000000000000000000000000000000000000000a3b61828488b117259",
"logIndex": "0x1",
"removed": false,
"topics": [
"0xcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5",
"0x0000000000000000000000003178490d60b5cceaa5a79fd4d9050c7405bab80c"
],
"transactionHash": "0x32d3b5a0178a33cfbf904cfd36f66a13ff8576f409f15aae86dc3ff0e101c93a",
"transactionIndex": "0x0"
},
{
"address": "0x4200000000000000000000000000000000000007",
"blockHash": "0x13bf6e592e572c0a021488b6f2d910114be3491fc08a35f2ee2b38063df24abf",
"blockNumber": "0x169a45d",
"data": "0x00000000000000000000000042000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000001b04f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e4a9f9e6750000000000000000000000007fc66500c84a76ad7e9c93437bfc5ac33e2ddae900000000000000000000000076fb31fb4af56892a25e32cfc43de717950c92780000000000000000000000003178490d60b5cceaa5a79fd4d9050c7405bab80c0000000000000000000000003178490d60b5cceaa5a79fd4d9050c7405bab80c0000000000000000000000000000000000000000000000a3b61828488b11725900000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"logIndex": "0x2",
"removed": false,
"topics": [
"0xcb0f7ffd78f9aee47a248fae8db181db6eee833039123e026dcbff529522e52a",
"0x00000000000000000000000099c9fc46f92e8a1c0dec1b1747d010903e884be1"
],
"transactionHash": "0x32d3b5a0178a33cfbf904cfd36f66a13ff8576f409f15aae86dc3ff0e101c93a",
"transactionIndex": "0x0"
},
{
"address": "0x4200000000000000000000000000000000000010",
"blockHash": "0x13bf6e592e572c0a021488b6f2d910114be3491fc08a35f2ee2b38063df24abf",
"blockNumber": "0x169a45d",
"data": "0x0000000000000000000000003178490d60b5cceaa5a79fd4d9050c7405bab80c0000000000000000000000000000000000000000000000a3b61828488b11725900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000",
"logIndex": "0x3",
"removed": false,
"topics": [
"0x73d170910aba9e6d50b102db522b1dbcd796216f5128b445aa2135272886497e",
"0x0000000000000000000000007fc66500c84a76ad7e9c93437bfc5ac33e2ddae9",
"0x00000000000000000000000076fb31fb4af56892a25e32cfc43de717950c9278",
"0x0000000000000000000000003178490d60b5cceaa5a79fd4d9050c7405bab80c"
],
"transactionHash": "0x32d3b5a0178a33cfbf904cfd36f66a13ff8576f409f15aae86dc3ff0e101c93a",
"transactionIndex": "0x0"
}
],
"logsBloom": "0x00000000000000000010000000000000000000000000001000100000001000000000000000000080000000000000008000000000000000000000040000000000000000000000000040000008000000000000100000000000000000004000000000000000020000000000000000000820080000000000000000000010014000000001000000000000000000000000000000800000000000000004000000200000000000000000000001000000000000000000200000000000000000000000000000000002000000000000000400000000000002100400000008000000000020000000000000000000000010000000000000000000000000002000000000248000",
"status": "0x1",
"to": "0x4200000000000000000000000000000000000010",
"transactionHash": "0x32d3b5a0178a33cfbf904cfd36f66a13ff8576f409f15aae86dc3ff0e101c93a",
"transactionIndex": "0x0"
}
{
"blockHash": "0x1fae89e0362ec677f76f7f3b7693b0dc05de5b5e1c4f34ee9add4339cb6391b6",
"blockNumber": "0x16a58e2",
"contractAddress": null,
"cumulativeGasUsed": "0x1aef3",
"from": "0x6659612eb0e2464ccadf7a5e851bcd12873f6e04",
"gasUsed": "0x1aef3",
"logs": [
{
"address": "0xda10009cbd5d07dd0cecc66161fc93d7c9000da1",
"blockHash": "0x1fae89e0362ec677f76f7f3b7693b0dc05de5b5e1c4f34ee9add4339cb6391b6",
"blockNumber": "0x16a58e2",
"data": "0x0000000000000000000000000000000000000000000211654585005212800000",
"logIndex": "0x0",
"removed": false,
"topics": [
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"0x0000000000000000000000006659612eb0e2464ccadf7a5e851bcd12873f6e04",
"0x0000000000000000000000000000000000000000000000000000000000000000"
],
"transactionHash": "0x38236157c6941ef64f4dd0dfa7efed4a82ef9fccdcdda75a8ee89cbe831b182b",
"transactionIndex": "0x0"
},
{
"address": "0x4200000000000000000000000000000000000007",
"blockHash": "0x1fae89e0362ec677f76f7f3b7693b0dc05de5b5e1c4f34ee9add4339cb6391b6",
"blockNumber": "0x16a58e2",
"data": "0x000000000000000000000000467194771dae2967aef3ecbedd3bf9a310c76c650000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000001b05e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e4a9f9e6750000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000da10009cbd5d07dd0cecc66161fc93d7c9000da10000000000000000000000006659612eb0e2464ccadf7a5e851bcd12873f6e040000000000000000000000006659612eb0e2464ccadf7a5e851bcd12873f6e04000000000000000000000000000000000000000000021165458500521280000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"logIndex": "0x1",
"removed": false,
"topics": [
"0xcb0f7ffd78f9aee47a248fae8db181db6eee833039123e026dcbff529522e52a",
"0x00000000000000000000000010e6593cdda8c58a1d0f14c5164b376352a55f2f"
],
"transactionHash": "0x38236157c6941ef64f4dd0dfa7efed4a82ef9fccdcdda75a8ee89cbe831b182b",
"transactionIndex": "0x0"
},
{
"address": "0x467194771dae2967aef3ecbedd3bf9a310c76c65",
"blockHash": "0x1fae89e0362ec677f76f7f3b7693b0dc05de5b5e1c4f34ee9add4339cb6391b6",
"blockNumber": "0x16a58e2",
"data": "0x0000000000000000000000006659612eb0e2464ccadf7a5e851bcd12873f6e04000000000000000000000000000000000000000000021165458500521280000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000",
"logIndex": "0x2",
"removed": false,
"topics": [
"0x73d170910aba9e6d50b102db522b1dbcd796216f5128b445aa2135272886497e",
"0x0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f",
"0x000000000000000000000000da10009cbd5d07dd0cecc66161fc93d7c9000da1",
"0x0000000000000000000000006659612eb0e2464ccadf7a5e851bcd12873f6e04"
],
"transactionHash": "0x38236157c6941ef64f4dd0dfa7efed4a82ef9fccdcdda75a8ee89cbe831b182b",
"transactionIndex": "0x0"
}
],
"logsBloom": "0x000000000000008000100000000000000000000000000000001000000010000000000000000000800000000000000080000000000000000000000000000000c0000000000000000041000008000080000000000000000000000000000000008000400000020000000000000000000800000000000000000000002010000000200000000100000000000000000000000000000000800000000000000400000200000000000000000001000000010000000000000000000000000000000000000000000002000000000000000400000000200000100000000000000000000020000000000020000000000800000000000000000000000000100000000000000000",
"status": "0x1",
"to": "0x467194771dae2967aef3ecbedd3bf9a310c76c65",
"transactionHash": "0x38236157c6941ef64f4dd0dfa7efed4a82ef9fccdcdda75a8ee89cbe831b182b",
"transactionIndex": "0x0"
}
{
"blockHash": "0x8a150d06f327859edb6e45e347105df56e047c690617d784c7aadedd0d426ff9",
"blockNumber": "0x1698be0",
"contractAddress": null,
"cumulativeGasUsed": "0x36ebf",
"from": "0x90f1cb932dbf94385434c40d53df3727f00e50b1",
"gasUsed": "0x36ebf",
"logs": [
{
"address": "0x8700daec35af8ff88c16bdf0418774cb3d7599b4",
"blockHash": "0x8a150d06f327859edb6e45e347105df56e047c690617d784c7aadedd0d426ff9",
"blockNumber": "0x1698be0",
"data": "0x0000000000000000000000000000000000000000000001c9f23e7ccc897c65e5",
"logIndex": "0x0",
"removed": false,
"topics": [
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"0x00000000000000000000000090f1cb932dbf94385434c40d53df3727f00e50b1",
"0x0000000000000000000000000000000000000000000000000000000000000000"
],
"transactionHash": "0xed57a510022157b14542491a501daed1d58003e4b274b331d2fc40dcc43f0941",
"transactionIndex": "0x0"
},
{
"address": "0x4200000000000000000000000000000000000007",
"blockHash": "0x8a150d06f327859edb6e45e347105df56e047c690617d784c7aadedd0d426ff9",
"blockNumber": "0x1698be0",
"data": "0x000000000000000000000000136b1ec699c62b0606854056f02dc7bb80482d630000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000001b04c00000000000000000000000000000000000000000000000000000000002dc6c00000000000000000000000000000000000000000000000000000000000000044f4f7b41a00000000000000000000000090f1cb932dbf94385434c40d53df3727f00e50b10000000000000000000000000000000000000000000001c9f23e7ccc897c65e500000000000000000000000000000000000000000000000000000000",
"logIndex": "0x1",
"removed": false,
"topics": [
"0xcb0f7ffd78f9aee47a248fae8db181db6eee833039123e026dcbff529522e52a",
"0x00000000000000000000000039ea01a0298c315d149a490e34b59dbf2ec7e48f"
],
"transactionHash": "0xed57a510022157b14542491a501daed1d58003e4b274b331d2fc40dcc43f0941",
"transactionIndex": "0x0"
},
{
"address": "0x136b1ec699c62b0606854056f02dc7bb80482d63",
"blockHash": "0x8a150d06f327859edb6e45e347105df56e047c690617d784c7aadedd0d426ff9",
"blockNumber": "0x1698be0",
"data": "0x00000000000000000000000090f1cb932dbf94385434c40d53df3727f00e50b10000000000000000000000000000000000000000000001c9f23e7ccc897c65e5",
"logIndex": "0x2",
"removed": false,
"topics": [
"0xbb2689ff876f7ef453cf8865dde5ab10349d222e2e1383c5152fbdb083f02da2",
"0x00000000000000000000000090f1cb932dbf94385434c40d53df3727f00e50b1"
],
"transactionHash": "0xed57a510022157b14542491a501daed1d58003e4b274b331d2fc40dcc43f0941",
"transactionIndex": "0x0"
}
],
"logsBloom": "0x00000000000000000010000000000040000000000000000000000000081000000000000000000080000000000000008000000000000000001000000000000000000000080000000041000008000000000000000000000000000000000000080000100000020000000000000200000800000000000000000000000010000000000002000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000002000000000200000000000001000000100000000000000000000020020000000000000000000000000000000000000000000000800000000000000000",
"status": "0x1",
"to": "0x136b1ec699c62b0606854056f02dc7bb80482d63",
"transactionHash": "0xed57a510022157b14542491a501daed1d58003e4b274b331d2fc40dcc43f0941",
"transactionIndex": "0x0"
}
#!/bin/bash
HASH=$1
if [[ -z $HASH ]]; then
exit 1
fi
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" > /dev/null && pwd )"
TRACES=$DIR/call-traces
RECEIPTS=$DIR/receipts
DIFFS=$DIR/state-diffs
mkdir -p $TRACES
mkdir -p $RECEIPTS
mkdir -p $DIFFS
cast rpc \
debug_traceTransaction \
$HASH \
'{"tracer": "callTracer"}' | jq > $TRACES/$HASH.json
cast receipt $HASH --json | jq > $RECEIPTS/$HASH.json
cast rpc \
debug_traceTransaction \
$HASH \
'{"tracer": "prestateTracer"}' | jq > $DIFFS/$HASH.json
package crossdomain
import (
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
)
var (
// Standard ABI types
Uint256Type, _ = abi.NewType("uint256", "", nil)
BytesType, _ = abi.NewType("bytes", "", nil)
AddressType, _ = abi.NewType("address", "", nil)
)
// WithdrawalMessage represents a Withdrawal. The Withdrawal
// and LegacyWithdrawal types must implement this interface.
type WithdrawalMessage interface {
Encode() ([]byte, error)
Decode([]byte) error
Hash() (common.Hash, error)
StorageSlot() (common.Hash, error)
}
package crossdomain
import (
"errors"
"math/big"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
)
var _ WithdrawalMessage = (*Withdrawal)(nil)
// Withdrawal represents a withdrawal transaction on L2
type Withdrawal struct {
Nonce *big.Int
Sender *common.Address
Target *common.Address
Value *big.Int
GasLimit *big.Int
Data []byte
}
// NewWithdrawal will create a Withdrawal
func NewWithdrawal(
nonce *big.Int,
sender, target *common.Address,
value, gasLimit *big.Int,
data []byte,
) *Withdrawal {
return &Withdrawal{
Nonce: nonce,
Sender: sender,
Target: target,
Value: value,
GasLimit: gasLimit,
Data: data,
}
}
// Encode will serialize the Withdrawal so that it is suitable for hashing.
func (w *Withdrawal) Encode() ([]byte, error) {
args := abi.Arguments{
{Name: "nonce", Type: Uint256Type},
{Name: "sender", Type: AddressType},
{Name: "target", Type: AddressType},
{Name: "value", Type: Uint256Type},
{Name: "gasLimit", Type: Uint256Type},
{Name: "data", Type: BytesType},
}
enc, err := args.Pack(w.Nonce, w.Sender, w.Target, w.Value, w.GasLimit, w.Data)
if err != nil {
return nil, err
}
return enc, nil
}
// Decode will deserialize a Withdrawal
func (w *Withdrawal) Decode(data []byte) error {
args := abi.Arguments{
{Name: "nonce", Type: Uint256Type},
{Name: "sender", Type: AddressType},
{Name: "target", Type: AddressType},
{Name: "value", Type: Uint256Type},
{Name: "gasLimit", Type: Uint256Type},
{Name: "data", Type: BytesType},
}
decoded, err := args.Unpack(data)
if err != nil {
return err
}
nonce, ok := decoded[0].(*big.Int)
if !ok {
return errors.New("cannot abi decode nonce")
}
sender, ok := decoded[1].(common.Address)
if !ok {
return errors.New("cannot abi decode sender")
}
target, ok := decoded[2].(common.Address)
if !ok {
return errors.New("cannot abi decode target")
}
value, ok := decoded[3].(*big.Int)
if !ok {
return errors.New("cannot abi decode value")
}
gasLimit, ok := decoded[4].(*big.Int)
if !ok {
return errors.New("cannot abi decode gasLimit")
}
msgData, ok := decoded[5].([]byte)
if !ok {
return errors.New("cannot abi decode data")
}
w.Nonce = nonce
w.Sender = &sender
w.Target = &target
w.Value = value
w.GasLimit = gasLimit
w.Data = msgData
return nil
}
// Hash will hash the Withdrawal. This is the hash that is computed in
// the L2ToL1MessagePasser. The encoding is the same as the v1 cross domain
// message encoding without the 4byte selector prepended.
func (w *Withdrawal) Hash() (common.Hash, error) {
encoded, err := w.Encode()
if err != nil {
return common.Hash{}, err
}
hash := crypto.Keccak256(encoded)
return common.BytesToHash(hash), nil
}
// StorageSlot will compute the storage slot that will be set to
// true in the L2ToL1MessagePasser. The withdrawal proof sent to
// L1 will prove that this storage slot is set to "true".
func (w *Withdrawal) StorageSlot() (common.Hash, error) {
hash, err := w.Hash()
if err != nil {
return common.Hash{}, err
}
preimage := make([]byte, 64)
copy(preimage, hash.Bytes())
slot := crypto.Keccak256(preimage)
return common.BytesToHash(slot), nil
}
package crossdomain_test
import (
"fmt"
"math/big"
"testing"
"github.com/ethereum-optimism/optimism/op-chain-ops/crossdomain"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/stretchr/testify/require"
)
// FuzzEncodeDecodeWithdrawal will fuzz encoding and decoding of a Withdrawal
func FuzzEncodeDecodeWithdrawal(f *testing.F) {
f.Fuzz(func(t *testing.T, _nonce, _sender, _target, _value, _gasLimit, data []byte) {
nonce := new(big.Int).SetBytes(_nonce)
sender := common.BytesToAddress(_sender)
target := common.BytesToAddress(_target)
value := new(big.Int).SetBytes(_value)
gasLimit := new(big.Int).SetBytes(_gasLimit)
withdrawal := crossdomain.NewWithdrawal(
nonce,
&sender,
&target,
value,
gasLimit,
data,
)
encoded, err := withdrawal.Encode()
require.Nil(t, err)
var w crossdomain.Withdrawal
err = w.Decode(encoded)
require.Nil(t, err)
require.Equal(t, withdrawal.Nonce.Uint64(), w.Nonce.Uint64())
require.Equal(t, withdrawal.Sender, w.Sender)
require.Equal(t, withdrawal.Target, w.Target)
require.Equal(t, withdrawal.Value.Uint64(), w.Value.Uint64())
require.Equal(t, withdrawal.GasLimit.Uint64(), w.GasLimit.Uint64())
require.Equal(t, withdrawal.Data, w.Data)
})
}
// TestWithdrawalHashing will test the correct computation of Withdrawal hashes
// and the storage slot that the withdrawal hash is stored in. Test vectors
// generated with forge
func TestWithdrawalHashing(t *testing.T) {
type expect struct {
Hash common.Hash
Slot common.Hash
}
cases := []struct {
Withdrawal *crossdomain.Withdrawal
Expect expect
}{
{
Withdrawal: crossdomain.NewWithdrawal(
big.NewInt(0),
ptr(common.HexToAddress("0xaa179e0640054db6ba4fe9b291dd3b248f4b4960")),
ptr(common.HexToAddress("0x9b2b72e299e04f00fc5b386972d8951bb870d65e")),
big.NewInt(1),
decimalStringToBig("124808255574871339965699013847079823271"),
hexutil.MustDecode("0x2e1d8f26c6611c04d9f8ea352444b9d366f76c19897c851f5ce9a4d650cf2355f92da68491af279f78110a31c6cb26db09b20b3b1307ff99be0bc410d8bf6994b0e87ced86b747773597dfd1da84268508e34a46a087088ed9276738ffe39e7a1264"),
),
Expect: expect{
Hash: common.HexToHash("0xbddee6e1e89962069cb559abae8342ea3490f9488509c22c482c4ba73988165c"),
Slot: common.HexToHash("0x26bea3ec4f60cfc1152358454086b7f6a3b669d84a0ec088b2e316ff88c2a892"),
},
},
{
Withdrawal: crossdomain.NewWithdrawal(
big.NewInt(0),
ptr(common.HexToAddress("0x00000000000000000000000000000000000011bc")),
ptr(common.HexToAddress("0x00000000000000000000000000000000000033eb")),
big.NewInt(26),
decimalStringToBig("22338"),
hexutil.MustDecode("0x0000000000000000000000000000000000000000000000000000000000000004"),
),
Expect: expect{
Hash: common.HexToHash("0x65768976d27ba8a7f91c5b267b97d29830103171863c0ba24f3234ef07d0f8e3"),
Slot: common.HexToHash("0xd73bc49fa8e52d7717fb65cbec7ff0e30bf4e2fbbd38924d1b2efa1f96381517"),
},
},
{
Withdrawal: crossdomain.NewWithdrawal(
big.NewInt(0),
ptr(common.HexToAddress("0x4b0ca57cb88a41771d2cc24ac9fd50afeaa3eedd")),
ptr(common.HexToAddress("0x8a5e8410b2c3e1036c49ff8acae1e659e2508200")),
big.NewInt(3),
decimalStringToBig("115792089237316195423570985008687907853269984665640564039457584007913129639935"),
hexutil.MustDecode("0xce6b96a23be7a1ac1de74f3202dfc4cedaef69502204c0d92f7b352a837a"),
),
Expect: expect{
Hash: common.HexToHash("0x4ba164b689ac62c27c68f41b5f3c4731eb2c25c2d39e4aadcc413d150764624f"),
Slot: common.HexToHash("0xf055f7cec6a95c9bfc93fc2dc0262d2323a7d4e74af5ee608f0fe2acc83fa1ef"),
},
},
}
for i, test := range cases {
t.Run(fmt.Sprintf("case%d", i), func(t *testing.T) {
hash, err := test.Withdrawal.Hash()
require.Nil(t, err)
require.Equal(t, hash, test.Expect.Hash)
slot, err := test.Withdrawal.StorageSlot()
require.Nil(t, err)
require.Equal(t, slot, test.Expect.Slot)
})
}
}
func decimalStringToBig(n string) *big.Int {
ret, ok := new(big.Int).SetString(n, 10)
if !ok {
panic("")
}
return ret
}
func ptr(i common.Address) *common.Address {
return &i
}
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