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				// fmt.Println("DBG canForge")
269				stats.Sync.Auction.CurrentSlot.Forger = forger
270			}
271			// Copy stateDB to synchronizer if there was a new batch
272			source := fmt.Sprintf("%v/BatchNum%v", batchBuilderDBPath, stats.Sync.LastBatch)
273			dest := fmt.Sprintf("%v/BatchNum%v", syncDBPath, stats.Sync.LastBatch)
274			if stats.Sync.LastBatch != 0 {
275				if _, err := os.Stat(dest); os.IsNotExist(err) {
276					log.Infow("Making pebble checkpoint for sync",
277						"source", source, "dest", dest)
278					err = pebbleMakeCheckpoint(source, dest)
279					require.NoError(t, err)
280				}
281			}
282			coord.SendMsg(MsgSyncBlock{
283				Stats: stats,
284			})
285		}
286	}
287
288	// NOTE: With the current test, the coordinator will enter in forge
289	// time before the bidded slot because no one else is forging in the
290	// other slots before the slot deadline.
291	// simulate forgeSequence time
292	waitForSlot(2)
293	log.Info("~~~ simulate entering in forge time")
294	time.Sleep(1 * time.Second)
295
296	// simulate going out from forgeSequence
297	waitForSlot(3)
298	log.Info("~~~ simulate going out from forge time")
299	time.Sleep(1 * time.Second)
300
301	// simulate entering forgeSequence time again
302	waitForSlot(4)
303	log.Info("~~~ simulate entering in forge time again")
304	time.Sleep(2 * time.Second)
305
306	// simulate stopping forgerLoop by channel
307	log.Info("~~~ simulate stopping forgerLoop by closing coordinator stopch")
308	coord.Stop()
309	time.Sleep(1 * time.Second)
310}
311
312func TestCoordinatorStartStop(t *testing.T) {
313	ethClientSetup := test.NewClientSetupExample()
314	ethClientSetup.ChainID = big.NewInt(int64(chainID))
315	var timer timer
316	ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
317	modules := newTestModules(t)
318	coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
319	coord.Start()
320	coord.Stop()
321}
322
323func TestCoordCanForge(t *testing.T) {
324	ethClientSetup := test.NewClientSetupExample()
325	ethClientSetup.ChainID = big.NewInt(int64(chainID))
326	bootForger := ethClientSetup.AuctionVariables.BootCoordinator
327
328	var timer timer
329	ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
330	modules := newTestModules(t)
331	coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
332	_, err := ethClient.AuctionSetCoordinator(forger, "https://foo.bar")
333	require.NoError(t, err)
334	bid, ok := new(big.Int).SetString("12000000000000000000", 10)
335	if !ok {
336		panic("bad bid")
337	}
338	_, err = ethClient.AuctionBidSimple(2, bid)
339	require.NoError(t, err)
340
341	modules2 := newTestModules(t)
342	bootCoord := newTestCoordinator(t, bootForger, ethClient, ethClientSetup, modules2)
343
344	assert.Equal(t, forger, coord.cfg.ForgerAddress)
345	assert.Equal(t, bootForger, bootCoord.cfg.ForgerAddress)
346	ethBootCoord, err := ethClient.AuctionGetBootCoordinator()
347	require.NoError(t, err)
348	assert.Equal(t, &bootForger, ethBootCoord)
349
350	var stats synchronizer.Stats
351
352	// Slot 0.  No bid, so the winner is the boot coordinator
353	stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum
354	stats.Sync.LastBlock = stats.Eth.LastBlock
355	stats.Sync.Auction.CurrentSlot.Forger = bootForger
356	assert.Equal(t, false, coord.canForge(&stats))
357	assert.Equal(t, true, bootCoord.canForge(&stats))
358
359	// Slot 0.  No bid, and we reach the deadline, so anyone can forge
360	stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum +
361		int64(ethClientSetup.AuctionVariables.SlotDeadline)
362	stats.Sync.LastBlock = stats.Eth.LastBlock
363	stats.Sync.Auction.CurrentSlot.Forger = bootForger
364	assert.Equal(t, true, coord.canForge(&stats))
365	assert.Equal(t, true, bootCoord.canForge(&stats))
366
367	// Slot 1. coordinator bid, so the winner is the coordinator
368	stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum +
369		1*int64(ethClientSetup.AuctionConstants.BlocksPerSlot)
370	stats.Sync.LastBlock = stats.Eth.LastBlock
371	stats.Sync.Auction.CurrentSlot.Forger = forger
372	assert.Equal(t, true, coord.canForge(&stats))
373	assert.Equal(t, false, bootCoord.canForge(&stats))
374}
375
376func TestCoordHandleMsgSyncBlock(t *testing.T) {
377	ethClientSetup := test.NewClientSetupExample()
378	ethClientSetup.ChainID = big.NewInt(int64(chainID))
379	bootForger := ethClientSetup.AuctionVariables.BootCoordinator
380
381	var timer timer
382	ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
383	modules := newTestModules(t)
384	coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
385	_, err := ethClient.AuctionSetCoordinator(forger, "https://foo.bar")
386	require.NoError(t, err)
387	bid, ok := new(big.Int).SetString("11000000000000000000", 10)
388	if !ok {
389		panic("bad bid")
390	}
391	_, err = ethClient.AuctionBidSimple(2, bid)
392	require.NoError(t, err)
393
394	var msg MsgSyncBlock
395	stats := &msg.Stats
396	ctx := context.Background()
397
398	// Slot 0.  No bid, so the winner is the boot coordinator
399	// pipelineStarted: false -> false
400	stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum
401	stats.Sync.LastBlock = stats.Eth.LastBlock
402	stats.Sync.Auction.CurrentSlot.Forger = bootForger
403	assert.Equal(t, false, coord.canForge(stats))
404	require.NoError(t, coord.handleMsgSyncBlock(ctx, &msg))
405	assert.Nil(t, coord.pipeline)
406
407	// Slot 0.  No bid, and we reach the deadline, so anyone can forge
408	// pipelineStarted: false -> true
409	stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum +
410		int64(ethClientSetup.AuctionVariables.SlotDeadline)
411	stats.Sync.LastBlock = stats.Eth.LastBlock
412	stats.Sync.Auction.CurrentSlot.Forger = bootForger
413	assert.Equal(t, true, coord.canForge(stats))
414	require.NoError(t, coord.handleMsgSyncBlock(ctx, &msg))
415	assert.NotNil(t, coord.pipeline)
416
417	// Slot 0.  No bid, and we reach the deadline, so anyone can forge
418	// pipelineStarted: true -> true
419	stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum +
420		int64(ethClientSetup.AuctionVariables.SlotDeadline) + 1
421	stats.Sync.LastBlock = stats.Eth.LastBlock
422	stats.Sync.Auction.CurrentSlot.Forger = bootForger
423	assert.Equal(t, true, coord.canForge(stats))
424	require.NoError(t, coord.handleMsgSyncBlock(ctx, &msg))
425	assert.NotNil(t, coord.pipeline)
426
427	// Slot 0. No bid, so the winner is the boot coordinator
428	// pipelineStarted: true -> false
429	stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum +
430		1*int64(ethClientSetup.AuctionConstants.BlocksPerSlot)
431	stats.Sync.LastBlock = stats.Eth.LastBlock
432	stats.Sync.Auction.CurrentSlot.Forger = bootForger
433	assert.Equal(t, false, coord.canForge(stats))
434	require.NoError(t, coord.handleMsgSyncBlock(ctx, &msg))
435	assert.Nil(t, coord.pipeline)
436}
437
438func TestPipelineShouldL1L2Batch(t *testing.T) {
439	ethClientSetup := test.NewClientSetupExample()
440	ethClientSetup.ChainID = big.NewInt(int64(chainID))
441
442	var timer timer
443	ctx := context.Background()
444	ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
445	modules := newTestModules(t)
446	var stats synchronizer.Stats
447	coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
448	pipeline, err := coord.newPipeline(ctx, &stats)
449	require.NoError(t, err)
450	pipeline.vars = coord.vars
451
452	// Check that the parameters are the ones we expect and use in this test
453	require.Equal(t, 0.5, pipeline.cfg.L1BatchTimeoutPerc)
454	require.Equal(t, int64(9), ethClientSetup.RollupVariables.ForgeL1L2BatchTimeout)
455	l1BatchTimeoutPerc := pipeline.cfg.L1BatchTimeoutPerc
456	l1BatchTimeout := ethClientSetup.RollupVariables.ForgeL1L2BatchTimeout
457
458	startBlock := int64(100)
459
460	//
461	// No scheduled L1Batch
462	//
463
464	// Last L1Batch was a long time ago
465	stats.Eth.LastBlock.Num = startBlock
466	stats.Sync.LastBlock = stats.Eth.LastBlock
467	stats.Sync.LastL1BatchBlock = 0
468	pipeline.stats = stats
469	assert.Equal(t, true, pipeline.shouldL1L2Batch())
470
471	stats.Sync.LastL1BatchBlock = startBlock
472
473	// We are are one block before the timeout range * 0.5
474	stats.Eth.LastBlock.Num = startBlock + int64(float64(l1BatchTimeout)*l1BatchTimeoutPerc) - 1
475	stats.Sync.LastBlock = stats.Eth.LastBlock
476	pipeline.stats = stats
477	assert.Equal(t, false, pipeline.shouldL1L2Batch())
478
479	// We are are at timeout range * 0.5
480	stats.Eth.LastBlock.Num = startBlock + int64(float64(l1BatchTimeout)*l1BatchTimeoutPerc)
481	stats.Sync.LastBlock = stats.Eth.LastBlock
482	pipeline.stats = stats
483	assert.Equal(t, true, pipeline.shouldL1L2Batch())
484
485	//
486	// Scheduled L1Batch
487	//
488	pipeline.lastScheduledL1BatchBlockNum = startBlock
489	stats.Sync.LastL1BatchBlock = startBlock - 10
490
491	// We are are one block before the timeout range * 0.5
492	stats.Eth.LastBlock.Num = startBlock + int64(float64(l1BatchTimeout)*l1BatchTimeoutPerc) - 1
493	stats.Sync.LastBlock = stats.Eth.LastBlock
494	pipeline.stats = stats
495	assert.Equal(t, false, pipeline.shouldL1L2Batch())
496
497	// We are are at timeout range * 0.5
498	stats.Eth.LastBlock.Num = startBlock + int64(float64(l1BatchTimeout)*l1BatchTimeoutPerc)
499	stats.Sync.LastBlock = stats.Eth.LastBlock
500	pipeline.stats = stats
501	assert.Equal(t, true, pipeline.shouldL1L2Batch())
502}
503
504// ethAddTokens adds the tokens from the blocks to the blockchain
505func ethAddTokens(blocks []common.BlockData, client *test.Client) {
506	for _, block := range blocks {
507		for _, token := range block.Rollup.AddedTokens {
508			consts := eth.ERC20Consts{
509				Name:     fmt.Sprintf("Token %d", token.TokenID),
510				Symbol:   fmt.Sprintf("TK%d", token.TokenID),
511				Decimals: 18,
512			}
513			// tokenConsts[token.TokenID] = consts
514			client.CtlAddERC20(token.EthAddr, consts)
515		}
516	}
517}
518
519const testTokensLen = 3
520const testUsersLen = 4
521
522func preloadSync(t *testing.T, ethClient *test.Client, sync *synchronizer.Synchronizer,
523	historyDB *historydb.HistoryDB, stateDB *statedb.StateDB) *til.Context {
524	// Create a set with `testTokensLen` tokens and for each token
525	// `testUsersLen` accounts.
526	var set []til.Instruction
527	// set = append(set, til.Instruction{Typ: "Blockchain"})
528	for tokenID := 1; tokenID < testTokensLen; tokenID++ {
529		set = append(set, til.Instruction{
530			Typ:     til.TypeAddToken,
531			TokenID: common.TokenID(tokenID),
532		})
533	}
534	depositAmount, ok := new(big.Int).SetString("10225000000000000000000000000000000", 10)
535	require.True(t, ok)
536	for tokenID := 0; tokenID < testTokensLen; tokenID++ {
537		for user := 0; user < testUsersLen; user++ {
538			set = append(set, til.Instruction{
539				Typ:           common.TxTypeCreateAccountDeposit,
540				TokenID:       common.TokenID(tokenID),
541				DepositAmount: depositAmount,
542				From:          fmt.Sprintf("User%d", user),
543			})
544		}
545	}
546	set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
547	set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
548	set = append(set, til.Instruction{Typ: til.TypeNewBlock})
549
550	tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
551	blocks, err := tc.GenerateBlocksFromInstructions(set)
552	require.NoError(t, err)
553	require.NotNil(t, blocks)
554
555	ethAddTokens(blocks, ethClient)
556	err = ethClient.CtlAddBlocks(blocks)
557	require.NoError(t, err)
558
559	ctx := context.Background()
560	for {
561		syncBlock, discards, err := sync.Sync2(ctx, nil)
562		require.NoError(t, err)
563		require.Nil(t, discards)
564		if syncBlock == nil {
565			break
566		}
567	}
568	dbTokens, err := historyDB.GetAllTokens()
569	require.Nil(t, err)
570	require.Equal(t, testTokensLen, len(dbTokens))
571
572	dbAccounts, err := historyDB.GetAllAccounts()
573	require.Nil(t, err)
574	require.Equal(t, testTokensLen*testUsersLen, len(dbAccounts))
575
576	sdbAccounts, err := stateDB.GetAccounts()
577	require.Nil(t, err)
578	require.Equal(t, testTokensLen*testUsersLen, len(sdbAccounts))
579
580	return tc
581}
582
583func TestPipeline1(t *testing.T) {
584	ethClientSetup := test.NewClientSetupExample()
585	ethClientSetup.ChainID = big.NewInt(int64(chainID))
586
587	var timer timer
588	ctx := context.Background()
589	ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
590	modules := newTestModules(t)
591	coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
592	sync := newTestSynchronizer(t, ethClient, ethClientSetup, modules)
593
594	// preload the synchronier (via the test ethClient) some tokens and
595	// users with positive balances
596	tilCtx := preloadSync(t, ethClient, sync, modules.historyDB, modules.stateDB)
597	syncStats := sync.Stats()
598	batchNum := common.BatchNum(syncStats.Sync.LastBatch)
599	syncSCVars := sync.SCVars()
600
601	pipeline, err := coord.newPipeline(ctx, syncStats)
602	require.NoError(t, err)
603
604	// Insert some l2txs in the Pool
605	setPool := `
606Type: PoolL2
607
608PoolTransfer(0) User0-User1: 100 (126)
609PoolTransfer(0) User1-User2: 200 (126)
610PoolTransfer(0) User2-User3: 300 (126)
611	`
612	l2txs, err := tilCtx.GeneratePoolL2Txs(setPool)
613	require.NoError(t, err)
614	for _, tx := range l2txs {
615		err := modules.l2DB.AddTxTest(&tx) //nolint:gosec
616		require.NoError(t, err)
617	}
618
619	err = pipeline.reset(batchNum, syncStats.Sync.LastForgeL1TxsNum, &synchronizer.SCVariables{
620		Rollup:   *syncSCVars.Rollup,
621		Auction:  *syncSCVars.Auction,
622		WDelayer: *syncSCVars.WDelayer,
623	})
624	require.NoError(t, err)
625	// Sanity check
626	sdbAccounts, err := pipeline.txSelector.LocalAccountsDB().GetAccounts()
627	require.Nil(t, err)
628	require.Equal(t, testTokensLen*testUsersLen, len(sdbAccounts))
629
630	// Sanity check
631	sdbAccounts, err = pipeline.batchBuilder.LocalStateDB().GetAccounts()
632	require.Nil(t, err)
633	require.Equal(t, testTokensLen*testUsersLen, len(sdbAccounts))
634
635	// Sanity check
636	require.Equal(t, modules.stateDB.MT.Root(),
637		pipeline.batchBuilder.LocalStateDB().MT.Root())
638
639	batchNum++
640
641	batchInfo, err := pipeline.forgeBatch(batchNum)
642	require.NoError(t, err)
643	assert.Equal(t, 3, len(batchInfo.L2Txs))
644
645	batchNum++
646	batchInfo, err = pipeline.forgeBatch(batchNum)
647	require.NoError(t, err)
648	assert.Equal(t, 0, len(batchInfo.L2Txs))
649}
650
651func TestCoordinatorStress(t *testing.T) {
652	if os.Getenv("TEST_COORD_STRESS") == "" {
653		return
654	}
655	log.Info("Begin Test Coord Stress")
656	ethClientSetup := test.NewClientSetupExample()
657	ethClientSetup.ChainID = big.NewInt(int64(chainID))
658	var timer timer
659	ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
660	modules := newTestModules(t)
661	coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
662	syn := newTestSynchronizer(t, ethClient, ethClientSetup, modules)
663
664	coord.Start()
665	ctx, cancel := context.WithCancel(context.Background())
666	var wg sync.WaitGroup
667
668	// Synchronizer loop
669	wg.Add(1)
670	go func() {
671		for {
672			blockData, _, err := syn.Sync2(ctx, nil)
673			if ctx.Err() != nil {
674				wg.Done()
675				return
676			}
677			require.NoError(t, err)
678			if blockData != nil {
679				stats := syn.Stats()
680				coord.SendMsg(MsgSyncBlock{
681					Stats:   *stats,
682					Batches: blockData.Rollup.Batches,
683					Vars: synchronizer.SCVariablesPtr{
684						Rollup:   blockData.Rollup.Vars,
685						Auction:  blockData.Auction.Vars,
686						WDelayer: blockData.WDelayer.Vars,
687					},
688				})
689			} else {
690				time.Sleep(100 * time.Millisecond)
691			}
692		}
693	}()
694
695	// Blockchain mining loop
696	wg.Add(1)
697	go func() {
698		for {
699			select {
700			case <-ctx.Done():
701				wg.Done()
702				return
703			case <-time.After(1 * time.Second):
704				ethClient.CtlMineBlock()
705			}
706		}
707	}()
708
709	time.Sleep(600 * time.Second)
710
711	cancel()
712	wg.Wait()
713	coord.Stop()
714}
715
716func TestRollupForgeBatch(t *testing.T) {
717	if os.Getenv("TEST_ROLLUP_FORGE_BATCH") == "" {
718		return
719	}
720	const web3URL = "http://localhost:8545"
721	const password = "test"
722	addr := ethCommon.HexToAddress("0xb4124ceb3451635dacedd11767f004d8a28c6ee7")
723	sk, err := crypto.HexToECDSA(
724		"a8a54b2d8197bc0b19bb8a084031be71835580a01e70a45a13babd16c9bc1563")
725	require.NoError(t, err)
726	rollupAddr := ethCommon.HexToAddress("0x8EEaea23686c319133a7cC110b840d1591d9AeE0")
727	pathKeystore, err := ioutil.TempDir("", "tmpKeystore")
728	require.NoError(t, err)
729	deleteme = append(deleteme, pathKeystore)
730	ctx := context.Background()
731	batchInfo := &BatchInfo{}
732	proofClient := &prover.MockClient{}
733	chainID := uint16(0)
734
735	ethClient, err := ethclient.Dial(web3URL)
736	require.NoError(t, err)
737	ethCfg := eth.EthereumConfig{
738		CallGasLimit:        300000,
739		DeployGasLimit:      1000000,
740		GasPriceDiv:         100,
741		ReceiptTimeout:      60 * time.Second,
742		IntervalReceiptLoop: 500 * time.Millisecond,
743	}
744	scryptN := ethKeystore.LightScryptN
745	scryptP := ethKeystore.LightScryptP
746	keyStore := ethKeystore.NewKeyStore(pathKeystore,
747		scryptN, scryptP)
748	account, err := keyStore.ImportECDSA(sk, password)
749	require.NoError(t, err)
750	require.Equal(t, account.Address, addr)
751	err = keyStore.Unlock(account, password)
752	require.NoError(t, err)
753
754	client, err := eth.NewClient(ethClient, &account, keyStore, &eth.ClientConfig{
755		Ethereum: ethCfg,
756		Rollup: eth.RollupConfig{
757			Address: rollupAddr,
758		},
759		Auction: eth.AuctionConfig{
760			Address: ethCommon.Address{},
761			TokenHEZ: eth.TokenConfig{
762				Address: ethCommon.Address{},
763				Name:    "HEZ",
764			},
765		},
766		WDelayer: eth.WDelayerConfig{
767			Address: ethCommon.Address{},
768		},
769	})
770	require.NoError(t, err)
771
772	zkInputs := common.NewZKInputs(chainID, 100, 24, 512, 32, big.NewInt(1))
773	zkInputs.Metadata.NewStateRootRaw = &merkletree.Hash{1}
774	zkInputs.Metadata.NewExitRootRaw = &merkletree.Hash{2}
775	batchInfo.ZKInputs = zkInputs
776	err = proofClient.CalculateProof(ctx, batchInfo.ZKInputs)
777	require.NoError(t, err)
778
779	proof, pubInputs, err := proofClient.GetProof(ctx)
780	require.NoError(t, err)
781	batchInfo.Proof = proof
782	batchInfo.PublicInputs = pubInputs
783
784	batchInfo.ForgeBatchArgs = prepareForgeBatchArgs(batchInfo)
785	_, err = client.RollupForgeBatch(batchInfo.ForgeBatchArgs)
786	require.NoError(t, err)
787	batchInfo.Proof = proof
788}
789
790// TODO: Test Reorg
791// TODO: Test Pipeline
792// TODO: Test TxMonitor
793// TODO: Test forgeBatch
794// TODO: Test waitServerProof
795// TODO: Test handleReorg