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