diff --git a/op-batcher/batcher/driver.go b/op-batcher/batcher/driver.go index f2324145b905e..a1ca679dd5cd1 100644 --- a/op-batcher/batcher/driver.go +++ b/op-batcher/batcher/driver.go @@ -378,13 +378,15 @@ func (l *BatchSubmitter) sendTransaction(ctx context.Context, txdata txData, que data := txdata.Bytes() // if plasma DA is enabled we post the txdata to the DA Provider and replace it with the commitment. if l.Config.UsePlasma { - data, err = l.PlasmaDA.SetInput(ctx, data) + comm, err := l.PlasmaDA.SetInput(ctx, data) if err != nil { l.Log.Error("Failed to post input to Plasma DA", "error", err) // requeue frame if we fail to post to the DA Provider so it can be retried l.recordFailedTx(txdata, err) return nil } + // signal plasma commitment tx with TxDataVersion1 + data = comm.TxData(derive.TxDataVersion1) } var candidate *txmgr.TxCandidate diff --git a/op-e2e/actions/l2_batcher.go b/op-e2e/actions/l2_batcher.go index 8427d33be8628..5afbf2a1da2d6 100644 --- a/op-e2e/actions/l2_batcher.go +++ b/op-e2e/actions/l2_batcher.go @@ -253,7 +253,7 @@ func (s *L2Batcher) ActL2BatchSubmit(t Testing, txOpts ...func(tx *types.Dynamic if s.l2BatcherCfg.UsePlasma { comm, err := s.l2BatcherCfg.PlasmaDA.SetInput(t.Ctx(), payload) require.NoError(t, err, "failed to set input for plasma") - payload = comm.Encode() + payload = comm.TxData(derive.TxDataVersion1) } nonce, err := s.l1.PendingNonceAt(t.Ctx(), s.batcherAddr) diff --git a/op-e2e/actions/plasma_test.go b/op-e2e/actions/plasma_test.go index 619f608c6ea3c..e93718f147d55 100644 --- a/op-e2e/actions/plasma_test.go +++ b/op-e2e/actions/plasma_test.go @@ -159,7 +159,8 @@ func (a *L2PlasmaDA) ActNewL2Tx(t Testing) { a.batcher.ActL2BatchBuffer(t) a.batcher.ActL2ChannelClose(t) a.batcher.ActL2BatchSubmit(t, func(tx *types.DynamicFeeTx) { - a.lastComm = tx.Data + // skip txdata version byte + a.lastComm = tx.Data[1:] }) a.miner.ActL1StartBlock(3)(t) diff --git a/op-node/rollup/derive/params.go b/op-node/rollup/derive/params.go index bba78cc2dfee1..8784ae0584564 100644 --- a/op-node/rollup/derive/params.go +++ b/op-node/rollup/derive/params.go @@ -19,6 +19,11 @@ func frameSize(frame Frame) uint64 { const DerivationVersion0 = 0 +// TxDataVersion1 is the version number for batcher transactions containing +// plasma inputs. It should not collide with DerivationVersion which is still +// used downstream when parsing the frames. +const TxDataVersion1 = 1 + // MaxSpanBatchSize is the maximum amount of bytes that will be needed // to decode every span batch field. This value cannot be larger than // MaxRLPBytesPerChannel because single batch cannot be larger than channel size. diff --git a/op-node/rollup/derive/plasma_data_source.go b/op-node/rollup/derive/plasma_data_source.go index 3e0ab1610166b..8feb7f8edea74 100644 --- a/op-node/rollup/derive/plasma_data_source.go +++ b/op-node/rollup/derive/plasma_data_source.go @@ -43,14 +43,19 @@ func (s *PlasmaDataSource) Next(ctx context.Context) (eth.Data, error) { } if s.comm == nil { - var err error // the l1 source returns the input commitment for the batch. data, err := s.src.Next(ctx) if err != nil { return nil, err } + // If the tx data type is not plasma, we forward it downstream to let the next + // steps validate and potentially parse it as L1 DA inputs. + if data[0] != TxDataVersion1 { + return data, nil + } + // validate batcher inbox data is a commitment. - comm, err := plasma.DecodeKeccak256(data) + comm, err := plasma.DecodeKeccak256(data[1:]) if err != nil { s.log.Warn("invalid commitment", "data", fmt.Sprintf("%x", data), "err", err) return s.Next(ctx) diff --git a/op-node/rollup/derive/plasma_data_source_test.go b/op-node/rollup/derive/plasma_data_source_test.go index 94c8dc08621eb..fb68283c1f4d9 100644 --- a/op-node/rollup/derive/plasma_data_source_test.go +++ b/op-node/rollup/derive/plasma_data_source_test.go @@ -137,7 +137,7 @@ func TestPlasmaDataSource(t *testing.T) { Gas: 100_000, To: &batcherInbox, Value: big.NewInt(int64(0)), - Data: comm.Encode(), + Data: comm.TxData(TxDataVersion1), }) require.NoError(t, err) @@ -237,7 +237,7 @@ func TestPlasmaDataSource(t *testing.T) { Gas: 100_000, To: &batcherInbox, Value: big.NewInt(int64(0)), - Data: comm.Encode(), + Data: comm.TxData(TxDataVersion1), }) require.NoError(t, err) @@ -350,7 +350,7 @@ func TestPlasmaDataSourceStall(t *testing.T) { Gas: 100_000, To: &batcherInbox, Value: big.NewInt(int64(0)), - Data: comm.Encode(), + Data: comm.TxData(TxDataVersion1), }) require.NoError(t, err) @@ -453,7 +453,7 @@ func TestPlasmaDataSourceInvalidData(t *testing.T) { Gas: 100_000, To: &batcherInbox, Value: big.NewInt(int64(0)), - Data: comm.Encode(), + Data: comm.TxData(TxDataVersion1), }) require.NoError(t, err) @@ -468,11 +468,11 @@ func TestPlasmaDataSourceInvalidData(t *testing.T) { Gas: 100_000, To: &batcherInbox, Value: big.NewInt(int64(0)), - Data: comm2.Encode(), + Data: comm2.TxData(TxDataVersion1), }) require.NoError(t, err) - // invalid commitment + // regular input instead of commitment input3 := testutils.RandomData(rng, 32) tx3, err := types.SignNewTx(batcherPriv, signer, &types.DynamicFeeTx{ ChainID: signer.ChainID(), @@ -493,12 +493,16 @@ func TestPlasmaDataSourceInvalidData(t *testing.T) { src, err := factory.OpenData(ctx, ref, batcherAddr) require.NoError(t, err) - // oversized input should be skipped + // oversized input is skipped and returns input2 directly data, err := src.Next(ctx) require.NoError(t, err) require.Equal(t, hexutil.Bytes(input2), data) - // invalid commitment is skipped so should return an EOF + // regular input is passed through + data, err = src.Next(ctx) + require.NoError(t, err) + require.Equal(t, hexutil.Bytes(input3), data) + _, err = src.Next(ctx) require.ErrorIs(t, err, io.EOF) diff --git a/op-plasma/commitment.go b/op-plasma/commitment.go index e0f49e5384257..d63b7ffa313b3 100644 --- a/op-plasma/commitment.go +++ b/op-plasma/commitment.go @@ -27,6 +27,11 @@ func (c Keccak256Commitment) Encode() []byte { return append([]byte{byte(Keccak256CommitmentType)}, c...) } +// TxData adds an extra version byte to signal it's a commitment. +func (c Keccak256Commitment) TxData(version uint8) []byte { + return append([]byte{version}, c.Encode()...) +} + // Verify checks if the commitment matches the given input. func (c Keccak256Commitment) Verify(input []byte) error { if !bytes.Equal(c, crypto.Keccak256(input)) {