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	"sync"
 10	"testing"
 11	"time"
 12
 13	ethKeystore "github.com/ethereum/go-ethereum/accounts/keystore"
 14	ethCommon "github.com/ethereum/go-ethereum/common"
 15	"github.com/ethereum/go-ethereum/crypto"
 16	"github.com/ethereum/go-ethereum/ethclient"
 17	"github.com/hermeznetwork/hermez-node/batchbuilder"
 18	"github.com/hermeznetwork/hermez-node/common"
 19	dbUtils "github.com/hermeznetwork/hermez-node/db"
 20	"github.com/hermeznetwork/hermez-node/db/historydb"
 21	"github.com/hermeznetwork/hermez-node/db/l2db"
 22	"github.com/hermeznetwork/hermez-node/db/statedb"
 23	"github.com/hermeznetwork/hermez-node/eth"
 24	"github.com/hermeznetwork/hermez-node/log"
 25	"github.com/hermeznetwork/hermez-node/prover"
 26	"github.com/hermeznetwork/hermez-node/synchronizer"
 27	"github.com/hermeznetwork/hermez-node/test"
 28	"github.com/hermeznetwork/hermez-node/test/til"
 29	"github.com/hermeznetwork/hermez-node/txprocessor"
 30	"github.com/hermeznetwork/hermez-node/txselector"
 31	"github.com/hermeznetwork/tracerr"
 32	"github.com/iden3/go-iden3-crypto/babyjub"
 33	"github.com/iden3/go-merkletree"
 34	"github.com/iden3/go-merkletree/db/pebble"
 35	"github.com/stretchr/testify/assert"
 36	"github.com/stretchr/testify/require"
 37)
 38
 39var deleteme = []string{}
 40
 41func pebbleMakeCheckpoint(source, dest string) error {
 42	// Remove dest folder (if it exists) before doing the checkpoint
 43	if _, err := os.Stat(dest); !os.IsNotExist(err) {
 44		err := os.RemoveAll(dest)
 45		if err != nil {
 46			return tracerr.Wrap(err)
 47		}
 48	} else if err != nil && !os.IsNotExist(err) {
 49		return tracerr.Wrap(err)
 50	}
 51
 52	sto, err := pebble.NewPebbleStorage(source, false)
 53	if err != nil {
 54		return tracerr.Wrap(err)
 55	}
 56	defer func() {
 57		errClose := sto.Pebble().Close()
 58		if errClose != nil {
 59			log.Errorw("Pebble.Close", "err", errClose)
 60		}
 61	}()
 62
 63	// execute Checkpoint
 64	err = sto.Pebble().Checkpoint(dest)
 65	if err != nil {
 66		return tracerr.Wrap(err)
 67	}
 68
 69	return nil
 70}
 71
 72func TestMain(m *testing.M) {
 73	exitVal := m.Run()
 74	for _, dir := range deleteme {
 75		if err := os.RemoveAll(dir); err != nil {
 76			panic(err)
 77		}
 78	}
 79	os.Exit(exitVal)
 80}
 81
 82var syncDBPath string
 83var txSelDBPath string
 84var batchBuilderDBPath string
 85
 86type modules struct {
 87	historyDB    *historydb.HistoryDB
 88	l2DB         *l2db.L2DB
 89	txSelector   *txselector.TxSelector
 90	batchBuilder *batchbuilder.BatchBuilder
 91	stateDB      *statedb.StateDB
 92}
 93
 94var maxL1Txs uint64 = 256
 95var maxTxs uint64 = 376
 96var nLevels uint32 = 32   //nolint:deadcode,unused
 97var maxFeeTxs uint32 = 64 //nolint:deadcode,varcheck
 98var chainID uint16 = 0
 99
100func newTestModules(t *testing.T) modules {
101	var err error
102	syncDBPath, err = ioutil.TempDir("", "tmpSyncDB")
103	require.NoError(t, err)
104	deleteme = append(deleteme, syncDBPath)
105	syncStateDB, err := statedb.NewStateDB(syncDBPath, 128, statedb.TypeSynchronizer, 48)
106	assert.NoError(t, err)
107
108	pass := os.Getenv("POSTGRES_PASS")
109	db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
110	require.NoError(t, err)
111	test.WipeDB(db)
112	l2DB := l2db.NewL2DB(db, 10, 100, 24*time.Hour)
113	historyDB := historydb.NewHistoryDB(db)
114
115	txSelDBPath, err = ioutil.TempDir("", "tmpTxSelDB")
116	require.NoError(t, err)
117	deleteme = append(deleteme, txSelDBPath)
118
119	var bjj babyjub.PublicKeyComp
120	err = bjj.UnmarshalText([]byte("c433f7a696b7aa3a5224efb3993baf0ccd9e92eecee0c29a3f6c8208a9e81d9e"))
121	require.NoError(t, err)
122	coordAccount := &txselector.CoordAccount{ // TODO TMP
123		Addr:                ethCommon.HexToAddress("0xc58d29fA6e86E4FAe04DDcEd660d45BCf3Cb2370"),
124		BJJ:                 bjj,
125		AccountCreationAuth: nil,
126	}
127	txSelector, err := txselector.NewTxSelector(coordAccount, txSelDBPath, syncStateDB, l2DB)
128	assert.NoError(t, err)
129
130	batchBuilderDBPath, err = ioutil.TempDir("", "tmpBatchBuilderDB")
131	require.NoError(t, err)
132	deleteme = append(deleteme, batchBuilderDBPath)
133	batchBuilder, err := batchbuilder.NewBatchBuilder(batchBuilderDBPath, syncStateDB, nil, 0, uint64(nLevels))
134	assert.NoError(t, err)
135
136	return modules{
137		historyDB:    historyDB,
138		l2DB:         l2DB,
139		txSelector:   txSelector,
140		batchBuilder: batchBuilder,
141		stateDB:      syncStateDB,
142	}
143}
144
145type timer struct {
146	time int64
147}
148
149func (t *timer) Time() int64 {
150	currentTime := t.time
151	t.time++
152	return currentTime
153}
154
155var bidder = ethCommon.HexToAddress("0x6b175474e89094c44da98b954eedeac495271d0f")
156var forger = ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
157
158func newTestCoordinator(t *testing.T, forgerAddr ethCommon.Address, ethClient *test.Client,
159	ethClientSetup *test.ClientSetup, modules modules) *Coordinator {
160	debugBatchPath, err := ioutil.TempDir("", "tmpDebugBatch")
161	require.NoError(t, err)
162	deleteme = append(deleteme, debugBatchPath)
163
164	conf := Config{
165		ForgerAddress:          forgerAddr,
166		ConfirmBlocks:          5,
167		L1BatchTimeoutPerc:     0.5,
168		EthClientAttempts:      5,
169		SyncRetryInterval:      400 * time.Microsecond,
170		EthClientAttemptsDelay: 100 * time.Millisecond,
171		TxManagerCheckInterval: 300 * time.Millisecond,
172		DebugBatchPath:         debugBatchPath,
173		Purger: PurgerCfg{
174			PurgeBatchDelay:      10,
175			PurgeBlockDelay:      10,
176			InvalidateBatchDelay: 4,
177			InvalidateBlockDelay: 4,
178		},
179		TxProcessorConfig: txprocessor.Config{
180			NLevels:  nLevels,
181			MaxFeeTx: maxFeeTxs,
182			MaxTx:    uint32(maxTxs),
183			MaxL1Tx:  uint32(maxL1Txs),
184			ChainID:  chainID,
185		},
186		VerifierIdx: 0,
187	}
188
189	serverProofs := []prover.Client{
190		&prover.MockClient{Delay: 300 * time.Millisecond},
191		&prover.MockClient{Delay: 400 * time.Millisecond},
192	}
193
194	scConsts := &synchronizer.SCConsts{
195		Rollup:   *ethClientSetup.RollupConstants,
196		Auction:  *ethClientSetup.AuctionConstants,
197		WDelayer: *ethClientSetup.WDelayerConstants,
198	}
199	initSCVars := &synchronizer.SCVariables{
200		Rollup:   *ethClientSetup.RollupVariables,
201		Auction:  *ethClientSetup.AuctionVariables,
202		WDelayer: *ethClientSetup.WDelayerVariables,
203	}
204	coord, err := NewCoordinator(conf, modules.historyDB, modules.l2DB, modules.txSelector,
205		modules.batchBuilder, serverProofs, ethClient, scConsts, initSCVars)
206	require.NoError(t, err)
207	return coord
208}
209
210func newTestSynchronizer(t *testing.T, ethClient *test.Client, ethClientSetup *test.ClientSetup,
211	modules modules) *synchronizer.Synchronizer {
212	sync, err := synchronizer.NewSynchronizer(ethClient, modules.historyDB, modules.stateDB,
213		synchronizer.Config{
214			StatsRefreshPeriod: 0 * time.Second,
215		})
216	require.NoError(t, err)
217	return sync
218}
219
220// TestCoordinatorFlow is a test where the coordinator is stared (which means
221// that goroutines are spawned), and ethereum blocks are mined via the
222// test.Client to simulate starting and stopping forging times.  This test
223// works without a synchronizer, and no l2txs are inserted in the pool, so all
224// the batches are forged empty.  The purpose of this test is to manually
225// observe via the logs that nothing crashes and that the coordinator starts
226// and stops forging at the right blocks.
227func TestCoordinatorFlow(t *testing.T) {
228	if os.Getenv("TEST_COORD_FLOW") == "" {
229		return
230	}
231	ethClientSetup := test.NewClientSetupExample()
232	ethClientSetup.ChainID = big.NewInt(int64(chainID))
233	var timer timer
234	ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
235	modules := newTestModules(t)
236	coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
237
238	// Bid for slot 2 and 4
239	_, err := ethClient.AuctionSetCoordinator(forger, "https://foo.bar")
240	require.NoError(t, err)
241	_, err = ethClient.AuctionBidSimple(2, big.NewInt(9999))
242	require.NoError(t, err)
243	_, err = ethClient.AuctionBidSimple(4, big.NewInt(9999))
244	require.NoError(t, err)
245
246	coord.Start()
247	time.Sleep(1 * time.Second)
248
249	waitForSlot := func(slot int64) {
250		for {
251			blockNum, err := ethClient.EthLastBlock()
252			require.NoError(t, err)
253			nextBlockSlot, err := ethClient.AuctionGetSlotNumber(blockNum + 1)
254			require.NoError(t, err)
255			if nextBlockSlot == slot {
256				break
257			}
258			ethClient.CtlMineBlock()
259			time.Sleep(100 * time.Millisecond)
260			var stats synchronizer.Stats
261			stats.Eth.LastBlock = *ethClient.CtlLastBlock()
262			stats.Sync.LastBlock = stats.Eth.LastBlock
263			stats.Eth.LastBatch = ethClient.CtlLastForgedBatch()
264			stats.Sync.LastBatch = stats.Eth.LastBatch
265			canForge, err := ethClient.AuctionCanForge(forger, blockNum+1)
266			require.NoError(t, err)
267			if canForge {
268				stats.Sync.Auction.CurrentSlot.Forger = forger
269			}
270			// Copy stateDB to synchronizer if there was a new batch
271			source := fmt.Sprintf("%v/BatchNum%v", batchBuilderDBPath, stats.Sync.LastBatch)
272			dest := fmt.Sprintf("%v/BatchNum%v", syncDBPath, stats.Sync.LastBatch)
273			if stats.Sync.LastBatch != 0 {
274				if _, err := os.Stat(dest); os.IsNotExist(err) {
275					log.Infow("Making pebble checkpoint for sync",
276						"source", source, "dest", dest)
277					err = pebbleMakeCheckpoint(source, dest)
278					require.NoError(t, err)
279				}
280			}
281			coord.SendMsg(MsgSyncBlock{
282				Stats: stats,
283			})
284		}
285	}
286
287	// NOTE: With the current test, the coordinator will enter in forge
288	// time before the bidded slot because no one else is forging in the
289	// other slots before the slot deadline.
290	// simulate forgeSequence time
291	waitForSlot(2)
292	log.Info("~~~ simulate entering in forge time")
293	time.Sleep(1 * time.Second)
294
295	// simulate going out from forgeSequence
296	waitForSlot(3)
297	log.Info("~~~ simulate going out from forge time")
298	time.Sleep(1 * time.Second)
299
300	// simulate entering forgeSequence time again
301	waitForSlot(4)
302	log.Info("~~~ simulate entering in forge time again")
303	time.Sleep(2 * time.Second)
304
305	// simulate stopping forgerLoop by channel
306	log.Info("~~~ simulate stopping forgerLoop by closing coordinator stopch")
307	coord.Stop()
308	time.Sleep(1 * time.Second)
309}
310
311func TestCoordinatorStartStop(t *testing.T) {
312	ethClientSetup := test.NewClientSetupExample()
313	ethClientSetup.ChainID = big.NewInt(int64(chainID))
314	var timer timer
315	ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
316	modules := newTestModules(t)
317	coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
318	coord.Start()
319	coord.Stop()
320}
321
322func TestCoordCanForge(t *testing.T) {
323	ethClientSetup := test.NewClientSetupExample()
324	ethClientSetup.ChainID = big.NewInt(int64(chainID))
325	bootForger := ethClientSetup.AuctionVariables.BootCoordinator
326
327	var timer timer
328	ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
329	modules := newTestModules(t)
330	coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
331	_, err := ethClient.AuctionSetCoordinator(forger, "https://foo.bar")
332	require.NoError(t, err)
333	bid, ok := new(big.Int).SetString("12000000000000000000", 10)
334	if !ok {
335		panic("bad bid")
336	}
337	_, err = ethClient.AuctionBidSimple(2, bid)
338	require.NoError(t, err)
339
340	modules2 := newTestModules(t)
341	bootCoord := newTestCoordinator(t, bootForger, ethClient, ethClientSetup, modules2)
342
343	assert.Equal(t, forger, coord.cfg.ForgerAddress)
344	assert.Equal(t, bootForger, bootCoord.cfg.ForgerAddress)
345	ethBootCoord, err := ethClient.AuctionGetBootCoordinator()
346	require.NoError(t, err)
347	assert.Equal(t, &bootForger, ethBootCoord)
348
349	var stats synchronizer.Stats
350
351	// Slot 0.  No bid, so the winner is the boot coordinator
352	stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum
353	stats.Sync.LastBlock = stats.Eth.LastBlock
354	stats.Sync.Auction.CurrentSlot.Forger = bootForger
355	assert.Equal(t, false, coord.canForge(&stats))
356	assert.Equal(t, true, bootCoord.canForge(&stats))
357
358	// Slot 0.  No bid, and we reach the deadline, so anyone can forge
359	stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum +
360		int64(ethClientSetup.AuctionVariables.SlotDeadline)
361	stats.Sync.LastBlock = stats.Eth.LastBlock
362	stats.Sync.Auction.CurrentSlot.Forger = bootForger
363	assert.Equal(t, true, coord.canForge(&stats))
364	assert.Equal(t, true, bootCoord.canForge(&stats))
365
366	// Slot 1. coordinator bid, so the winner is the coordinator
367	stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum +
368		1*int64(ethClientSetup.AuctionConstants.BlocksPerSlot)
369	stats.Sync.LastBlock = stats.Eth.LastBlock
370	stats.Sync.Auction.CurrentSlot.Forger = forger
371	assert.Equal(t, true, coord.canForge(&stats))
372	assert.Equal(t, false, bootCoord.canForge(&stats))
373}
374
375func TestCoordHandleMsgSyncBlock(t *testing.T) {
376	ethClientSetup := test.NewClientSetupExample()
377	ethClientSetup.ChainID = big.NewInt(int64(chainID))
378	bootForger := ethClientSetup.AuctionVariables.BootCoordinator
379
380	var timer timer
381	ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
382	modules := newTestModules(t)
383	coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
384	_, err := ethClient.AuctionSetCoordinator(forger, "https://foo.bar")
385	require.NoError(t, err)
386	bid, ok := new(big.Int).SetString("11000000000000000000", 10)
387	if !ok {
388		panic("bad bid")
389	}
390	_, err = ethClient.AuctionBidSimple(2, bid)
391	require.NoError(t, err)
392
393	var msg MsgSyncBlock
394	stats := &msg.Stats
395	ctx := context.Background()
396
397	// Slot 0.  No bid, so the winner is the boot coordinator
398	// pipelineStarted: false -> false
399	stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum
400	stats.Sync.LastBlock = stats.Eth.LastBlock
401	stats.Sync.Auction.CurrentSlot.Forger = bootForger
402	assert.Equal(t, false, coord.canForge(stats))
403	require.NoError(t, coord.handleMsgSyncBlock(ctx, &msg))
404	assert.Nil(t, coord.pipeline)
405
406	// Slot 0.  No bid, and we reach the deadline, so anyone can forge
407	// pipelineStarted: false -> true
408	stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum +
409		int64(ethClientSetup.AuctionVariables.SlotDeadline)
410	stats.Sync.LastBlock = stats.Eth.LastBlock
411	stats.Sync.Auction.CurrentSlot.Forger = bootForger
412	assert.Equal(t, true, coord.canForge(stats))
413	require.NoError(t, coord.handleMsgSyncBlock(ctx, &msg))
414	assert.NotNil(t, coord.pipeline)
415
416	// Slot 0.  No bid, and we reach the deadline, so anyone can forge
417	// pipelineStarted: true -> true
418	stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum +
419		int64(ethClientSetup.AuctionVariables.SlotDeadline) + 1
420	stats.Sync.LastBlock = stats.Eth.LastBlock
421	stats.Sync.Auction.CurrentSlot.Forger = bootForger
422	assert.Equal(t, true, coord.canForge(stats))
423	require.NoError(t, coord.handleMsgSyncBlock(ctx, &msg))
424	assert.NotNil(t, coord.pipeline)
425
426	// Slot 0. No bid, so the winner is the boot coordinator
427	// pipelineStarted: true -> false
428	stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum +
429		1*int64(ethClientSetup.AuctionConstants.BlocksPerSlot)
430	stats.Sync.LastBlock = stats.Eth.LastBlock
431	stats.Sync.Auction.CurrentSlot.Forger = bootForger
432	assert.Equal(t, false, coord.canForge(stats))
433	require.NoError(t, coord.handleMsgSyncBlock(ctx, &msg))
434	assert.Nil(t, coord.pipeline)
435}
436
437func TestPipelineShouldL1L2Batch(t *testing.T) {
438	ethClientSetup := test.NewClientSetupExample()
439	ethClientSetup.ChainID = big.NewInt(int64(chainID))
440
441	var timer timer
442	ctx := context.Background()
443	ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
444	modules := newTestModules(t)
445	var stats synchronizer.Stats
446	coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
447	pipeline, err := coord.newPipeline(ctx)
448	require.NoError(t, err)
449	pipeline.vars = coord.vars
450
451	// Check that the parameters are the ones we expect and use in this test
452	require.Equal(t, 0.5, pipeline.cfg.L1BatchTimeoutPerc)
453	require.Equal(t, int64(10), ethClientSetup.RollupVariables.ForgeL1L2BatchTimeout)
454	l1BatchTimeoutPerc := pipeline.cfg.L1BatchTimeoutPerc
455	l1BatchTimeout := ethClientSetup.RollupVariables.ForgeL1L2BatchTimeout
456
457	startBlock := int64(100)
458	// Empty batchInfo to pass to shouldL1L2Batch() which sets debug information
459	batchInfo := BatchInfo{}
460
461	//
462	// No scheduled L1Batch
463	//
464
465	// Last L1Batch was a long time ago
466	stats.Eth.LastBlock.Num = startBlock
467	stats.Sync.LastBlock = stats.Eth.LastBlock
468	stats.Sync.LastL1BatchBlock = 0
469	pipeline.stats = stats
470	assert.Equal(t, true, pipeline.shouldL1L2Batch(&batchInfo))
471
472	stats.Sync.LastL1BatchBlock = startBlock
473
474	// We are are one block before the timeout range * 0.5
475	stats.Eth.LastBlock.Num = startBlock - 1 + int64(float64(l1BatchTimeout-1)*l1BatchTimeoutPerc) - 1
476	stats.Sync.LastBlock = stats.Eth.LastBlock
477	pipeline.stats = stats
478	assert.Equal(t, false, pipeline.shouldL1L2Batch(&batchInfo))
479
480	// We are are at timeout range * 0.5
481	stats.Eth.LastBlock.Num = startBlock - 1 + int64(float64(l1BatchTimeout-1)*l1BatchTimeoutPerc)
482	stats.Sync.LastBlock = stats.Eth.LastBlock
483	pipeline.stats = stats
484	assert.Equal(t, true, pipeline.shouldL1L2Batch(&batchInfo))
485
486	//
487	// Scheduled L1Batch
488	//
489	pipeline.lastScheduledL1BatchBlockNum = startBlock
490	stats.Sync.LastL1BatchBlock = startBlock - 10
491
492	// We are are one block before the timeout range * 0.5
493	stats.Eth.LastBlock.Num = startBlock - 1 + int64(float64(l1BatchTimeout-1)*l1BatchTimeoutPerc) - 1
494	stats.Sync.LastBlock = stats.Eth.LastBlock
495	pipeline.stats = stats
496	assert.Equal(t, false, pipeline.shouldL1L2Batch(&batchInfo))
497
498	// We are are at timeout range * 0.5
499	stats.Eth.LastBlock.Num = startBlock - 1 + int64(float64(l1BatchTimeout-1)*l1BatchTimeoutPerc)
500	stats.Sync.LastBlock = stats.Eth.LastBlock
501	pipeline.stats = stats
502	assert.Equal(t, true, pipeline.shouldL1L2Batch(&batchInfo))
503}
504
505// ethAddTokens adds the tokens from the blocks to the blockchain
506func ethAddTokens(blocks []common.BlockData, client *test.Client) {
507	for _, block := range blocks {
508		for _, token := range block.Rollup.AddedTokens {
509			consts := eth.ERC20Consts{
510				Name:     fmt.Sprintf("Token %d", token.TokenID),
511				Symbol:   fmt.Sprintf("TK%d", token.TokenID),
512				Decimals: 18,
513			}
514			// tokenConsts[token.TokenID] = consts
515			client.CtlAddERC20(token.EthAddr, consts)
516		}
517	}
518}
519
520const testTokensLen = 3
521const testUsersLen = 4
522
523func preloadSync(t *testing.T, ethClient *test.Client, sync *synchronizer.Synchronizer,
524	historyDB *historydb.HistoryDB, stateDB *statedb.StateDB) *til.Context {
525	// Create a set with `testTokensLen` tokens and for each token
526	// `testUsersLen` accounts.
527	var set []til.Instruction
528	// set = append(set, til.Instruction{Typ: "Blockchain"})
529	for tokenID := 1; tokenID < testTokensLen; tokenID++ {
530		set = append(set, til.Instruction{
531			Typ:     til.TypeAddToken,
532			TokenID: common.TokenID(tokenID),
533		})
534	}
535	depositAmount, ok := new(big.Int).SetString("10225000000000000000000000000000000", 10)
536	require.True(t, ok)
537	for tokenID := 0; tokenID < testTokensLen; tokenID++ {
538		for user := 0; user < testUsersLen; user++ {
539			set = append(set, til.Instruction{
540				Typ:           common.TxTypeCreateAccountDeposit,
541				TokenID:       common.TokenID(tokenID),
542				DepositAmount: depositAmount,
543				From:          fmt.Sprintf("User%d", user),
544			})
545		}
546	}
547	set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
548	set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
549	set = append(set, til.Instruction{Typ: til.TypeNewBlock})
550
551	tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
552	blocks, err := tc.GenerateBlocksFromInstructions(set)
553	require.NoError(t, err)
554	require.NotNil(t, blocks)
555
556	ethAddTokens(blocks, ethClient)
557	err = ethClient.CtlAddBlocks(blocks)
558	require.NoError(t, err)
559
560	ctx := context.Background()
561	for {
562		syncBlock, discards, err := sync.Sync2(ctx, nil)
563		require.NoError(t, err)
564		require.Nil(t, discards)
565		if syncBlock == nil {
566			break
567		}
568	}
569	dbTokens, err := historyDB.GetAllTokens()
570	require.Nil(t, err)
571	require.Equal(t, testTokensLen, len(dbTokens))
572
573	dbAccounts, err := historyDB.GetAllAccounts()
574	require.Nil(t, err)
575	require.Equal(t, testTokensLen*testUsersLen, len(dbAccounts))
576
577	sdbAccounts, err := stateDB.GetAccounts()
578	require.Nil(t, err)
579	require.Equal(t, testTokensLen*testUsersLen, len(sdbAccounts))
580
581	return tc
582}
583
584func TestPipeline1(t *testing.T) {
585	ethClientSetup := test.NewClientSetupExample()
586	ethClientSetup.ChainID = big.NewInt(int64(chainID))
587
588	var timer timer
589	ctx := context.Background()
590	ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
591	modules := newTestModules(t)
592	coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
593	sync := newTestSynchronizer(t, ethClient, ethClientSetup, modules)
594
595	// preload the synchronier (via the test ethClient) some tokens and
596	// users with positive balances
597	tilCtx := preloadSync(t, ethClient, sync, modules.historyDB, modules.stateDB)
598	syncStats := sync.Stats()
599	batchNum := common.BatchNum(syncStats.Sync.LastBatch)
600	syncSCVars := sync.SCVars()
601
602	pipeline, err := coord.newPipeline(ctx)
603	require.NoError(t, err)
604
605	// Insert some l2txs in the Pool
606	setPool := `
607Type: PoolL2
608
609PoolTransfer(0) User0-User1: 100 (126)
610PoolTransfer(0) User1-User2: 200 (126)
611PoolTransfer(0) User2-User3: 300 (126)
612	`
613	l2txs, err := tilCtx.GeneratePoolL2Txs(setPool)
614	require.NoError(t, err)
615	for _, tx := range l2txs {
616		err := modules.l2DB.AddTxTest(&tx) //nolint:gosec
617		require.NoError(t, err)
618	}
619
620	err = pipeline.reset(batchNum, syncStats.Sync.LastForgeL1TxsNum, syncStats, &synchronizer.SCVariables{
621		Rollup:   *syncSCVars.Rollup,
622		Auction:  *syncSCVars.Auction,
623		WDelayer: *syncSCVars.WDelayer,
624	})
625	require.NoError(t, err)
626	// Sanity check
627	sdbAccounts, err := pipeline.txSelector.LocalAccountsDB().GetAccounts()
628	require.Nil(t, err)
629	require.Equal(t, testTokensLen*testUsersLen, len(sdbAccounts))
630
631	// Sanity check
632	sdbAccounts, err = pipeline.batchBuilder.LocalStateDB().GetAccounts()
633	require.Nil(t, err)
634	require.Equal(t, testTokensLen*testUsersLen, len(sdbAccounts))
635
636	// Sanity check
637	require.Equal(t, modules.stateDB.MT.Root(),
638		pipeline.batchBuilder.LocalStateDB().MT.Root())
639
640	batchNum++
641
642	batchInfo, err := pipeline.forgeBatch(batchNum)
643	require.NoError(t, err)
644	assert.Equal(t, 3, len(batchInfo.L2Txs))
645
646	batchNum++
647	batchInfo, err = pipeline.forgeBatch(batchNum)
648	require.NoError(t, err)
649	assert.Equal(t, 0, len(batchInfo.L2Txs))
650}
651
652func TestCoordinatorStress(t *testing.T) {
653	if os.Getenv("TEST_COORD_STRESS") == "" {
654		return
655	}
656	log.Info("Begin Test Coord Stress")
657	ethClientSetup := test.NewClientSetupExample()
658	ethClientSetup.ChainID = big.NewInt(int64(chainID))
659	var timer timer
660	ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
661	modules := newTestModules(t)
662	coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
663	syn := newTestSynchronizer(t, ethClient, ethClientSetup, modules)
664
665	coord.Start()
666	ctx, cancel := context.WithCancel(context.Background())
667	var wg sync.WaitGroup
668
669	// Synchronizer loop
670	wg.Add(1)
671	go func() {
672		for {
673			blockData, _, err := syn.Sync2(ctx, nil)
674			if ctx.Err() != nil {
675				wg.Done()
676				return
677			}
678			require.NoError(t, err)
679			if blockData != nil {
680				stats := syn.Stats()
681				coord.SendMsg(MsgSyncBlock{
682					Stats:   *stats,
683					Batches: blockData.Rollup.Batches,
684					Vars: synchronizer.SCVariablesPtr{
685						Rollup:   blockData.Rollup.Vars,
686						Auction:  blockData.Auction.Vars,
687						WDelayer: blockData.WDelayer.Vars,
688					},
689				})
690			} else {
691				time.Sleep(100 * time.Millisecond)
692			}
693		}
694	}()
695
696	// Blockchain mining loop
697	wg.Add(1)
698	go func() {
699		for {
700			select {
701			case <-ctx.Done():
702				wg.Done()
703				return
704			case <-time.After(1 * time.Second):
705				ethClient.CtlMineBlock()
706			}
707		}
708	}()
709
710	time.Sleep(600 * time.Second)
711
712	cancel()
713	wg.Wait()
714	coord.Stop()
715}
716
717func TestRollupForgeBatch(t *testing.T) {
718	if os.Getenv("TEST_ROLLUP_FORGE_BATCH") == "" {
719		return
720	}
721	const web3URL = "http://localhost:8545"
722	const password = "test"
723	addr := ethCommon.HexToAddress("0xb4124ceb3451635dacedd11767f004d8a28c6ee7")
724	sk, err := crypto.HexToECDSA(
725		"a8a54b2d8197bc0b19bb8a084031be71835580a01e70a45a13babd16c9bc1563")
726	require.NoError(t, err)
727	rollupAddr := ethCommon.HexToAddress("0x8EEaea23686c319133a7cC110b840d1591d9AeE0")
728	pathKeystore, err := ioutil.TempDir("", "tmpKeystore")
729	require.NoError(t, err)
730	deleteme = append(deleteme, pathKeystore)
731	ctx := context.Background()
732	batchInfo := &BatchInfo{}
733	proofClient := &prover.MockClient{}
734	chainID := uint16(0)
735
736	ethClient, err := ethclient.Dial(web3URL)
737	require.NoError(t, err)
738	ethCfg := eth.EthereumConfig{
739		CallGasLimit: 300000,
740		GasPriceDiv:  100,
741	}
742	scryptN := ethKeystore.LightScryptN
743	scryptP := ethKeystore.LightScryptP
744	keyStore := ethKeystore.NewKeyStore(pathKeystore,
745		scryptN, scryptP)
746	account, err := keyStore.ImportECDSA(sk, password)
747	require.NoError(t, err)
748	require.Equal(t, account.Address, addr)
749	err = keyStore.Unlock(account, password)
750	require.NoError(t, err)
751
752	client, err := eth.NewClient(ethClient, &account, keyStore, &eth.ClientConfig{
753		Ethereum: ethCfg,
754		Rollup: eth.RollupConfig{
755			Address: rollupAddr,
756		},
757		Auction: eth.AuctionConfig{
758			Address: ethCommon.Address{},
759			TokenHEZ: eth.TokenConfig{
760				Address: ethCommon.Address{},
761				Name:    "HEZ",
762			},
763		},
764		WDelayer: eth.WDelayerConfig{
765			Address: ethCommon.Address{},
766		},
767	})
768	require.NoError(t, err)
769
770	zkInputs := common.NewZKInputs(chainID, 100, 24, 512, 32, big.NewInt(1))
771	zkInputs.Metadata.NewStateRootRaw = &merkletree.Hash{1}
772	zkInputs.Metadata.NewExitRootRaw = &merkletree.Hash{2}
773	batchInfo.ZKInputs = zkInputs
774	err = proofClient.CalculateProof(ctx, batchInfo.ZKInputs)
775	require.NoError(t, err)
776
777	proof, pubInputs, err := proofClient.GetProof(ctx)
778	require.NoError(t, err)
779	batchInfo.Proof = proof
780	batchInfo.PublicInputs = pubInputs
781
782	batchInfo.ForgeBatchArgs = prepareForgeBatchArgs(batchInfo)
783	_, err = client.RollupForgeBatch(batchInfo.ForgeBatchArgs)
784	require.NoError(t, err)
785	batchInfo.Proof = proof
786}
787
788// TODO: Test Reorg
789// TODO: Test Pipeline
790// TODO: Test TxMonitor
791// TODO: Test forgeBatch
792// TODO: Test waitServerProof
793// TODO: Test handleReorg