diff --git a/.github/workflows/test-e2e.yml b/.github/workflows/test-e2e.yml index 133d50da6..1b0d6c57b 100644 --- a/.github/workflows/test-e2e.yml +++ b/.github/workflows/test-e2e.yml @@ -51,7 +51,7 @@ jobs: with: repository: 0xPolygon/kurtosis-cdk path: kurtosis-cdk - ref: arpit/bridge-service + ref: v0.3.3 - name: Install Kurtosis CDK tools uses: ./kurtosis-cdk/.github/actions/setup-kurtosis-cdk diff --git a/.github/workflows/test-resequence.yml b/.github/workflows/test-resequence.yml index d6044dd40..b4813341e 100644 --- a/.github/workflows/test-resequence.yml +++ b/.github/workflows/test-resequence.yml @@ -34,7 +34,7 @@ jobs: with: repository: 0xPolygon/kurtosis-cdk path: kurtosis-cdk - ref: arpit/bridge-service + ref: v0.2.31 - name: Install Kurtosis CDK tools uses: ./kurtosis-cdk/.github/actions/setup-kurtosis-cdk diff --git a/aggregator/aggregator.go b/aggregator/aggregator.go index 832aa2487..93455c73e 100644 --- a/aggregator/aggregator.go +++ b/aggregator/aggregator.go @@ -1060,7 +1060,7 @@ func (a *Aggregator) getVerifiedBatchAccInputHash(ctx context.Context, batchNumb func (a *Aggregator) getAndLockBatchToProve( ctx context.Context, prover ProverInterface, -) (*state.Batch, []byte, *state.Proof, error) { +) (*state.Batch, *state.Proof, error) { proverID := prover.ID() proverName := prover.Name() @@ -1076,7 +1076,7 @@ func (a *Aggregator) getAndLockBatchToProve( // Get last virtual batch number from L1 lastVerifiedBatchNumber, err := a.etherman.GetLatestVerifiedBatchNum() if err != nil { - return nil, nil, nil, err + return nil, nil, err } proofExists := true @@ -1089,7 +1089,7 @@ func (a *Aggregator) getAndLockBatchToProve( if err != nil { tmpLogger.Infof("Error checking proof exists for batch %d", batchNumberToVerify) - return nil, nil, nil, err + return nil, nil, err } if proofExists { @@ -1101,7 +1101,7 @@ func (a *Aggregator) getAndLockBatchToProve( err := a.storage.CleanupGeneratedProofs(ctx, math.MaxInt, nil) if err != nil { tmpLogger.Infof("Error cleaning up generated proofs for batch %d", batchNumberToVerify) - return nil, nil, nil, err + return nil, nil, err } batchNumberToVerify-- break @@ -1112,7 +1112,7 @@ func (a *Aggregator) getAndLockBatchToProve( // Check if the batch has been sequenced sequence, err := a.l1Syncr.GetSequenceByBatchNumber(ctx, batchNumberToVerify) if err != nil && !errors.Is(err, entities.ErrNotFound) { - return nil, nil, nil, err + return nil, nil, err } // Not found, so it it not possible to verify the batch yet @@ -1120,7 +1120,7 @@ func (a *Aggregator) getAndLockBatchToProve( tmpLogger.Infof("Sequencing event for batch %d has not been synced yet, "+ "so it is not possible to verify it yet. Waiting ...", batchNumberToVerify) - return nil, nil, nil, state.ErrNotFound + return nil, nil, state.ErrNotFound } stateSequence := state.Sequence{ @@ -1128,22 +1128,29 @@ func (a *Aggregator) getAndLockBatchToProve( ToBatchNumber: sequence.ToBatchNumber, } + // Store the sequence in aggregator DB + err = a.storage.AddSequence(ctx, stateSequence, nil) + if err != nil { + tmpLogger.Infof("Error storing sequence for batch %d", batchNumberToVerify) + return nil, nil, err + } + // Get Batch from L1 Syncer virtualBatch, err := a.l1Syncr.GetVirtualBatchByBatchNumber(a.ctx, batchNumberToVerify) if err != nil && !errors.Is(err, entities.ErrNotFound) { a.logger.Errorf("Error getting virtual batch: %v", err) - return nil, nil, nil, err + return nil, nil, err } else if errors.Is(err, entities.ErrNotFound) { a.logger.Infof("Virtual batch %d has not been synced yet, "+ "so it is not possible to verify it yet. Waiting ...", batchNumberToVerify) - return nil, nil, nil, state.ErrNotFound + return nil, nil, state.ErrNotFound } // Get Batch from RPC rpcBatch, err := a.rpcClient.GetBatch(batchNumberToVerify) if err != nil { a.logger.Errorf("error getting batch %d from RPC: %v.", batchNumberToVerify, err) - return nil, nil, nil, err + return nil, nil, err } // Compare BatchL2Data from virtual batch and rpcBatch (skipping injected batch (1)) @@ -1164,7 +1171,7 @@ func (a *Aggregator) getAndLockBatchToProve( oldAccInputHash := a.getAccInputHash(batchNumberToVerify - 1) if oldAccInputHash == (common.Hash{}) && batchNumberToVerify > 1 { tmpLogger.Warnf("AccInputHash for previous batch (%d) is not in memory. Waiting ...", batchNumberToVerify-1) - return nil, nil, nil, state.ErrNotFound + return nil, nil, state.ErrNotFound } forcedBlockHashL1 := rpcBatch.ForcedBlockHashL1() @@ -1174,7 +1181,7 @@ func (a *Aggregator) getAndLockBatchToProve( l1Block, err := a.l1Syncr.GetL1BlockByNumber(ctx, virtualBatch.BlockNumber) if err != nil { a.logger.Errorf("Error getting l1 block: %v", err) - return nil, nil, nil, err + return nil, nil, err } forcedBlockHashL1 = l1Block.ParentHash @@ -1220,34 +1227,9 @@ func (a *Aggregator) getAndLockBatchToProve( ForkID: a.cfg.ForkId, } - // Request the witness from the server, if it is busy just keep looping until it is available - start := time.Now() - witness, err := a.rpcClient.GetWitness(batchNumberToVerify, a.cfg.UseFullWitness) - for err != nil { - if errors.Is(err, rpc.ErrBusy) { - a.logger.Debugf( - "Witness server is busy, retrying get witness for batch %d in %v", - batchNumberToVerify, a.cfg.RetryTime.Duration, - ) - } else { - a.logger.Errorf("Failed to get witness for batch %d, err: %v", batchNumberToVerify, err) - } - time.Sleep(a.cfg.RetryTime.Duration) - witness, err = a.rpcClient.GetWitness(batchNumberToVerify, a.cfg.UseFullWitness) - } - end := time.Now() - a.logger.Debugf("Time to get witness for batch %d: %v", batchNumberToVerify, end.Sub(start)) - - // Store the sequence in aggregator DB - err = a.storage.AddSequence(ctx, stateSequence, nil) - if err != nil { - tmpLogger.Infof("Error storing sequence for batch %d", batchNumberToVerify) - - return nil, nil, nil, err - } - // All the data required to generate a proof is ready - tmpLogger.Infof("All information to generate proof for batch %d is ready", virtualBatch.BatchNumber) + tmpLogger.Infof("All information to generate proof for batch %d is ready. "+ + "Witness will be requested.", virtualBatch.BatchNumber) tmpLogger = tmpLogger.WithFields("batch", virtualBatch.BatchNumber) now := time.Now().Round(time.Microsecond) @@ -1264,10 +1246,10 @@ func (a *Aggregator) getAndLockBatchToProve( if err != nil { tmpLogger.Errorf("Failed to add batch proof to DB for batch %d, err: %v", virtualBatch.BatchNumber, err) - return nil, nil, nil, err + return nil, nil, err } - return stateBatch, witness, proof, nil + return stateBatch, proof, nil } func (a *Aggregator) tryGenerateBatchProof(ctx context.Context, prover ProverInterface) (bool, error) { @@ -1278,7 +1260,7 @@ func (a *Aggregator) tryGenerateBatchProof(ctx context.Context, prover ProverInt ) tmpLogger.Debug("tryGenerateBatchProof start") - batchToProve, witness, proof, err0 := a.getAndLockBatchToProve(ctx, prover) + batchToProve, proof, err0 := a.getAndLockBatchToProve(ctx, prover) if errors.Is(err0, state.ErrNotFound) || errors.Is(err0, entities.ErrNotFound) { // nothing to proof, swallow the error tmpLogger.Debug("Nothing to generate proof") @@ -1288,6 +1270,11 @@ func (a *Aggregator) tryGenerateBatchProof(ctx context.Context, prover ProverInt return false, err0 } + // Request Witness + tmpLogger.Infof("Requesting witness for batch %d", batchToProve.BatchNumber) + witness := a.getWitness(batchToProve.BatchNumber) + tmpLogger.Infof("Witness received for batch %d", batchToProve.BatchNumber) + tmpLogger = tmpLogger.WithFields("batch", batchToProve.BatchNumber) var ( @@ -1369,6 +1356,28 @@ func (a *Aggregator) tryGenerateBatchProof(ctx context.Context, prover ProverInt return true, nil } +func (a *Aggregator) getWitness(batchNumber uint64) []byte { + // Request the witness from the server, if it is busy just keep looping until it is available + start := time.Now() + witness, err := a.rpcClient.GetWitness(batchNumber, a.cfg.UseFullWitness) + for err != nil { + if errors.Is(err, rpc.ErrBusy) { + a.logger.Debugf( + "Witness server is busy, retrying get witness for batch %d in %v", + batchNumber, a.cfg.RetryTime.Duration, + ) + } else { + a.logger.Errorf("Failed to get witness for batch %d, err: %v", batchNumber, err) + } + time.Sleep(a.cfg.RetryTime.Duration) + witness, err = a.rpcClient.GetWitness(batchNumber, a.cfg.UseFullWitness) + } + end := time.Now() + a.logger.Debugf("Time to get witness for batch %d: %v", batchNumber, end.Sub(start)) + + return witness +} + func (a *Aggregator) performSanityChecks(tmpLogger *log.Logger, stateRoot, accInputHash common.Hash, batchToProve *state.Batch) { // Sanity Check: state root from the proof must match the one from the batch diff --git a/aggregator/aggregator_test.go b/aggregator/aggregator_test.go index 6e012fb63..eb12ae81e 100644 --- a/aggregator/aggregator_test.go +++ b/aggregator/aggregator_test.go @@ -21,6 +21,7 @@ import ( mocks "github.com/0xPolygon/cdk/aggregator/mocks" "github.com/0xPolygon/cdk/aggregator/prover" "github.com/0xPolygon/cdk/config/types" + "github.com/0xPolygon/cdk/rpc" rpctypes "github.com/0xPolygon/cdk/rpc/types" "github.com/0xPolygon/cdk/state" "github.com/0xPolygonHermez/zkevm-synchronizer-l1/synchronizer" @@ -1551,6 +1552,51 @@ func Test_tryGenerateBatchProof(t *testing.T) { assert.ErrorIs(err, errTest) }, }, + { + name: "getAndLockBatchToProve CheckProofExistsForBatch fails", + setup: func(m mox, a *Aggregator) { + m.proverMock.On("Name").Return(proverName).Twice() + m.proverMock.On("ID").Return(proverID).Twice() + m.proverMock.On("Addr").Return("addr") + m.etherman.On("GetLatestVerifiedBatchNum").Return(lastVerifiedBatchNum, nil).Once() + m.storageMock.On("CheckProofExistsForBatch", mock.MatchedBy(matchProverCtxFn), mock.Anything, nil).Return(true, errTest) + }, + asserts: func(result bool, a *Aggregator, err error) { + assert.False(result) + assert.ErrorIs(err, errTest) + }, + }, + { + name: "getAndLockBatchToProve CleanupGeneratedProofs fails", + setup: func(m mox, a *Aggregator) { + m.proverMock.On("Name").Return(proverName).Twice() + m.proverMock.On("ID").Return(proverID).Twice() + m.proverMock.On("Addr").Return("addr") + m.etherman.On("GetLatestVerifiedBatchNum").Return(lastVerifiedBatchNum, nil).Once() + m.storageMock.On("CheckProofExistsForBatch", mock.MatchedBy(matchProverCtxFn), mock.Anything, nil).Return(true, nil) + m.storageMock.On("CleanupGeneratedProofs", mock.Anything, mock.Anything, mock.Anything).Return(errTest).Once() + }, + asserts: func(result bool, a *Aggregator, err error) { + assert.False(result) + assert.ErrorIs(err, errTest) + }, + }, + { + name: "getAndLockBatchToProve GetSequenceByBatchNumber fails", + setup: func(m mox, a *Aggregator) { + m.proverMock.On("Name").Return(proverName).Twice() + m.proverMock.On("ID").Return(proverID).Twice() + m.proverMock.On("Addr").Return("addr") + m.etherman.On("GetLatestVerifiedBatchNum").Return(lastVerifiedBatchNum, nil).Once() + m.storageMock.On("CheckProofExistsForBatch", mock.MatchedBy(matchProverCtxFn), mock.Anything, nil).Return(true, nil) + m.storageMock.On("CleanupGeneratedProofs", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() + m.synchronizerMock.On("GetSequenceByBatchNumber", mock.Anything, mock.Anything).Return(nil, errTest).Once() + }, + asserts: func(result bool, a *Aggregator, err error) { + assert.False(result) + assert.ErrorIs(err, errTest) + }, + }, { name: "getAndLockBatchToProve returns ErrNotFound", setup: func(m mox, a *Aggregator) { @@ -1919,3 +1965,19 @@ func Test_sanityChecks(t *testing.T) { return }() } + +func Test_getWitness(t *testing.T) { + mockRPC := mocks.NewRPCInterfaceMock(t) + sut := &Aggregator{ + rpcClient: mockRPC, + logger: log.WithFields("module", "unittest"), + cfg: Config{ + RetryTime: types.Duration{Duration: time.Microsecond * 1}, + }, + } + mockRPC.EXPECT().GetWitness(mock.Anything, mock.Anything).Return([]byte("witness"), errors.New("test error")).Once() + mockRPC.EXPECT().GetWitness(mock.Anything, mock.Anything).Return([]byte("witness"), rpc.ErrBusy).Once() + mockRPC.EXPECT().GetWitness(mock.Anything, mock.Anything).Return([]byte("witness"), nil).Once() + data := sut.getWitness(1234) + require.NotNil(t, data) +} diff --git a/go.mod b/go.mod index 7b9a15a07..3bba46806 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/0xPolygon/cdk-contracts-tooling v0.0.2-0.20241225094934-1d381f5703ef github.com/0xPolygon/cdk-data-availability v0.0.13 github.com/0xPolygon/cdk-rpc v0.0.0-20241004114257-6c3cb6eebfb6 - github.com/0xPolygon/zkevm-ethtx-manager v0.2.5 + github.com/0xPolygon/zkevm-ethtx-manager v0.2.7 github.com/0xPolygonHermez/zkevm-synchronizer-l1 v1.0.7 github.com/agglayer/aggkit v0.1.0-beta3 github.com/ethereum/go-ethereum v1.15.5 diff --git a/go.sum b/go.sum index 1829d7425..1dca2d376 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,8 @@ github.com/0xPolygon/cdk-data-availability v0.0.13 h1:CoZoSGOtg+wCF3s9XfLf+dc9H5 github.com/0xPolygon/cdk-data-availability v0.0.13/go.mod h1:u/vHga1Wdx4qeglcvh3VCGxeU7h/EouZnuYeFBibOZU= github.com/0xPolygon/cdk-rpc v0.0.0-20241004114257-6c3cb6eebfb6 h1:FXL/rcO7/GtZ3kRFw+C7J6vmGnl8gcazg+Gh/NVmnas= github.com/0xPolygon/cdk-rpc v0.0.0-20241004114257-6c3cb6eebfb6/go.mod h1:2scWqMMufrQXu7TikDgQ3BsyaKoX8qP26D6E262vSOg= -github.com/0xPolygon/zkevm-ethtx-manager v0.2.5 h1:t6vLS597OjPcoZzvpGXooIy+ANQEX6LoxYBenRmu15I= -github.com/0xPolygon/zkevm-ethtx-manager v0.2.5/go.mod h1:xuLx/9KDv5wO8mnkiiX5pZHyTWQZXyHjmBRBGEzNGXo= +github.com/0xPolygon/zkevm-ethtx-manager v0.2.7 h1:eS2ewz4z+S16ZWQRyci6Y3U9YSR+sx1opB0/NxhmKlQ= +github.com/0xPolygon/zkevm-ethtx-manager v0.2.7/go.mod h1:xuLx/9KDv5wO8mnkiiX5pZHyTWQZXyHjmBRBGEzNGXo= github.com/0xPolygonHermez/zkevm-synchronizer-l1 v1.0.7 h1:KJM1QlNZdZjNRS+ajPauD4uG+uaYgItaL+96Om3f8aI= github.com/0xPolygonHermez/zkevm-synchronizer-l1 v1.0.7/go.mod h1:exl+KHnTN6Y8HG4nSUXni4qKbAug0HjJqpebMSgl72k= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= diff --git a/sequencesender/ethtx.go b/sequencesender/ethtx.go index b71324fc0..72108e09c 100644 --- a/sequencesender/ethtx.go +++ b/sequencesender/ethtx.go @@ -216,6 +216,9 @@ func (s *SequenceSender) syncAllEthTxResults(ctx context.Context) (time.Time, er numResults := len(results) s.mutexEthTx.Lock() for _, result := range results { + for txHash := range result.Txs { + log.Debugf("syncAllEthTxResults: id: %s tx:%s", result.ID.String(), txHash.String()) + } txSequence, exists := s.ethTransactions[result.ID] if !exists { log.Debugf("transaction %v missing in memory structure. Adding it", result.ID) @@ -306,7 +309,7 @@ func (s *SequenceSender) getResultAndUpdateEthTx(ctx context.Context, txHash com txResult, err := s.ethTxManager.Result(ctx, txHash) switch { - case errors.Is(err, ethtxmanager.ErrNotFound): + case isEthTxManagerErrNotFound(err): s.logger.Infof("transaction %v does not exist in ethtxmanager. Marking it", txHash) txData.OnMonitor = false // Resend tx @@ -326,6 +329,25 @@ func (s *SequenceSender) getResultAndUpdateEthTx(ctx context.Context, txHash com return nil } +// this function is use instead of +// errors.Is(err, ethtxmanager.ErrNotFound) +func isEthTxManagerErrNotFound(err error) bool { + if err == nil { + return false + } + if errors.Is(err, ethtxmanager.ErrNotFound) { + return true + } + // Check all wrapped errors looking for the same message + for err != nil { + if err.Error() == ethtxmanager.ErrNotFound.Error() { + return true + } + err = errors.Unwrap(err) + } + return false +} + // loadSentSequencesTransactions loads the file into the memory structure func (s *SequenceSender) loadSentSequencesTransactions() error { // Check if file exists diff --git a/sequencesender/ethtx_test.go b/sequencesender/ethtx_test.go index 5cf915c64..cb338c978 100644 --- a/sequencesender/ethtx_test.go +++ b/sequencesender/ethtx_test.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "errors" + "fmt" "math/big" "os" "testing" @@ -18,6 +19,14 @@ import ( "github.com/stretchr/testify/require" ) +func TestIsEthTxManagerErrNotFound(t *testing.T) { + require.False(t, isEthTxManagerErrNotFound(nil)) + require.True(t, isEthTxManagerErrNotFound(ethtxmanager.ErrNotFound)) + require.True(t, isEthTxManagerErrNotFound(fmt.Errorf("not found"))) + require.True(t, isEthTxManagerErrNotFound(fmt.Errorf("wrapper: %w", ethtxmanager.ErrNotFound))) + require.False(t, isEthTxManagerErrNotFound(errors.New("another error"))) +} + func Test_sendTx(t *testing.T) { t.Parallel() diff --git a/sequencesender/sequencesender.go b/sequencesender/sequencesender.go index 41a56709b..e92311659 100644 --- a/sequencesender/sequencesender.go +++ b/sequencesender/sequencesender.go @@ -180,7 +180,7 @@ func (s *SequenceSender) batchRetrieval(ctx context.Context) error { // Try to retrieve batch from RPC rpcBatch, err := s.rpcClient.GetBatch(currentBatchNumber) if err != nil { - if errors.Is(err, ethtxmanager.ErrNotFound) { + if isEthTxManagerErrNotFound(err) { s.logger.Infof("batch %d not found in RPC", currentBatchNumber) } else { s.logger.Errorf("error getting batch %d from RPC: %v", currentBatchNumber, err) @@ -221,7 +221,13 @@ func (s *SequenceSender) populateSequenceData(rpcBatch *types.RPCBatch, batchNum } if len(batchRaw.Blocks) > 0 { - rpcBatch.SetL1InfoTreeIndex(batchRaw.Blocks[len(batchRaw.Blocks)-1].IndexL1InfoTree) + maxIndex := uint32(0) + for _, block := range batchRaw.Blocks { + if block.IndexL1InfoTree > maxIndex { + maxIndex = block.IndexL1InfoTree + } + } + rpcBatch.SetL1InfoTreeIndex(maxIndex) } s.sequenceData[batchNumber] = &sequenceData{ diff --git a/sequencesender/sequencesender_test.go b/sequencesender/sequencesender_test.go index 052719d34..36908b0f9 100644 --- a/sequencesender/sequencesender_test.go +++ b/sequencesender/sequencesender_test.go @@ -1,7 +1,9 @@ package sequencesender import ( + "encoding/hex" "errors" + "fmt" "math/big" "os" "testing" @@ -14,6 +16,7 @@ import ( "github.com/0xPolygon/cdk/sequencesender/seqsendertypes" "github.com/0xPolygon/cdk/sequencesender/txbuilder" "github.com/0xPolygon/cdk/state" + "github.com/0xPolygon/zkevm-ethtx-manager/ethtxmanager" ethtxtypes "github.com/0xPolygon/zkevm-ethtx-manager/types" "github.com/agglayer/aggkit/log" "github.com/ethereum/go-ethereum/common" @@ -24,9 +27,10 @@ import ( ) const ( - txStreamEncoded1 = "f86508843b9aca0082520894617b3a3528f9cdd6630fd3301b9c8911f7bf063d0a808207f5a0579b72a1c1ffdd845fba45317540982109298e2ec8d67ddf2cdaf22e80903677a01831e9a01291c7ea246742a5b5a543ca6938bfc3f6958c22be06fad99274e4ac" - txStreamEncoded2 = "f86509843b9aca0082520894617b3a3528f9cdd6630fd3301b9c8911f7bf063d0a808207f5a0908a522075e09485166ffa7630cd2b7013897fa1f1238013677d6f0a86efb3d2a0068b12435fcdc8ee254f3b1df8c5b29ed691eeee6065704f061130935976ca99" - txStreamEncoded3 = "b8b402f8b101268505d21dba0085076c363d8982dc60941929761e87667283f087ea9ab8370c174681b4e980b844095ea7b300000000000000000000000080a64c6d7f12c47b7c66c5b4e20e72bc1fcd5d9effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc001a0dd4db494969139a120e8721842455ec13f82757a4fc49b66d447c7d32d095a1da06ef54068a9aa67ecc4f52d885299a04feb6f3531cdfc771f1412cd3331d1ba4c" + txStreamEncoded1 = "f86508843b9aca0082520894617b3a3528f9cdd6630fd3301b9c8911f7bf063d0a808207f5a0579b72a1c1ffdd845fba45317540982109298e2ec8d67ddf2cdaf22e80903677a01831e9a01291c7ea246742a5b5a543ca6938bfc3f6958c22be06fad99274e4ac" + txStreamEncoded2 = "f86509843b9aca0082520894617b3a3528f9cdd6630fd3301b9c8911f7bf063d0a808207f5a0908a522075e09485166ffa7630cd2b7013897fa1f1238013677d6f0a86efb3d2a0068b12435fcdc8ee254f3b1df8c5b29ed691eeee6065704f061130935976ca99" + txStreamEncoded3 = "b8b402f8b101268505d21dba0085076c363d8982dc60941929761e87667283f087ea9ab8370c174681b4e980b844095ea7b300000000000000000000000080a64c6d7f12c47b7c66c5b4e20e72bc1fcd5d9effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc001a0dd4db494969139a120e8721842455ec13f82757a4fc49b66d447c7d32d095a1da06ef54068a9aa67ecc4f52d885299a04feb6f3531cdfc771f1412cd3331d1ba4c" + batchCodedRLP2Txs1 = "0b73e6af6f00000000ee02843b9aca00830186a0944d5cf5032b2a844602278b01199ed191a86c93ff88016345785d8a0000808203e88080bff0e780ba7db409339fd3f71969fa2cbf1b8535f6c725a1499d3318d3ef9c2b6340ddfab84add2c188f9efddb99771db1fe621c981846394ea4f035c85bcdd51bffee03843b9aca00830186a0944d5cf5032b2a844602278b01199ed191a86c93ff88016345785d8a0000808203e880805b346aa02230b22e62f73608de9ff39a162a6c24be9822209c770e3685b92d0756d5316ef954eefc58b068231ccea001fb7ac763ebe03afd009ad71cab36861e1bff" ) var ( @@ -617,3 +621,99 @@ func Test_marginTimeElapsed(t *testing.T) { }) } } + +func Test_isEthTxManagerErrNotFound(t *testing.T) { + require.False(t, isEthTxManagerErrNotFound(nil)) + require.True(t, isEthTxManagerErrNotFound(ethtxmanager.ErrNotFound)) + require.True(t, isEthTxManagerErrNotFound(fmt.Errorf("is wrapped %w", ethtxmanager.ErrNotFound))) + require.False(t, isEthTxManagerErrNotFound(fmt.Errorf("another error"))) +} + +func Test_batchRetrieval(t *testing.T) { + t.Parallel() + + errTest := errors.New("example error for test") + tests := []struct { + name string + getRPC func(t *testing.T) *mocks.RPCInterfaceMock + batchNumber uint64 + expectedBatch *rpctypes.RPCBatch + expectedErr string + }{ + { + name: "successfully get batch", + getRPC: func(t *testing.T) *mocks.RPCInterfaceMock { + t.Helper() + + mngr := mocks.NewRPCInterfaceMock(t) + mngr.On("GetBatch", mock.Anything).Return( + rpctypes.NewRPCBatch(1, common.Hash{}, nil, nil, + common.Hash{}, common.Hash{}, common.Hash{}, common.Address{}, true), nil) + return mngr + }, + batchNumber: 1, + expectedBatch: &rpctypes.RPCBatch{}, + expectedErr: "context deadline exceeded", + }, + { + name: "fails get batch", + getRPC: func(t *testing.T) *mocks.RPCInterfaceMock { + t.Helper() + + mngr := mocks.NewRPCInterfaceMock(t) + mngr.On("GetBatch", mock.Anything).Return( + nil, errTest).Once() + mngr.On("GetBatch", mock.Anything).Return( + rpctypes.NewRPCBatch(1, common.Hash{}, nil, nil, + common.Hash{}, common.Hash{}, common.Hash{}, common.Address{}, true), nil) + + return mngr + }, + batchNumber: 1, + expectedBatch: &rpctypes.RPCBatch{}, + expectedErr: "context deadline exceeded", + }, + } + + for _, tt := range tests { + tt := tt + + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + s := SequenceSender{ + cfg: Config{ + GetBatchWaitInterval: types2.NewDuration(time.Millisecond), + }, + rpcClient: tt.getRPC(t), + logger: log.GetDefaultLogger(), + sequenceData: make(map[uint64]*sequenceData), + } + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + err := s.batchRetrieval(ctx) + if tt.expectedErr != "" { + require.Contains(t, err.Error(), tt.expectedErr) + } else { + require.NoError(t, err) + } + }) + } +} + +func Test_populateSequenceData(t *testing.T) { + sut := SequenceSender{ + cfg: Config{ + GetBatchWaitInterval: types2.NewDuration(time.Millisecond), + }, + logger: log.GetDefaultLogger(), + sequenceData: make(map[uint64]*sequenceData), + } + batchL2Data, err := hex.DecodeString(batchCodedRLP2Txs1) + require.NoError(t, err) + batch := rpctypes.NewRPCBatch(1, common.Hash{}, nil, batchL2Data, + common.Hash{}, common.Hash{}, common.Hash{}, common.Address{}, true) + + err = sut.populateSequenceData(batch, 1234) + require.NoError(t, err) +} diff --git a/test/combinations/fork11-rollup.yml b/test/combinations/fork11-rollup.yml index cef4276ce..a67edce8a 100644 --- a/test/combinations/fork11-rollup.yml +++ b/test/combinations/fork11-rollup.yml @@ -1,11 +1,10 @@ args: zkevm_contracts_image: leovct/zkevm-contracts:v7.0.0-rc.2-fork.11-patch.1 - zkevm_prover_image: hermeznetwork/zkevm-prover:v7.0.2-fork.11 - cdk_erigon_node_image: hermeznetwork/cdk-erigon:v2.1.2 - zkevm_node_image: hermeznetwork/zkevm-node:v0.7.0-fork11-RC1 - cdk_node_image: cdk + agglayer_image: ghcr.io/agglayer/agglayer:0.2.0-rc.19 + zkevm_prover_image: hermeznetwork/zkevm-prover:v7.0.4-hotfix.2-fork.11 + zkevm_node_image: hermeznetwork/zkevm-node:v0.7.0-fork11 + cdk_node_image: cdk:latest gas_token_enabled: true gas_token_address: '' data_availability_mode: rollup sequencer_type: erigon - agglayer_image: ghcr.io/agglayer/agglayer:0.2.0-rc.19 diff --git a/test/combinations/fork12-cdk-validium.yml b/test/combinations/fork12-cdk-validium.yml index 7416a27b1..be21a579e 100644 --- a/test/combinations/fork12-cdk-validium.yml +++ b/test/combinations/fork12-cdk-validium.yml @@ -1,10 +1,8 @@ args: - zkevm_contracts_image: leovct/zkevm-contracts:v8.0.0-rc.4-fork.12-patch.1 - zkevm_prover_image: hermeznetwork/zkevm-prover:v8.0.0-RC12-fork.12 - cdk_erigon_node_image: hermeznetwork/cdk-erigon:v2.1.2 - cdk_node_image: cdk + zkevm_contracts_image: leovct/zkevm-contracts:v9.0.0-rc.6-pp-fork.12 + zkevm_prover_image: hermeznetwork/zkevm-prover:v8.0.0-RC16-fork.12 + cdk_node_image: cdk:latest gas_token_enabled: true gas_token_address: '' data_availability_mode: cdk-validium sequencer_type: erigon - agglayer_image: ghcr.io/agglayer/agglayer@sha256:5715855f2cc6834bd84a99a33937915164648547d21bfb55198948b0ae4e0fad diff --git a/test/combinations/fork12-rollup.yml b/test/combinations/fork12-rollup.yml index 3bea9afbc..5469d2984 100644 --- a/test/combinations/fork12-rollup.yml +++ b/test/combinations/fork12-rollup.yml @@ -1,10 +1,8 @@ args: - zkevm_contracts_image: leovct/zkevm-contracts:v8.0.0-rc.4-fork.12-patch.1 - zkevm_prover_image: hermeznetwork/zkevm-prover:v8.0.0-RC12-fork.12 - cdk_erigon_node_image: hermeznetwork/cdk-erigon:v2.1.2 - cdk_node_image: cdk + zkevm_contracts_image: leovct/zkevm-contracts:v9.0.0-rc.6-pp-fork.12 + zkevm_prover_image: hermeznetwork/zkevm-prover:v8.0.0-RC16-fork.12 + cdk_node_image: cdk:latest gas_token_enabled: true gas_token_address: '' data_availability_mode: rollup sequencer_type: erigon - agglayer_image: ghcr.io/agglayer/agglayer@sha256:5715855f2cc6834bd84a99a33937915164648547d21bfb55198948b0ae4e0fad diff --git a/test/combinations/fork9-cdk-validium.yml b/test/combinations/fork9-cdk-validium.yml index 30795613c..51d4ea2f3 100644 --- a/test/combinations/fork9-cdk-validium.yml +++ b/test/combinations/fork9-cdk-validium.yml @@ -1,14 +1,11 @@ args: zkevm_contracts_image: leovct/zkevm-contracts:v6.0.0-rc.1-fork.9-patch.1 - zkevm_prover_image: hermeznetwork/zkevm-prover:v6.0.6 - cdk_erigon_node_image: hermeznetwork/cdk-erigon:v2.1.2 - zkevm_node_image: hermeznetwork/zkevm-node:v0.7.3-RC1 + agglayer_image: ghcr.io/agglayer/agglayer:0.2.0-rc.19 + zkevm_prover_image: hermeznetwork/zkevm-prover:v6.0.8 + zkevm_node_image: hermeznetwork/zkevm-node:v0.7.3 cdk_validium_node_image: 0xpolygon/cdk-validium-node:0.7.0-cdk cdk_node_image: cdk gas_token_enabled: true gas_token_address: '' additional_services: - pless_zkevm_node - data_availability_mode: cdk-validium - sequencer_type: erigon - agglayer_image: ghcr.io/agglayer/agglayer:0.2.0-rc.19 diff --git a/test/config/kurtosis-cdk-node-config.toml.template b/test/config/kurtosis-cdk-node-config.toml.template index 6729f7b71..6101d0bd5 100644 --- a/test/config/kurtosis-cdk-node-config.toml.template +++ b/test/config/kurtosis-cdk-node-config.toml.template @@ -1,7 +1,7 @@ PathRWData = "{{.zkevm_path_rw_data}}/" L1URL="{{.l1_rpc_url}}" L2URL="http://{{.l2_rpc_name}}{{.deployment_suffix}}:{{.zkevm_rpc_http_port}}" -AggLayerURL="{{.agglayer_url}}" +AggLayerURL="{{.agglayer_readrpc_url}}" ForkId = {{.zkevm_rollup_fork_id}} IsValidiumMode = {{.is_cdk_validium}} diff --git a/test/config/kurtosis-cdk-node-config.toml.template.pessimistic b/test/config/kurtosis-cdk-node-config.toml.template.pessimistic new file mode 100644 index 000000000..a0c8e6db3 --- /dev/null +++ b/test/config/kurtosis-cdk-node-config.toml.template.pessimistic @@ -0,0 +1,62 @@ +PathRWData = "{{.zkevm_path_rw_data}}/" +L1URL="{{.l1_rpc_url}}" +L2URL="http://{{.l2_rpc_name}}{{.deployment_suffix}}:{{.zkevm_rpc_http_port}}" +AggLayerURL="{{.agglayer_url}}" + +ForkId = {{.zkevm_rollup_fork_id}} +IsValidiumMode = {{.is_cdk_validium}} + +{{if eq .zkevm_rollup_fork_id "12"}} +ContractVersions = "banana" +{{else if eq .zkevm_rollup_fork_id "13"}} +# Doesn't look like this is needed at the moment, but soon perhaps? +# ContractVersions = "durian" +ContractVersions = "banana" +{{else}} +ContractVersions = "elderberry" +{{end}} + +L2Coinbase = "{{.zkevm_l2_sequencer_address}}" +SequencerPrivateKeyPath = "{{or .zkevm_l2_sequencer_keystore_file "/etc/cdk/sequencer.keystore"}}" +SequencerPrivateKeyPassword = "{{.zkevm_l2_keystore_password}}" + +AggregatorPrivateKeyPath = "{{or .zkevm_l2_aggregator_keystore_file "/etc/cdk/aggregator.keystore"}}" +AggregatorPrivateKeyPassword = "{{.zkevm_l2_keystore_password}}" +SenderProofToL1Addr = "{{.zkevm_l2_agglayer_address}}" +polygonBridgeAddr = "{{.zkevm_bridge_address}}" + + +RPCURL = "http://{{.l2_rpc_name}}{{.deployment_suffix}}:{{.zkevm_rpc_http_port}}" +WitnessURL = "http://{{.l2_rpc_name}}{{.deployment_suffix}}:{{.zkevm_rpc_http_port}}" + + +# This values can be override directly from genesis.json +rollupCreationBlockNumber = "{{.zkevm_rollup_manager_block_number}}" +rollupManagerCreationBlockNumber = "{{.zkevm_rollup_manager_block_number}}" +genesisBlockNumber = "{{.zkevm_rollup_manager_block_number}}" +[L1Config] + chainId = "{{.l1_chain_id}}" + polygonZkEVMGlobalExitRootAddress = "{{.zkevm_global_exit_root_address}}" + polygonRollupManagerAddress = "{{.zkevm_rollup_manager_address}}" + polTokenAddress = "{{.pol_token_address}}" + polygonZkEVMAddress = "{{.zkevm_rollup_address}}" + +[L2Config] + GlobalExitRootAddr = "{{.zkevm_global_exit_root_address}}" + +[Log] +Environment = "development" # "production" or "development" +Level = "{{.global_log_level}}" +Outputs = ["stderr"] + +[Aggregator] + Port = "{{.zkevm_aggregator_port}}" + RetryTime = "30s" + VerifyProofInterval = "10s" + GasOffset = 150000 + SettlementBackend = "agglayer" + +[AggSender] +SaveCertificatesToFilesPath = "{{.zkevm_path_rw_data}}/" + + diff --git a/test/run-e2e.sh b/test/run-e2e.sh index d0e3f12eb..6f67301af 100755 --- a/test/run-e2e.sh +++ b/test/run-e2e.sh @@ -1,5 +1,6 @@ #!/bin/bash source $(dirname $0)/scripts/env.sh +source $(dirname $0)/scripts/shared.sh FORK=$1 if [ -z $FORK ]; then @@ -25,8 +26,8 @@ else fi kurtosis clean --all -echo "Override cdk config file" -cp $BASE_FOLDER/config/kurtosis-cdk-node-config.toml.template $KURTOSIS_FOLDER/templates/trusted-node/cdk-node-config.toml +override_cdk_node_config_file $DATA_AVAILABILITY_MODE + KURTOSIS_CONFIG_FILE="combinations/$FORK-$DATA_AVAILABILITY_MODE.yml" TEMP_CONFIG_FILE=$(mktemp --suffix ".yml") echo "rendering $KURTOSIS_CONFIG_FILE to temp file $TEMP_CONFIG_FILE" diff --git a/test/scripts/shared.sh b/test/scripts/shared.sh new file mode 100644 index 000000000..778364f80 --- /dev/null +++ b/test/scripts/shared.sh @@ -0,0 +1,17 @@ + +function override_cdk_node_config_file(){ + local __DATA_AVAILABILITY_MODE=$1 + if [ -z $__DATA_AVAILABILITY_MODE ]; then + echo "Missing DATA_AVAILABILITY_MODE:override_cdk_node_config_file ['rollup', 'cdk-validium', 'pessimistic']" + return 1 + fi + echo "Override cdk config file" + local _FILENAME=$BASE_FOLDER/config/kurtosis-cdk-node-config.toml.template.$__DATA_AVAILABILITY_MODE + cp $_FILENAME $KURTOSIS_FOLDER/templates/trusted-node/cdk-node-config.toml + if [ $? -ne 0 ]; then + echo "... copying generic config file" + _FILENAME=$BASE_FOLDER/config/kurtosis-cdk-node-config.toml.template + cp $_FILENAME $KURTOSIS_FOLDER/templates/trusted-node/cdk-node-config.toml + fi + echo "Override cdk config using: " $_FILENAME +}