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