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