From 05b1badb30b3e2d0cb40fd2097b31ad15662035a Mon Sep 17 00:00:00 2001 From: Joshua Gutow Date: Fri, 11 Mar 2022 11:32:01 -0800 Subject: [PATCH] ref impl: Add simple batch serialization --- opnode/rollup/derive/batch.go | 70 ++++++++++++++++++++++ opnode/rollup/derive/batch_test.go | 32 ++++++++++ opnode/rollup/derive/payload_attributes.go | 19 +++--- 3 files changed, 109 insertions(+), 12 deletions(-) create mode 100644 opnode/rollup/derive/batch.go create mode 100644 opnode/rollup/derive/batch_test.go diff --git a/opnode/rollup/derive/batch.go b/opnode/rollup/derive/batch.go new file mode 100644 index 000000000000..341fd8bacd25 --- /dev/null +++ b/opnode/rollup/derive/batch.go @@ -0,0 +1,70 @@ +package derive + +import ( + "bytes" + "errors" + + "github.com/ethereum-optimism/optimistic-specs/opnode/l2" + "github.com/ethereum-optimism/optimistic-specs/opnode/rollup" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/rlp" +) + +// Batch format +// first byte is type followed by bytstring. +// +// BatchV1Type := 0 +// BatchV1Type ++ RLP([epoch, timestamp, transaction_list] + +const ( + BatchV1Type = iota +) + +type BatchV1 struct { + Epoch uint64 + Timestamp uint64 + Transactions []hexutil.Bytes +} + +type BatchData struct { + Epoch rollup.Epoch // aka l1 num + Timestamp uint64 + // no feeRecipient address input, all fees go to a L2 contract + Transactions []l2.Data +} + +func ParseBatch(data []byte) (BatchData, error) { + var v1 BatchV1 + if err := v1.UnmarshalBinary(data); err != nil { + return BatchData{}, err + } + return BatchData{Epoch: rollup.Epoch(v1.Epoch), Timestamp: v1.Timestamp, Transactions: v1.Transactions}, nil +} + +// // TODO: Is this needed? +// // EncodeRLP implements rlp.Encoder +// func (b *BatchV1) EncodeRLP(w io.Writer) error { +// return rlp.Encode(w, b) +// } + +// MarshalBinary returns the canonical encoding of the batch. +func (b *BatchV1) MarshalBinary() ([]byte, error) { + var buf bytes.Buffer + buf.WriteByte(BatchV1Type) + err := rlp.Encode(&buf, b) + return buf.Bytes(), err +} + +// // TODO: Is this needed? +// // DecodeRLP implements rlp.Decoder +// func (b *BatchV1) DecodeRLP(s *rlp.Stream) error { +// return s.Decode(b) +// } + +// UnmarshalBinary decodes the canonical encoding of batch. +func (batch *BatchV1) UnmarshalBinary(b []byte) error { + if len(b) == 0 { + return errors.New("Batch too short") + } + return rlp.DecodeBytes(b[1:], batch) +} diff --git a/opnode/rollup/derive/batch_test.go b/opnode/rollup/derive/batch_test.go new file mode 100644 index 000000000000..e4776729cae7 --- /dev/null +++ b/opnode/rollup/derive/batch_test.go @@ -0,0 +1,32 @@ +package derive + +import ( + "testing" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/stretchr/testify/assert" +) + +func TestBatchRoundTrip(t *testing.T) { + batches := []BatchV1{ + { + Epoch: 0, + Timestamp: 0, + Transactions: []hexutil.Bytes{}, + }, + { + Epoch: 1, + Timestamp: 1647026951, + Transactions: []hexutil.Bytes{[]byte{0, 0, 0}, []byte{0x76, 0xfd, 0x7c}}, + }, + } + + for i, batch := range batches { + enc, err := batch.MarshalBinary() + assert.NoError(t, err) + var dec BatchV1 + err = dec.UnmarshalBinary(enc) + assert.NoError(t, err) + assert.Equal(t, batch, dec, "Batch not equal test case %v", i) + } +} diff --git a/opnode/rollup/derive/payload_attributes.go b/opnode/rollup/derive/payload_attributes.go index 662117525bff..6b2ca501b633 100644 --- a/opnode/rollup/derive/payload_attributes.go +++ b/opnode/rollup/derive/payload_attributes.go @@ -186,13 +186,19 @@ func BatchesFromEVMTransactions(config *rollup.Config, txs []*types.Transaction) if to := tx.To(); to != nil && *to == config.BatchInboxAddress { seqDataSubmitter, err := l1Signer.Sender(tx) if err != nil { + // TODO: log error continue // bad signature, ignore } // some random L1 user might have sent a transaction to our batch inbox, ignore them if seqDataSubmitter != config.BatchSenderAddress { continue // not an authorized batch submitter, ignore } - out = append(out, ParseBatches(tx.Data())...) + batch, err := ParseBatch(tx.Data()) + if err != nil { + // TODO: log error + continue + } + out = append(out, batch) } } return @@ -328,14 +334,3 @@ func DeriveDeposits(l1Info L1Info, receipts []*types.Receipt) ([]l2.Data, error) } return encodedTxs, nil } - -type BatchData struct { - Epoch rollup.Epoch // aka l1 num - Timestamp uint64 - // no feeRecipient address input, all fees go to a L2 contract - Transactions []l2.Data -} - -func ParseBatches(data l2.Data) []BatchData { - return nil // TODO -}