arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/coordinator/coordinator_test.go
coordinator/coordinator_test.goRaw
  1package coordinator
  2
  3import (
  4	"context"
  5	"fmt"
  6	"io/ioutil"
  7	"math/big"
  8	"os"
  9	"testing"
 10	"time"
 11
 12	ethCommon "github.com/ethereum/go-ethereum/common"
 13	"github.com/hermeznetwork/hermez-node/batchbuilder"
 14	"github.com/hermeznetwork/hermez-node/common"
 15	dbUtils "github.com/hermeznetwork/hermez-node/db"
 16	"github.com/hermeznetwork/hermez-node/db/historydb"
 17	"github.com/hermeznetwork/hermez-node/db/l2db"
 18	"github.com/hermeznetwork/hermez-node/db/statedb"
 19	"github.com/hermeznetwork/hermez-node/eth"
 20	"github.com/hermeznetwork/hermez-node/log"
 21	"github.com/hermeznetwork/hermez-node/prover"
 22	"github.com/hermeznetwork/hermez-node/synchronizer"
 23	"github.com/hermeznetwork/hermez-node/test"
 24	"github.com/hermeznetwork/hermez-node/test/til"
 25	"github.com/hermeznetwork/hermez-node/txselector"
 26	"github.com/hermeznetwork/tracerr"
 27	"github.com/iden3/go-merkletree/db/pebble"
 28	"github.com/stretchr/testify/assert"
 29	"github.com/stretchr/testify/require"
 30)
 31
 32var deleteme = []string{}
 33
 34func pebbleMakeCheckpoint(source, dest string) error {
 35	// Remove dest folder (if it exists) before doing the checkpoint
 36	if _, err := os.Stat(dest); !os.IsNotExist(err) {
 37		err := os.RemoveAll(dest)
 38		if err != nil {
 39			return tracerr.Wrap(err)
 40		}
 41	} else if err != nil && !os.IsNotExist(err) {
 42		return tracerr.Wrap(err)
 43	}
 44
 45	sto, err := pebble.NewPebbleStorage(source, false)
 46	if err != nil {
 47		return tracerr.Wrap(err)
 48	}
 49	defer func() {
 50		errClose := sto.Pebble().Close()
 51		if errClose != nil {
 52			log.Errorw("Pebble.Close", "err", errClose)
 53		}
 54	}()
 55
 56	// execute Checkpoint
 57	err = sto.Pebble().Checkpoint(dest)
 58	if err != nil {
 59		return tracerr.Wrap(err)
 60	}
 61
 62	return nil
 63}
 64
 65func TestMain(m *testing.M) {
 66	exitVal := m.Run()
 67	for _, dir := range deleteme {
 68		if err := os.RemoveAll(dir); err != nil {
 69			panic(err)
 70		}
 71	}
 72	os.Exit(exitVal)
 73}
 74
 75var syncDBPath string
 76var txSelDBPath string
 77var batchBuilderDBPath string
 78
 79type modules struct {
 80	historyDB    *historydb.HistoryDB
 81	l2DB         *l2db.L2DB
 82	txSelector   *txselector.TxSelector
 83	batchBuilder *batchbuilder.BatchBuilder
 84	stateDB      *statedb.StateDB
 85}
 86
 87var maxL1UserTxs uint64 = 128
 88var maxL1Txs uint64 = 256
 89var maxL1CoordinatorTxs uint64 = maxL1Txs - maxL1UserTxs
 90var maxTxs uint64 = 376
 91var nLevels uint32 = 32   //nolint:deadcode,unused
 92var maxFeeTxs uint32 = 64 //nolint:deadcode,varcheck
 93
 94func newTestModules(t *testing.T) modules {
 95	nLevels := 32
 96
 97	var err error
 98	syncDBPath, err = ioutil.TempDir("", "tmpSyncDB")
 99	require.NoError(t, err)
100	deleteme = append(deleteme, syncDBPath)
101	syncStateDB, err := statedb.NewStateDB(syncDBPath, statedb.TypeSynchronizer, nLevels)
102	assert.NoError(t, err)
103
104	pass := os.Getenv("POSTGRES_PASS")
105	db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
106	require.NoError(t, err)
107	test.WipeDB(db)
108	l2DB := l2db.NewL2DB(db, 10, 100, 24*time.Hour)
109	historyDB := historydb.NewHistoryDB(db)
110
111	txSelDBPath, err = ioutil.TempDir("", "tmpTxSelDB")
112	require.NoError(t, err)
113	deleteme = append(deleteme, txSelDBPath)
114
115	coordAccount := &txselector.CoordAccount{ // TODO TMP
116		Addr:                ethCommon.HexToAddress("0xc58d29fA6e86E4FAe04DDcEd660d45BCf3Cb2370"),
117		BJJ:                 nil,
118		AccountCreationAuth: nil,
119	}
120	txSelector, err := txselector.NewTxSelector(coordAccount, txSelDBPath, syncStateDB, l2DB)
121	assert.NoError(t, err)
122
123	batchBuilderDBPath, err = ioutil.TempDir("", "tmpBatchBuilderDB")
124	require.NoError(t, err)
125	deleteme = append(deleteme, batchBuilderDBPath)
126	batchBuilder, err := batchbuilder.NewBatchBuilder(batchBuilderDBPath, syncStateDB, nil, 0, uint64(nLevels))
127	assert.NoError(t, err)
128
129	return modules{
130		historyDB:    historyDB,
131		l2DB:         l2DB,
132		txSelector:   txSelector,
133		batchBuilder: batchBuilder,
134		stateDB:      syncStateDB,
135	}
136}
137
138type timer struct {
139	time int64
140}
141
142func (t *timer) Time() int64 {
143	currentTime := t.time
144	t.time++
145	return currentTime
146}
147
148var bidder = ethCommon.HexToAddress("0x6b175474e89094c44da98b954eedeac495271d0f")
149var forger = ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
150
151func newTestCoordinator(t *testing.T, forgerAddr ethCommon.Address, ethClient *test.Client,
152	ethClientSetup *test.ClientSetup, modules modules) *Coordinator {
153	debugBatchPath, err := ioutil.TempDir("", "tmpDebugBatch")
154	require.NoError(t, err)
155	deleteme = append(deleteme, debugBatchPath)
156
157	conf := Config{
158		ForgerAddress:          forgerAddr,
159		ConfirmBlocks:          5,
160		L1BatchTimeoutPerc:     0.5,
161		EthClientAttempts:      5,
162		EthClientAttemptsDelay: 100 * time.Millisecond,
163		TxManagerCheckInterval: 300 * time.Millisecond,
164		DebugBatchPath:         debugBatchPath,
165	}
166	serverProofs := []prover.Client{&prover.MockClient{}, &prover.MockClient{}}
167
168	scConsts := &synchronizer.SCConsts{
169		Rollup:   *ethClientSetup.RollupConstants,
170		Auction:  *ethClientSetup.AuctionConstants,
171		WDelayer: *ethClientSetup.WDelayerConstants,
172	}
173	initSCVars := &synchronizer.SCVariables{
174		Rollup:   *ethClientSetup.RollupVariables,
175		Auction:  *ethClientSetup.AuctionVariables,
176		WDelayer: *ethClientSetup.WDelayerVariables,
177	}
178	coord, err := NewCoordinator(conf, modules.historyDB, modules.l2DB, modules.txSelector,
179		modules.batchBuilder, serverProofs, ethClient, scConsts, initSCVars)
180	require.NoError(t, err)
181	return coord
182}
183
184func newTestSynchronizer(t *testing.T, ethClient *test.Client, ethClientSetup *test.ClientSetup,
185	modules modules) *synchronizer.Synchronizer {
186	sync, err := synchronizer.NewSynchronizer(ethClient, modules.historyDB, modules.stateDB,
187		synchronizer.Config{
188			StartBlockNum: synchronizer.ConfigStartBlockNum{
189				Rollup:   1,
190				Auction:  1,
191				WDelayer: 1,
192			},
193			InitialVariables: synchronizer.SCVariables{
194				Rollup:   *ethClientSetup.RollupVariables,
195				Auction:  *ethClientSetup.AuctionVariables,
196				WDelayer: *ethClientSetup.WDelayerVariables,
197			},
198		})
199	require.NoError(t, err)
200	return sync
201}
202
203// TestCoordinatorFlow is a test where the coordinator is stared (which means
204// that goroutines are spawned), and ethereum blocks are mined via the
205// test.Client to simulate starting and stopping forging times.  This test
206// works without a synchronizer, and no l2txs are inserted in the pool, so all
207// the batches are forged empty.  The purpose of this test is to manually
208// observe via the logs that nothing crashes and that the coordinator starts
209// and stops forging at the right blocks.
210func TestCoordinatorFlow(t *testing.T) {
211	if os.Getenv("TEST_COORD_FLOW") == "" {
212		return
213	}
214	ethClientSetup := test.NewClientSetupExample()
215	var timer timer
216	ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
217	modules := newTestModules(t)
218	coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
219
220	// Bid for slot 2 and 4
221	_, err := ethClient.AuctionSetCoordinator(forger, "https://foo.bar")
222	require.NoError(t, err)
223	_, err = ethClient.AuctionBidSimple(2, big.NewInt(9999))
224	require.NoError(t, err)
225	_, err = ethClient.AuctionBidSimple(4, big.NewInt(9999))
226	require.NoError(t, err)
227
228	coord.Start()
229	time.Sleep(1 * time.Second)
230
231	waitForSlot := func(slot int64) {
232		for {
233			blockNum, err := ethClient.EthLastBlock()
234			require.NoError(t, err)
235			nextBlockSlot, err := ethClient.AuctionGetSlotNumber(blockNum + 1)
236			require.NoError(t, err)
237			if nextBlockSlot == slot {
238				break
239			}
240			ethClient.CtlMineBlock()
241			time.Sleep(100 * time.Millisecond)
242			var stats synchronizer.Stats
243			stats.Eth.LastBlock = *ethClient.CtlLastBlock()
244			stats.Sync.LastBlock = stats.Eth.LastBlock
245			stats.Eth.LastBatch = ethClient.CtlLastForgedBatch()
246			stats.Sync.LastBatch = stats.Eth.LastBatch
247			canForge, err := ethClient.AuctionCanForge(forger, blockNum+1)
248			require.NoError(t, err)
249			if canForge {
250				// fmt.Println("DBG canForge")
251				stats.Sync.Auction.CurrentSlot.Forger = forger
252			}
253			// Copy stateDB to synchronizer if there was a new batch
254			source := fmt.Sprintf("%v/BatchNum%v", batchBuilderDBPath, stats.Sync.LastBatch)
255			dest := fmt.Sprintf("%v/BatchNum%v", syncDBPath, stats.Sync.LastBatch)
256			if stats.Sync.LastBatch != 0 {
257				if _, err := os.Stat(dest); os.IsNotExist(err) {
258					log.Infow("Making pebble checkpoint for sync",
259						"source", source, "dest", dest)
260					err = pebbleMakeCheckpoint(source, dest)
261					require.NoError(t, err)
262				}
263			}
264			coord.SendMsg(MsgSyncBlock{
265				Stats: stats,
266			})
267		}
268	}
269
270	// NOTE: With the current test, the coordinator will enter in forge
271	// time before the bidded slot because no one else is forging in the
272	// other slots before the slot deadline.
273	// simulate forgeSequence time
274	waitForSlot(2)
275	log.Info("~~~ simulate entering in forge time")
276	time.Sleep(1 * time.Second)
277
278	// simulate going out from forgeSequence
279	waitForSlot(3)
280	log.Info("~~~ simulate going out from forge time")
281	time.Sleep(1 * time.Second)
282
283	// simulate entering forgeSequence time again
284	waitForSlot(4)
285	log.Info("~~~ simulate entering in forge time again")
286	time.Sleep(2 * time.Second)
287
288	// simulate stopping forgerLoop by channel
289	log.Info("~~~ simulate stopping forgerLoop by closing coordinator stopch")
290	coord.Stop()
291	time.Sleep(1 * time.Second)
292}
293
294func TestCoordinatorStartStop(t *testing.T) {
295	ethClientSetup := test.NewClientSetupExample()
296	var timer timer
297	ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
298	modules := newTestModules(t)
299	coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
300	coord.Start()
301	coord.Stop()
302}
303
304func TestCoordCanForge(t *testing.T) {
305	ethClientSetup := test.NewClientSetupExample()
306	bootForger := ethClientSetup.AuctionVariables.BootCoordinator
307
308	var timer timer
309	ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
310	modules := newTestModules(t)
311	coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
312	_, err := ethClient.AuctionSetCoordinator(forger, "https://foo.bar")
313	require.NoError(t, err)
314	_, err = ethClient.AuctionBidSimple(2, big.NewInt(9999))
315	require.NoError(t, err)
316
317	modules2 := newTestModules(t)
318	bootCoord := newTestCoordinator(t, bootForger, ethClient, ethClientSetup, modules2)
319
320	assert.Equal(t, forger, coord.cfg.ForgerAddress)
321	assert.Equal(t, bootForger, bootCoord.cfg.ForgerAddress)
322	ethBootCoord, err := ethClient.AuctionGetBootCoordinator()
323	require.NoError(t, err)
324	assert.Equal(t, &bootForger, ethBootCoord)
325
326	var stats synchronizer.Stats
327
328	// Slot 0.  No bid, so the winner is the boot coordinator
329	stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum
330	stats.Sync.LastBlock = stats.Eth.LastBlock
331	stats.Sync.Auction.CurrentSlot.Forger = bootForger
332	assert.Equal(t, false, coord.canForge(&stats))
333	assert.Equal(t, true, bootCoord.canForge(&stats))
334
335	// Slot 0.  No bid, and we reach the deadline, so anyone can forge
336	stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum +
337		int64(ethClientSetup.AuctionVariables.SlotDeadline)
338	stats.Sync.LastBlock = stats.Eth.LastBlock
339	stats.Sync.Auction.CurrentSlot.Forger = bootForger
340	assert.Equal(t, true, coord.canForge(&stats))
341	assert.Equal(t, true, bootCoord.canForge(&stats))
342
343	// Slot 1. coordinator bid, so the winner is the coordinator
344	stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum +
345		1*int64(ethClientSetup.AuctionConstants.BlocksPerSlot)
346	stats.Sync.LastBlock = stats.Eth.LastBlock
347	stats.Sync.Auction.CurrentSlot.Forger = forger
348	assert.Equal(t, true, coord.canForge(&stats))
349	assert.Equal(t, false, bootCoord.canForge(&stats))
350}
351
352func TestCoordHandleMsgSyncBlock(t *testing.T) {
353	ethClientSetup := test.NewClientSetupExample()
354	bootForger := ethClientSetup.AuctionVariables.BootCoordinator
355
356	var timer timer
357	ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
358	modules := newTestModules(t)
359	coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
360	_, err := ethClient.AuctionSetCoordinator(forger, "https://foo.bar")
361	require.NoError(t, err)
362	_, err = ethClient.AuctionBidSimple(2, big.NewInt(9999))
363	require.NoError(t, err)
364
365	var msg MsgSyncBlock
366	stats := &msg.Stats
367	ctx := context.Background()
368
369	// Slot 0.  No bid, so the winner is the boot coordinator
370	// pipelineStarted: false -> false
371	stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum
372	stats.Sync.LastBlock = stats.Eth.LastBlock
373	stats.Sync.Auction.CurrentSlot.Forger = bootForger
374	assert.Equal(t, false, coord.canForge(stats))
375	require.NoError(t, coord.handleMsgSyncBlock(ctx, &msg))
376	assert.Nil(t, coord.pipeline)
377
378	// Slot 0.  No bid, and we reach the deadline, so anyone can forge
379	// pipelineStarted: false -> true
380	stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum +
381		int64(ethClientSetup.AuctionVariables.SlotDeadline)
382	stats.Sync.LastBlock = stats.Eth.LastBlock
383	stats.Sync.Auction.CurrentSlot.Forger = bootForger
384	assert.Equal(t, true, coord.canForge(stats))
385	require.NoError(t, coord.handleMsgSyncBlock(ctx, &msg))
386	assert.NotNil(t, coord.pipeline)
387
388	// Slot 0.  No bid, and we reach the deadline, so anyone can forge
389	// pipelineStarted: true -> true
390	stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum +
391		int64(ethClientSetup.AuctionVariables.SlotDeadline) + 1
392	stats.Sync.LastBlock = stats.Eth.LastBlock
393	stats.Sync.Auction.CurrentSlot.Forger = bootForger
394	assert.Equal(t, true, coord.canForge(stats))
395	require.NoError(t, coord.handleMsgSyncBlock(ctx, &msg))
396	assert.NotNil(t, coord.pipeline)
397
398	// Slot 0. No bid, so the winner is the boot coordinator
399	// pipelineStarted: true -> false
400	stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum +
401		1*int64(ethClientSetup.AuctionConstants.BlocksPerSlot)
402	stats.Sync.LastBlock = stats.Eth.LastBlock
403	stats.Sync.Auction.CurrentSlot.Forger = bootForger
404	assert.Equal(t, false, coord.canForge(stats))
405	require.NoError(t, coord.handleMsgSyncBlock(ctx, &msg))
406	assert.Nil(t, coord.pipeline)
407}
408
409func TestPipelineShouldL1L2Batch(t *testing.T) {
410	ethClientSetup := test.NewClientSetupExample()
411
412	var timer timer
413	ctx := context.Background()
414	ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
415	modules := newTestModules(t)
416	coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
417	pipeline, err := coord.newPipeline(ctx)
418	require.NoError(t, err)
419	pipeline.vars = coord.vars
420
421	// Check that the parameters are the ones we expect and use in this test
422	require.Equal(t, 0.5, pipeline.cfg.L1BatchTimeoutPerc)
423	require.Equal(t, int64(9), ethClientSetup.RollupVariables.ForgeL1L2BatchTimeout)
424	l1BatchTimeoutPerc := pipeline.cfg.L1BatchTimeoutPerc
425	l1BatchTimeout := ethClientSetup.RollupVariables.ForgeL1L2BatchTimeout
426
427	var stats synchronizer.Stats
428
429	startBlock := int64(100)
430
431	//
432	// No scheduled L1Batch
433	//
434
435	// Last L1Batch was a long time ago
436	stats.Eth.LastBlock.Num = startBlock
437	stats.Sync.LastBlock = stats.Eth.LastBlock
438	stats.Sync.LastL1BatchBlock = 0
439	pipeline.stats = stats
440	assert.Equal(t, true, pipeline.shouldL1L2Batch())
441
442	stats.Sync.LastL1BatchBlock = startBlock
443
444	// We are are one block before the timeout range * 0.5
445	stats.Eth.LastBlock.Num = startBlock + int64(float64(l1BatchTimeout)*l1BatchTimeoutPerc) - 1
446	stats.Sync.LastBlock = stats.Eth.LastBlock
447	pipeline.stats = stats
448	assert.Equal(t, false, pipeline.shouldL1L2Batch())
449
450	// We are are at timeout range * 0.5
451	stats.Eth.LastBlock.Num = startBlock + int64(float64(l1BatchTimeout)*l1BatchTimeoutPerc)
452	stats.Sync.LastBlock = stats.Eth.LastBlock
453	pipeline.stats = stats
454	assert.Equal(t, true, pipeline.shouldL1L2Batch())
455
456	//
457	// Scheduled L1Batch
458	//
459	pipeline.lastScheduledL1BatchBlockNum = startBlock
460	stats.Sync.LastL1BatchBlock = startBlock - 10
461
462	// We are are one block before the timeout range * 0.5
463	stats.Eth.LastBlock.Num = startBlock + int64(float64(l1BatchTimeout)*l1BatchTimeoutPerc) - 1
464	stats.Sync.LastBlock = stats.Eth.LastBlock
465	pipeline.stats = stats
466	assert.Equal(t, false, pipeline.shouldL1L2Batch())
467
468	// We are are at timeout range * 0.5
469	stats.Eth.LastBlock.Num = startBlock + int64(float64(l1BatchTimeout)*l1BatchTimeoutPerc)
470	stats.Sync.LastBlock = stats.Eth.LastBlock
471	pipeline.stats = stats
472	assert.Equal(t, true, pipeline.shouldL1L2Batch())
473}
474
475// ethAddTokens adds the tokens from the blocks to the blockchain
476func ethAddTokens(blocks []common.BlockData, client *test.Client) {
477	for _, block := range blocks {
478		for _, token := range block.Rollup.AddedTokens {
479			consts := eth.ERC20Consts{
480				Name:     fmt.Sprintf("Token %d", token.TokenID),
481				Symbol:   fmt.Sprintf("TK%d", token.TokenID),
482				Decimals: 18,
483			}
484			// tokenConsts[token.TokenID] = consts
485			client.CtlAddERC20(token.EthAddr, consts)
486		}
487	}
488}
489
490const testTokensLen = 3
491const testUsersLen = 4
492
493func preloadSync(t *testing.T, ethClient *test.Client, sync *synchronizer.Synchronizer,
494	historyDB *historydb.HistoryDB, stateDB *statedb.StateDB) *til.Context {
495	// Create a set with `testTokensLen` tokens and for each token
496	// `testUsersLen` accounts.
497	var set []til.Instruction
498	// set = append(set, til.Instruction{Typ: "Blockchain"})
499	for tokenID := 1; tokenID < testTokensLen; tokenID++ {
500		set = append(set, til.Instruction{
501			Typ:     til.TypeAddToken,
502			TokenID: common.TokenID(tokenID),
503		})
504	}
505	depositAmount, ok := new(big.Int).SetString("10225000000000000000000000000000000", 10)
506	require.True(t, ok)
507	for tokenID := 0; tokenID < testTokensLen; tokenID++ {
508		for user := 0; user < testUsersLen; user++ {
509			set = append(set, til.Instruction{
510				Typ:           common.TxTypeCreateAccountDeposit,
511				TokenID:       common.TokenID(tokenID),
512				DepositAmount: depositAmount,
513				From:          fmt.Sprintf("User%d", user),
514			})
515		}
516	}
517	set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
518	set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
519	set = append(set, til.Instruction{Typ: til.TypeNewBlock})
520
521	tc := til.NewContext(common.RollupConstMaxL1UserTx)
522	blocks, err := tc.GenerateBlocksFromInstructions(set)
523	require.NoError(t, err)
524	require.NotNil(t, blocks)
525
526	ethAddTokens(blocks, ethClient)
527	err = ethClient.CtlAddBlocks(blocks)
528	require.NoError(t, err)
529
530	ctx := context.Background()
531	for {
532		syncBlock, discards, err := sync.Sync2(ctx, nil)
533		require.NoError(t, err)
534		require.Nil(t, discards)
535		if syncBlock == nil {
536			break
537		}
538	}
539	dbTokens, err := historyDB.GetAllTokens()
540	require.Nil(t, err)
541	require.Equal(t, testTokensLen, len(dbTokens))
542
543	dbAccounts, err := historyDB.GetAllAccounts()
544	require.Nil(t, err)
545	require.Equal(t, testTokensLen*testUsersLen, len(dbAccounts))
546
547	sdbAccounts, err := stateDB.GetAccounts()
548	require.Nil(t, err)
549	require.Equal(t, testTokensLen*testUsersLen, len(sdbAccounts))
550
551	return tc
552}
553
554func TestPipeline1(t *testing.T) {
555	ethClientSetup := test.NewClientSetupExample()
556
557	var timer timer
558	ctx := context.Background()
559	ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
560	modules := newTestModules(t)
561	coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
562	sync := newTestSynchronizer(t, ethClient, ethClientSetup, modules)
563	pipeline, err := coord.newPipeline(ctx)
564	require.NoError(t, err)
565
566	require.NotNil(t, sync)
567	require.NotNil(t, pipeline)
568
569	// preload the synchronier (via the test ethClient) some tokens and
570	// users with positive balances
571	tilCtx := preloadSync(t, ethClient, sync, modules.historyDB, modules.stateDB)
572	syncStats := sync.Stats()
573	batchNum := common.BatchNum(syncStats.Sync.LastBatch)
574	syncSCVars := sync.SCVars()
575
576	// Insert some l2txs in the Pool
577	setPool := `
578Type: PoolL2
579
580PoolTransfer(0) User0-User1: 100 (126)
581PoolTransfer(0) User1-User2: 200 (126)
582PoolTransfer(0) User2-User3: 300 (126)
583	`
584	l2txs, err := tilCtx.GeneratePoolL2Txs(setPool)
585	require.NoError(t, err)
586	for _, tx := range l2txs {
587		err := modules.l2DB.AddTxTest(&tx) //nolint:gosec
588		require.NoError(t, err)
589	}
590
591	err = pipeline.reset(batchNum, syncStats.Sync.LastForgeL1TxsNum, &synchronizer.SCVariables{
592		Rollup:   *syncSCVars.Rollup,
593		Auction:  *syncSCVars.Auction,
594		WDelayer: *syncSCVars.WDelayer,
595	})
596	require.NoError(t, err)
597	// Sanity check
598	sdbAccounts, err := pipeline.txSelector.LocalAccountsDB().GetAccounts()
599	require.Nil(t, err)
600	require.Equal(t, testTokensLen*testUsersLen, len(sdbAccounts))
601
602	// Sanity check
603	sdbAccounts, err = pipeline.batchBuilder.LocalStateDB().GetAccounts()
604	require.Nil(t, err)
605	require.Equal(t, testTokensLen*testUsersLen, len(sdbAccounts))
606
607	// Sanity check
608	require.Equal(t, modules.stateDB.MerkleTree().Root(),
609		pipeline.batchBuilder.LocalStateDB().MerkleTree().Root())
610
611	batchNum++
612
613	selectionConfig := &txselector.SelectionConfig{
614		MaxL1UserTxs:        maxL1UserTxs,
615		MaxL1CoordinatorTxs: maxL1CoordinatorTxs,
616		ProcessTxsConfig: statedb.ProcessTxsConfig{
617			NLevels:  nLevels,
618			MaxFeeTx: maxFeeTxs,
619			MaxTx:    uint32(maxTxs),
620			MaxL1Tx:  uint32(maxL1Txs),
621		},
622	}
623
624	batchInfo, err := pipeline.forgeBatch(ctx, batchNum, selectionConfig)
625	require.NoError(t, err)
626	assert.Equal(t, 3, len(batchInfo.L2Txs))
627
628	batchNum++
629	batchInfo, err = pipeline.forgeBatch(ctx, batchNum, selectionConfig)
630	require.NoError(t, err)
631	assert.Equal(t, 0, len(batchInfo.L2Txs))
632}
633
634// TODO: Test Reorg
635// TODO: Test Pipeline
636// TODO: Test TxMonitor
637// TODO: Test forgeBatch
638// TODO: Test waitServerProof
639// TODO: Test handleReorg