Skip to content

Commit

Permalink
feat: seq sender sanity check l1infotree (#86)
Browse files Browse the repository at this point in the history
  • Loading branch information
joanestebanr authored Sep 20, 2024
1 parent db81a26 commit 681c987
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 9 deletions.
19 changes: 12 additions & 7 deletions sequencesender/sequencesender.go
Original file line number Diff line number Diff line change
Expand Up @@ -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++ {
Expand All @@ -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
Expand All @@ -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 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -1168,7 +1168,9 @@ 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)
defer s.mutexSequence.Unlock()
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]
Expand All @@ -1183,7 +1185,12 @@ 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("L2 Block L1InfotreeIndex is 0, we don't change batch L1InfotreeIndex (%d)",
data.batch.L1InfoTreeIndex())
}
// New L2 block raw
newBlockRaw := state.L2BlockRaw{}

Expand All @@ -1200,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],
)
Expand All @@ -1229,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)
Expand Down
44 changes: 44 additions & 0 deletions sequencesender/sequencesender_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand Down Expand Up @@ -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")
}
16 changes: 16 additions & 0 deletions sequencesender/txbuilder/banana_base.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
49 changes: 47 additions & 2 deletions sequencesender/txbuilder/banana_base_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ package txbuilder_test

import (
"context"
"fmt"
"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"
Expand All @@ -31,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) {
Expand Down Expand Up @@ -79,6 +89,41 @@ 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")
}

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
Expand Down
35 changes: 35 additions & 0 deletions sequencesender/txbuilder/banana_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand Down Expand Up @@ -147,3 +148,37 @@ 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 _, block := range batchRawV2.Blocks {
if block.IndexL1InfoTree > maxIndex {
maxIndex = block.IndexL1InfoTree
}
}
return maxIndex, nil
}

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)
if err != nil {
return 0, fmt.Errorf("calculateMaxL1InfoTreeIndexInsideBatches: error getting batch L1InfoTree , err:%w", err)
}
if index > maxIndex {
maxIndex = index
}
}
return maxIndex, nil
}

0 comments on commit 681c987

Please sign in to comment.