From c511b806d03a7a67b70b360904b2e24165a8effe Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Thu, 19 Sep 2024 13:13:06 +0200 Subject: [PATCH 1/5] feat: wip --- sequencesender/txbuilder/banana_base.go | 16 ++++++++++ sequencesender/txbuilder/banana_base_test.go | 32 ++++++++++++++++++++ sequencesender/txbuilder/banana_types.go | 32 ++++++++++++++++++++ 3 files changed, 80 insertions(+) diff --git a/sequencesender/txbuilder/banana_base.go b/sequencesender/txbuilder/banana_base.go index 7b451ed8..91af8895 100644 --- a/sequencesender/txbuilder/banana_base.go +++ b/sequencesender/txbuilder/banana_base.go @@ -134,10 +134,26 @@ func (t *TxBuilderBananaBase) NewSequence( sequence.OldAccInputHash = oldAccInputHash sequence.AccInputHash = accInputHash + + err = SequenceSanityCheck(sequence) + if err != nil { + return nil, fmt.Errorf("sequenceSanityCheck fails. Err: %w", err) + } res := NewBananaSequence(*sequence) return res, nil } +func SequenceSanityCheck(seq *etherman.SequenceBanana) error { + maxL1InfoIndex, err := CalculateMaxL1InfoTreeIndexInsideSequence(seq) + if err != nil { + return err + } + if seq.CounterL1InfoRoot < maxL1InfoIndex+1 { + return fmt.Errorf("wrong CounterL1InfoRoot(%d): BatchL2Data (max=%d) ", seq.CounterL1InfoRoot, maxL1InfoIndex) + } + return nil +} + func (t *TxBuilderBananaBase) getL1InfoRoot(counterL1InfoRoot uint32) (common.Hash, error) { return t.globalExitRootContract.L1InfoRootMap(&bind.CallOpts{Pending: false}, counterL1InfoRoot) } diff --git a/sequencesender/txbuilder/banana_base_test.go b/sequencesender/txbuilder/banana_base_test.go index af4b05c0..29597e5b 100644 --- a/sequencesender/txbuilder/banana_base_test.go +++ b/sequencesender/txbuilder/banana_base_test.go @@ -5,11 +5,13 @@ import ( "math/big" "testing" + "github.com/0xPolygon/cdk/etherman" "github.com/0xPolygon/cdk/l1infotreesync" "github.com/0xPolygon/cdk/log" "github.com/0xPolygon/cdk/sequencesender/seqsendertypes" "github.com/0xPolygon/cdk/sequencesender/txbuilder" "github.com/0xPolygon/cdk/sequencesender/txbuilder/mocks_txbuilder" + "github.com/0xPolygon/cdk/state" "github.com/0xPolygon/cdk/state/datastream" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -79,6 +81,36 @@ func TestBananaBaseNewSequenceBatch(t *testing.T) { // TODO: check that the seq have the right values } +func TestBananaSanityCheck(t *testing.T) { + batch := state.BatchRawV2{ + Blocks: []state.L2BlockRaw{ + { + BlockNumber: 1, + ChangeL2BlockHeader: state.ChangeL2BlockHeader{ + DeltaTimestamp: 1, + IndexL1InfoTree: 1, + }, + }, + }, + } + data, err := state.EncodeBatchV2(&batch) + require.NoError(t, err) + require.NotNil(t, data) + seq := etherman.SequenceBanana{ + CounterL1InfoRoot: 2, + Batches: []etherman.Batch{ + { + L2Data: data, + }, + }, + } + err = txbuilder.SequenceSanityCheck(&seq) + require.NoError(t, err, "inside batchl2data max is 1 and counter is 2 (2>=1+1)") + seq.CounterL1InfoRoot = 1 + err = txbuilder.SequenceSanityCheck(&seq) + require.Error(t, err, "inside batchl2data max is 1 and counter is 1. The batchl2data is not included in counter") +} + type testDataBananaBase struct { rollupContract *mocks_txbuilder.RollupBananaBaseContractor getContract *mocks_txbuilder.GlobalExitRootBananaContractor diff --git a/sequencesender/txbuilder/banana_types.go b/sequencesender/txbuilder/banana_types.go index c09095b6..4f810c36 100644 --- a/sequencesender/txbuilder/banana_types.go +++ b/sequencesender/txbuilder/banana_types.go @@ -5,6 +5,7 @@ import ( "github.com/0xPolygon/cdk/etherman" "github.com/0xPolygon/cdk/sequencesender/seqsendertypes" + "github.com/0xPolygon/cdk/state" "github.com/ethereum/go-ethereum/common" ) @@ -147,3 +148,34 @@ func (b *BananaSequence) LastVirtualBatchNumber() uint64 { func (b *BananaSequence) SetLastVirtualBatchNumber(batchNumber uint64) { b.SequenceBanana.LastVirtualBatchNumber = batchNumber } + +func CalculateMaxL1InfoTreeIndexInsideL2Data(l2data []byte) (uint32, error) { + batchRawV2, err := state.DecodeBatchV2(l2data) + if err != nil { + return 0, fmt.Errorf("CalculateMaxL1InfoTreeIndexInsideL2Data: error decoding batchL2Data, err:%w", err) + } + if batchRawV2 == nil { + return 0, fmt.Errorf("CalculateMaxL1InfoTreeIndexInsideL2Data: batchRawV2 is nil") + } + maxIndex := uint32(0) + for i := range batchRawV2.Blocks { + if batchRawV2.Blocks[i].IndexL1InfoTree > maxIndex { + maxIndex = batchRawV2.Blocks[i].IndexL1InfoTree + } + } + return maxIndex, nil +} + +func CalculateMaxL1InfoTreeIndexInsideSequence(seq *etherman.SequenceBanana) (uint32, error) { + maxIndex := uint32(0) + for _, batch := range seq.Batches { + index, err := CalculateMaxL1InfoTreeIndexInsideL2Data(batch.L2Data) + if err != nil { + return 0, fmt.Errorf("CalculateMaxL1InfoTreeIndexInsideBatches: error getting batch L1InfoTree , err:%w", err) + } + if index > maxIndex { + maxIndex = index + } + } + return maxIndex, nil +} From c364fbbdba5cc7e45cedb1f5d1f80eeb59134ffd Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Thu, 19 Sep 2024 13:40:39 +0200 Subject: [PATCH 2/5] feat: wip --- sequencesender/sequencesender.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sequencesender/sequencesender.go b/sequencesender/sequencesender.go index 3431d3fe..0183f85c 100644 --- a/sequencesender/sequencesender.go +++ b/sequencesender/sequencesender.go @@ -1168,7 +1168,8 @@ func (s *SequenceSender) addInfoSequenceBatchEnd(batch *datastream.BatchEnd) { // addNewBatchL2Block adds a new L2 block to the work in progress batch func (s *SequenceSender) addNewBatchL2Block(l2Block *datastream.L2Block) { s.mutexSequence.Lock() - s.logger.Infof(".....new L2 block, number %d (batch %d)", l2Block.Number, l2Block.BatchNumber) + s.logger.Infof(".....new L2 block, number %d (batch %d) l1infotree %d", + l2Block.Number, l2Block.BatchNumber, l2Block.L1InfotreeIndex) // Current batch data := s.sequenceData[s.wipBatch] @@ -1183,7 +1184,11 @@ func (s *SequenceSender) addNewBatchL2Block(l2Block *datastream.L2Block) { ) } data.batch.SetLastCoinbase(common.BytesToAddress(l2Block.Coinbase)) - data.batch.SetL1InfoTreeIndex(l2Block.L1InfotreeIndex) + if l2Block.L1InfotreeIndex != 0 { + data.batch.SetL1InfoTreeIndex(l2Block.L1InfotreeIndex) + } else { + s.logger.Warnf("L1InfotreeIndex is 0, we don't change batch L1InfotreeIndex (%d)", data.batch.L1InfoTreeIndex()) + } // New L2 block raw newBlockRaw := state.L2BlockRaw{} From 722da752b9f2772a8341496a50de97e4d3ba5b06 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Thu, 19 Sep 2024 14:04:47 +0200 Subject: [PATCH 3/5] feat: wip --- sequencesender/sequencesender_test.go | 44 +++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/sequencesender/sequencesender_test.go b/sequencesender/sequencesender_test.go index c16fda42..f839cfca 100644 --- a/sequencesender/sequencesender_test.go +++ b/sequencesender/sequencesender_test.go @@ -4,7 +4,10 @@ import ( "testing" "github.com/0xPolygon/cdk/log" + "github.com/0xPolygon/cdk/sequencesender/txbuilder" "github.com/0xPolygon/cdk/state" + "github.com/0xPolygon/cdk/state/datastream" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" ) @@ -71,3 +74,44 @@ func TestStreamTx(t *testing.T) { printBatch(decodedBatch, true, true) } + +func TestAddNewBatchL2Block(t *testing.T) { + logger := log.GetDefaultLogger() + txBuilder := txbuilder.NewTxBuilderBananaZKEVM(logger, nil, nil, bind.TransactOpts{}, 100, nil, nil, nil) + sut := SequenceSender{ + logger: logger, + cfg: Config{}, + ethTransactions: make(map[common.Hash]*ethTxData), + ethTxData: make(map[common.Hash][]byte), + sequenceData: make(map[uint64]*sequenceData), + validStream: false, + latestStreamBatch: 0, + seqSendingStopped: false, + TxBuilder: txBuilder, + } + + l2Block := datastream.L2Block{ + Number: 1, + BatchNumber: 1, + L1InfotreeIndex: 1, + } + sut.addNewSequenceBatch(&l2Block) + l2Block = datastream.L2Block{ + Number: 2, + BatchNumber: 1, + L1InfotreeIndex: 0, + } + sut.addNewBatchL2Block(&l2Block) + data := sut.sequenceData[sut.wipBatch] + // L1InfotreeIndex 0 is ignored + require.Equal(t, uint32(1), data.batch.L1InfoTreeIndex(), "new block have index=0 and is ignored") + + l2Block = datastream.L2Block{ + Number: 2, + BatchNumber: 1, + L1InfotreeIndex: 5, + } + sut.addNewBatchL2Block(&l2Block) + data = sut.sequenceData[sut.wipBatch] + require.Equal(t, uint32(5), data.batch.L1InfoTreeIndex(), "new block have index=5 and is set") +} From 84c4282b544d1da944ce2c90fa9a5027302d6196 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Fri, 20 Sep 2024 11:16:50 +0200 Subject: [PATCH 4/5] feat: update with PR comments --- sequencesender/sequencesender.go | 12 ++++++------ sequencesender/txbuilder/banana_base.go | 2 +- sequencesender/txbuilder/banana_types.go | 21 ++++++++++++--------- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/sequencesender/sequencesender.go b/sequencesender/sequencesender.go index 0183f85c..1d76d3c0 100644 --- a/sequencesender/sequencesender.go +++ b/sequencesender/sequencesender.go @@ -214,6 +214,7 @@ func (s *SequenceSender) purgeSequences() { // Purge the information of batches that are already virtualized s.mutexSequence.Lock() + defer s.mutexSequence.Unlock() truncateUntil := 0 toPurge := make([]uint64, 0) for i := 0; i < len(s.sequenceList); i++ { @@ -240,7 +241,6 @@ func (s *SequenceSender) purgeSequences() { } s.logger.Infof("batches purged count: %d, fromBatch: %d, toBatch: %d", len(toPurge), firstPurged, lastPurged) } - s.mutexSequence.Unlock() } // purgeEthTx purges transactions from memory structures @@ -252,6 +252,7 @@ func (s *SequenceSender) purgeEthTx(ctx context.Context) { // Purge old transactions that are finalized s.mutexEthTx.Lock() + defer s.mutexEthTx.Unlock() timePurge := time.Now().Add(-s.cfg.WaitPeriodPurgeTxFile.Duration) toPurge := make([]common.Hash, 0) for hash, data := range s.ethTransactions { @@ -289,7 +290,6 @@ func (s *SequenceSender) purgeEthTx(ctx context.Context) { } s.logger.Infof("txs purged count: %d, fromNonce: %d, toNonce: %d", len(toPurge), firstPurged, lastPurged) } - s.mutexEthTx.Unlock() } // syncEthTxResults syncs results from L1 for transactions in the memory structure @@ -1168,6 +1168,7 @@ func (s *SequenceSender) addInfoSequenceBatchEnd(batch *datastream.BatchEnd) { // addNewBatchL2Block adds a new L2 block to the work in progress batch func (s *SequenceSender) addNewBatchL2Block(l2Block *datastream.L2Block) { s.mutexSequence.Lock() + defer s.mutexSequence.Unlock() s.logger.Infof(".....new L2 block, number %d (batch %d) l1infotree %d", l2Block.Number, l2Block.BatchNumber, l2Block.L1InfotreeIndex) @@ -1187,7 +1188,8 @@ func (s *SequenceSender) addNewBatchL2Block(l2Block *datastream.L2Block) { if l2Block.L1InfotreeIndex != 0 { data.batch.SetL1InfoTreeIndex(l2Block.L1InfotreeIndex) } else { - s.logger.Warnf("L1InfotreeIndex is 0, we don't change batch L1InfotreeIndex (%d)", data.batch.L1InfoTreeIndex()) + s.logger.Warnf("L2 Block L1InfotreeIndex is 0, we don't change batch L1InfotreeIndex (%d)", + data.batch.L1InfoTreeIndex()) } // New L2 block raw newBlockRaw := state.L2BlockRaw{} @@ -1205,13 +1207,12 @@ func (s *SequenceSender) addNewBatchL2Block(l2Block *datastream.L2Block) { blockRaw.DeltaTimestamp = l2Block.DeltaTimestamp blockRaw.IndexL1InfoTree = l2Block.L1InfotreeIndex } - - s.mutexSequence.Unlock() } // addNewBlockTx adds a new Tx to the current L2 block func (s *SequenceSender) addNewBlockTx(l2Tx *datastream.Transaction) { s.mutexSequence.Lock() + defer s.mutexSequence.Unlock() s.logger.Debugf("........new tx, length %d EGP %d SR %x..", len(l2Tx.Encoded), l2Tx.EffectiveGasPricePercentage, l2Tx.ImStateRoot[:8], ) @@ -1234,7 +1235,6 @@ func (s *SequenceSender) addNewBlockTx(l2Tx *datastream.Transaction) { // Add Tx blockRaw.Transactions = append(blockRaw.Transactions, l2TxRaw) - s.mutexSequence.Unlock() } // getWipL2Block returns index of the array and pointer to the current L2 block (helper func) diff --git a/sequencesender/txbuilder/banana_base.go b/sequencesender/txbuilder/banana_base.go index 91af8895..6d191c4a 100644 --- a/sequencesender/txbuilder/banana_base.go +++ b/sequencesender/txbuilder/banana_base.go @@ -144,7 +144,7 @@ func (t *TxBuilderBananaBase) NewSequence( } func SequenceSanityCheck(seq *etherman.SequenceBanana) error { - maxL1InfoIndex, err := CalculateMaxL1InfoTreeIndexInsideSequence(seq) + maxL1InfoIndex, err := calculateMaxL1InfoTreeIndexInsideSequence(seq) if err != nil { return err } diff --git a/sequencesender/txbuilder/banana_types.go b/sequencesender/txbuilder/banana_types.go index 4f810c36..c69d2876 100644 --- a/sequencesender/txbuilder/banana_types.go +++ b/sequencesender/txbuilder/banana_types.go @@ -149,29 +149,32 @@ func (b *BananaSequence) SetLastVirtualBatchNumber(batchNumber uint64) { b.SequenceBanana.LastVirtualBatchNumber = batchNumber } -func CalculateMaxL1InfoTreeIndexInsideL2Data(l2data []byte) (uint32, error) { +func calculateMaxL1InfoTreeIndexInsideL2Data(l2data []byte) (uint32, error) { batchRawV2, err := state.DecodeBatchV2(l2data) if err != nil { - return 0, fmt.Errorf("CalculateMaxL1InfoTreeIndexInsideL2Data: error decoding batchL2Data, err:%w", err) + return 0, fmt.Errorf("calculateMaxL1InfoTreeIndexInsideL2Data: error decoding batchL2Data, err:%w", err) } if batchRawV2 == nil { - return 0, fmt.Errorf("CalculateMaxL1InfoTreeIndexInsideL2Data: batchRawV2 is nil") + return 0, fmt.Errorf("calculateMaxL1InfoTreeIndexInsideL2Data: batchRawV2 is nil") } maxIndex := uint32(0) - for i := range batchRawV2.Blocks { - if batchRawV2.Blocks[i].IndexL1InfoTree > maxIndex { - maxIndex = batchRawV2.Blocks[i].IndexL1InfoTree + for _, block := range batchRawV2.Blocks { + if block.IndexL1InfoTree > maxIndex { + maxIndex = block.IndexL1InfoTree } } return maxIndex, nil } -func CalculateMaxL1InfoTreeIndexInsideSequence(seq *etherman.SequenceBanana) (uint32, error) { +func calculateMaxL1InfoTreeIndexInsideSequence(seq *etherman.SequenceBanana) (uint32, error) { + if seq == nil { + return 0, fmt.Errorf("calculateMaxL1InfoTreeIndexInsideSequence: seq is nil") + } maxIndex := uint32(0) for _, batch := range seq.Batches { - index, err := CalculateMaxL1InfoTreeIndexInsideL2Data(batch.L2Data) + index, err := calculateMaxL1InfoTreeIndexInsideL2Data(batch.L2Data) if err != nil { - return 0, fmt.Errorf("CalculateMaxL1InfoTreeIndexInsideBatches: error getting batch L1InfoTree , err:%w", err) + return 0, fmt.Errorf("calculateMaxL1InfoTreeIndexInsideBatches: error getting batch L1InfoTree , err:%w", err) } if index > maxIndex { maxIndex = index From 2330590ec63b22e6f3f62e4300a7ed06ea7d9fc7 Mon Sep 17 00:00:00 2001 From: joanestebanr <129153821+joanestebanr@users.noreply.github.com> Date: Fri, 20 Sep 2024 11:31:44 +0200 Subject: [PATCH 5/5] feat: increase coverage --- sequencesender/txbuilder/banana_base_test.go | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/sequencesender/txbuilder/banana_base_test.go b/sequencesender/txbuilder/banana_base_test.go index 29597e5b..3b449084 100644 --- a/sequencesender/txbuilder/banana_base_test.go +++ b/sequencesender/txbuilder/banana_base_test.go @@ -2,6 +2,7 @@ package txbuilder_test import ( "context" + "fmt" "math/big" "testing" @@ -33,8 +34,15 @@ func TestBananaBaseNewSequenceEmpty(t *testing.T) { seq, err := testData.sut.NewSequence(context.TODO(), nil, common.Address{}) require.NotNil(t, seq) require.NoError(t, err) - // TODO check values - // require.Equal(t, lastAcc, seq.LastAccInputHash()) +} + +func TestBananaBaseNewSequenceErrorHeaderByNumber(t *testing.T) { + testData := newBananaBaseTestData(t) + testData.l1Client.On("HeaderByNumber", mock.Anything, mock.Anything). + Return(nil, fmt.Errorf("error")) + seq, err := testData.sut.NewSequence(context.TODO(), nil, common.Address{}) + require.Nil(t, seq) + require.Error(t, err) } func TestBananaBaseNewBatchFromL2Block(t *testing.T) { @@ -111,6 +119,11 @@ func TestBananaSanityCheck(t *testing.T) { require.Error(t, err, "inside batchl2data max is 1 and counter is 1. The batchl2data is not included in counter") } +func TestBananaSanityCheckNilSeq(t *testing.T) { + err := txbuilder.SequenceSanityCheck(nil) + require.Error(t, err, "nil sequence") +} + type testDataBananaBase struct { rollupContract *mocks_txbuilder.RollupBananaBaseContractor getContract *mocks_txbuilder.GlobalExitRootBananaContractor