arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/synchronizer/synchronizer_test.go
synchronizer/synchronizer_test.goRaw
  1package synchronizer
  2
  3import (
  4	"context"
  5	"encoding/json"
  6	"fmt"
  7	"io/ioutil"
  8	"math/big"
  9	"os"
 10	"sort"
 11	"testing"
 12
 13	ethCommon "github.com/ethereum/go-ethereum/common"
 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/statedb"
 18	"github.com/hermeznetwork/hermez-node/eth"
 19	"github.com/hermeznetwork/hermez-node/test"
 20	"github.com/hermeznetwork/hermez-node/test/til"
 21	"github.com/jinzhu/copier"
 22	"github.com/stretchr/testify/assert"
 23	"github.com/stretchr/testify/require"
 24)
 25
 26var tokenConsts = map[common.TokenID]eth.ERC20Consts{}
 27
 28type timer struct {
 29	time int64
 30}
 31
 32func (t *timer) Time() int64 {
 33	currentTime := t.time
 34	t.time++
 35	return currentTime
 36}
 37
 38func accountsCmp(accounts []common.Account) func(i, j int) bool {
 39	return func(i, j int) bool { return accounts[i].Idx < accounts[j].Idx }
 40}
 41
 42// Check Sync output and HistoryDB state against expected values generated by
 43// til
 44func checkSyncBlock(t *testing.T, s *Synchronizer, blockNum int, block, syncBlock *common.BlockData) {
 45	// Check Blocks
 46	dbBlocks, err := s.historyDB.GetAllBlocks()
 47	require.Nil(t, err)
 48	dbBlocks = dbBlocks[1:] // ignore block 0, added by default in the DB
 49	assert.Equal(t, blockNum, len(dbBlocks))
 50	assert.Equal(t, int64(blockNum), dbBlocks[blockNum-1].Num)
 51	assert.NotEqual(t, dbBlocks[blockNum-1].Hash, dbBlocks[blockNum-2].Hash)
 52	assert.Greater(t, dbBlocks[blockNum-1].Timestamp.Unix(), dbBlocks[blockNum-2].Timestamp.Unix())
 53
 54	// Check Tokens
 55	assert.Equal(t, len(block.Rollup.AddedTokens), len(syncBlock.Rollup.AddedTokens))
 56	dbTokens, err := s.historyDB.GetAllTokens()
 57	require.Nil(t, err)
 58	dbTokens = dbTokens[1:] // ignore token 0, added by default in the DB
 59	for i, token := range block.Rollup.AddedTokens {
 60		dbToken := dbTokens[i]
 61		syncToken := syncBlock.Rollup.AddedTokens[i]
 62
 63		assert.Equal(t, block.Block.Num, syncToken.EthBlockNum)
 64		assert.Equal(t, token.TokenID, syncToken.TokenID)
 65		assert.Equal(t, token.EthAddr, syncToken.EthAddr)
 66		tokenConst := tokenConsts[token.TokenID]
 67		assert.Equal(t, tokenConst.Name, syncToken.Name)
 68		assert.Equal(t, tokenConst.Symbol, syncToken.Symbol)
 69		assert.Equal(t, tokenConst.Decimals, syncToken.Decimals)
 70
 71		var tokenCpy historydb.TokenWithUSD
 72		//nolint:gosec
 73		require.Nil(t, copier.Copy(&tokenCpy, &token))      // copy common.Token to historydb.TokenWithUSD
 74		require.Nil(t, copier.Copy(&tokenCpy, &tokenConst)) // copy common.Token to historydb.TokenWithUSD
 75		tokenCpy.ItemID = dbToken.ItemID                    // we don't care about ItemID
 76		assert.Equal(t, tokenCpy, dbToken)
 77	}
 78
 79	// Check submitted L1UserTxs
 80	assert.Equal(t, len(block.Rollup.L1UserTxs), len(syncBlock.Rollup.L1UserTxs))
 81	dbL1UserTxs, err := s.historyDB.GetAllL1UserTxs()
 82	require.Nil(t, err)
 83	// Ignore BatchNum in syncBlock.L1UserTxs because this value is set by
 84	// the HistoryDB. Also ignore EffectiveAmount & EffectiveDepositAmount
 85	// because this value is set by StateDB.ProcessTxs.
 86	for i := range syncBlock.Rollup.L1UserTxs {
 87		syncBlock.Rollup.L1UserTxs[i].BatchNum = block.Rollup.L1UserTxs[i].BatchNum
 88		assert.Nil(t, syncBlock.Rollup.L1UserTxs[i].EffectiveDepositAmount)
 89		assert.Nil(t, syncBlock.Rollup.L1UserTxs[i].EffectiveAmount)
 90	}
 91	assert.Equal(t, block.Rollup.L1UserTxs, syncBlock.Rollup.L1UserTxs)
 92	for _, tx := range block.Rollup.L1UserTxs {
 93		var dbTx *common.L1Tx
 94		// Find tx in DB output
 95		for _, _dbTx := range dbL1UserTxs {
 96			if *tx.ToForgeL1TxsNum == *_dbTx.ToForgeL1TxsNum &&
 97				tx.Position == _dbTx.Position {
 98				dbTx = new(common.L1Tx)
 99				*dbTx = _dbTx
100				break
101			}
102		}
103		// If the tx has been forged in this block, this will be
104		// reflected in the DB, and so the Effective values will be
105		// already set
106		if dbTx.BatchNum != nil {
107			tx.EffectiveAmount = tx.Amount
108			tx.EffectiveDepositAmount = tx.DepositAmount
109		}
110		assert.Equal(t, &tx, dbTx) //nolint:gosec
111	}
112
113	// Check Batches
114	assert.Equal(t, len(block.Rollup.Batches), len(syncBlock.Rollup.Batches))
115	dbBatches, err := s.historyDB.GetAllBatches()
116	require.Nil(t, err)
117
118	dbL1CoordinatorTxs, err := s.historyDB.GetAllL1CoordinatorTxs()
119	require.Nil(t, err)
120	dbL2Txs, err := s.historyDB.GetAllL2Txs()
121	require.Nil(t, err)
122	dbExits, err := s.historyDB.GetAllExits()
123	require.Nil(t, err)
124	// dbL1CoordinatorTxs := []common.L1Tx{}
125	for i, batch := range block.Rollup.Batches {
126		var dbBatch *common.Batch
127		// Find batch in DB output
128		for _, _dbBatch := range dbBatches {
129			if batch.Batch.BatchNum == _dbBatch.BatchNum {
130				dbBatch = new(common.Batch)
131				*dbBatch = _dbBatch
132				break
133			}
134		}
135		syncBatch := syncBlock.Rollup.Batches[i]
136
137		// We don't care about TotalFeesUSD.  Use the syncBatch that
138		// has a TotalFeesUSD inserted by the HistoryDB
139		batch.Batch.TotalFeesUSD = syncBatch.Batch.TotalFeesUSD
140		assert.Equal(t, batch.CreatedAccounts, syncBatch.CreatedAccounts)
141		batch.Batch.NumAccounts = len(batch.CreatedAccounts)
142
143		// Test field by field to facilitate debugging of errors
144		assert.Equal(t, batch.L1UserTxs, syncBatch.L1UserTxs)
145		assert.Equal(t, batch.L1CoordinatorTxs, syncBatch.L1CoordinatorTxs)
146		assert.Equal(t, batch.L2Txs, syncBatch.L2Txs)
147		// In exit tree, we only check AccountIdx and Balance, because
148		// it's what we have precomputed before.
149		require.Equal(t, len(batch.ExitTree), len(syncBatch.ExitTree))
150		for j := range batch.ExitTree {
151			exit := &batch.ExitTree[j]
152			assert.Equal(t, exit.AccountIdx, syncBatch.ExitTree[j].AccountIdx)
153			assert.Equal(t, exit.Balance, syncBatch.ExitTree[j].Balance)
154			*exit = syncBatch.ExitTree[j]
155		}
156		assert.Equal(t, batch.Batch, syncBatch.Batch)
157		assert.Equal(t, batch, syncBatch)
158		assert.Equal(t, &batch.Batch, dbBatch) //nolint:gosec
159
160		// Check forged L1UserTxs from DB, and check effective values
161		// in sync output
162		for j, tx := range batch.L1UserTxs {
163			var dbTx *common.L1Tx
164			// Find tx in DB output
165			for _, _dbTx := range dbL1UserTxs {
166				if *tx.BatchNum == *_dbTx.BatchNum &&
167					tx.Position == _dbTx.Position {
168					dbTx = new(common.L1Tx)
169					*dbTx = _dbTx
170					break
171				}
172			}
173			assert.Equal(t, &tx, dbTx) //nolint:gosec
174
175			syncTx := &syncBlock.Rollup.Batches[i].L1UserTxs[j]
176			assert.Equal(t, syncTx.DepositAmount, syncTx.EffectiveDepositAmount)
177			assert.Equal(t, syncTx.Amount, syncTx.EffectiveAmount)
178		}
179
180		// Check L1CoordinatorTxs from DB
181		for _, tx := range batch.L1CoordinatorTxs {
182			var dbTx *common.L1Tx
183			// Find tx in DB output
184			for _, _dbTx := range dbL1CoordinatorTxs {
185				if *tx.BatchNum == *_dbTx.BatchNum &&
186					tx.Position == _dbTx.Position {
187					dbTx = new(common.L1Tx)
188					*dbTx = _dbTx
189					break
190				}
191			}
192			assert.Equal(t, &tx, dbTx) //nolint:gosec
193		}
194
195		// Check L2Txs from DB
196		for _, tx := range batch.L2Txs {
197			var dbTx *common.L2Tx
198			// Find tx in DB output
199			for _, _dbTx := range dbL2Txs {
200				if tx.BatchNum == _dbTx.BatchNum &&
201					tx.Position == _dbTx.Position {
202					dbTx = new(common.L2Tx)
203					*dbTx = _dbTx
204					break
205				}
206			}
207			assert.Equal(t, &tx, dbTx) //nolint:gosec
208		}
209
210		// Check Exits from DB
211		for _, exit := range batch.ExitTree {
212			var dbExit *common.ExitInfo
213			// Find exit in DB output
214			for _, _dbExit := range dbExits {
215				if exit.BatchNum == _dbExit.BatchNum &&
216					exit.AccountIdx == _dbExit.AccountIdx {
217					dbExit = new(common.ExitInfo)
218					*dbExit = _dbExit
219					break
220				}
221			}
222			// Compare MerkleProof in JSON because unmarshaled 0
223			// big.Int leaves the internal big.Int array at nil,
224			// and gives trouble when comparing big.Int with
225			// internal big.Int array != nil but empty.
226			mtp, err := json.Marshal(exit.MerkleProof)
227			require.Nil(t, err)
228			dbMtp, err := json.Marshal(dbExit.MerkleProof)
229			require.Nil(t, err)
230			assert.Equal(t, mtp, dbMtp)
231			dbExit.MerkleProof = exit.MerkleProof
232			assert.Equal(t, &exit, dbExit) //nolint:gosec
233		}
234	}
235
236	// Compare accounts from HistoryDB with StateDB (they should match)
237	dbAccounts, err := s.historyDB.GetAllAccounts()
238	require.Nil(t, err)
239	sdbAccounts, err := s.stateDB.GetAccounts()
240	require.Nil(t, err)
241	assertEqualAccountsHistoryDBStateDB(t, dbAccounts, sdbAccounts)
242}
243
244func assertEqualAccountsHistoryDBStateDB(t *testing.T, hdbAccs, sdbAccs []common.Account) {
245	assert.Equal(t, len(hdbAccs), len(sdbAccs))
246	sort.SliceStable(hdbAccs, accountsCmp(hdbAccs))
247	sort.SliceStable(sdbAccs, accountsCmp(sdbAccs))
248	for i := range hdbAccs {
249		hdbAcc := hdbAccs[i]
250		sdbAcc := sdbAccs[i]
251		assert.Equal(t, hdbAcc.Idx, sdbAcc.Idx)
252		assert.Equal(t, hdbAcc.TokenID, sdbAcc.TokenID)
253		assert.Equal(t, hdbAcc.EthAddr, sdbAcc.EthAddr)
254		assert.Equal(t, hdbAcc.PublicKey, sdbAcc.PublicKey)
255	}
256}
257
258// ethAddTokens adds the tokens from the blocks to the blockchain
259func ethAddTokens(blocks []common.BlockData, client *test.Client) {
260	for _, block := range blocks {
261		for _, token := range block.Rollup.AddedTokens {
262			consts := eth.ERC20Consts{
263				Name:     fmt.Sprintf("Token %d", token.TokenID),
264				Symbol:   fmt.Sprintf("TK%d", token.TokenID),
265				Decimals: 18,
266			}
267			tokenConsts[token.TokenID] = consts
268			client.CtlAddERC20(token.EthAddr, consts)
269		}
270	}
271}
272
273// ethAddBlocks adds block data to the smart contracts
274func ethAddBlocks(t *testing.T, blocks []common.BlockData,
275	client *test.Client, clientSetup *test.ClientSetup) {
276	for _, block := range blocks {
277		for _, token := range block.Rollup.AddedTokens {
278			_, err := client.RollupAddTokenSimple(token.EthAddr, clientSetup.RollupVariables.FeeAddToken)
279			require.Nil(t, err)
280		}
281		for _, tx := range block.Rollup.L1UserTxs {
282			client.CtlSetAddr(tx.FromEthAddr)
283			_, err := client.RollupL1UserTxERC20ETH(tx.FromBJJ, int64(tx.FromIdx), tx.DepositAmount, tx.Amount,
284				uint32(tx.TokenID), int64(tx.ToIdx))
285			require.Nil(t, err)
286		}
287		client.CtlSetAddr(clientSetup.AuctionVariables.BootCoordinator)
288		for _, batch := range block.Rollup.Batches {
289			_, err := client.RollupForgeBatch(&eth.RollupForgeBatchArgs{
290				NewLastIdx:            batch.Batch.LastIdx,
291				NewStRoot:             batch.Batch.StateRoot,
292				NewExitRoot:           batch.Batch.ExitRoot,
293				L1CoordinatorTxs:      batch.L1CoordinatorTxs,
294				L1CoordinatorTxsAuths: [][]byte{}, // Intentionally empty
295				L2TxsData:             batch.L2Txs,
296				FeeIdxCoordinator:     batch.Batch.FeeIdxsCoordinator,
297				// Circuit selector
298				VerifierIdx: 0, // Intentionally empty
299				L1Batch:     batch.L1Batch,
300				ProofA:      [2]*big.Int{},    // Intentionally empty
301				ProofB:      [2][2]*big.Int{}, // Intentionally empty
302				ProofC:      [2]*big.Int{},    // Intentionally empty
303			})
304			require.Nil(t, err)
305		}
306		// Mine block and sync
307		client.CtlMineBlock()
308	}
309}
310
311func TestSync(t *testing.T) {
312	//
313	// Setup
314	//
315
316	ctx := context.Background()
317	// Int State DB
318	dir, err := ioutil.TempDir("", "tmpdb")
319	require.Nil(t, err)
320	defer assert.Nil(t, os.RemoveAll(dir))
321
322	stateDB, err := statedb.NewStateDB(dir, statedb.TypeSynchronizer, 32)
323	assert.NoError(t, err)
324
325	// Init History DB
326	pass := os.Getenv("POSTGRES_PASS")
327	db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
328	require.Nil(t, err)
329	historyDB := historydb.NewHistoryDB(db)
330	// Clear DB
331	test.WipeDB(historyDB.DB())
332
333	// Init eth client
334	var timer timer
335	clientSetup := test.NewClientSetupExample()
336	bootCoordAddr := clientSetup.AuctionVariables.BootCoordinator
337	client := test.NewClient(true, &timer, &ethCommon.Address{}, clientSetup)
338
339	// Create Synchronizer
340	s, err := NewSynchronizer(client, historyDB, stateDB, Config{
341		StartBlockNum: ConfigStartBlockNum{
342			Rollup:   1,
343			Auction:  1,
344			WDelayer: 1,
345		},
346		InitialVariables: SCVariables{
347			Rollup:   *clientSetup.RollupVariables,
348			Auction:  *clientSetup.AuctionVariables,
349			WDelayer: *clientSetup.WDelayerVariables,
350		},
351	})
352	require.Nil(t, err)
353
354	//
355	// First Sync from an initial state
356	//
357	var vars struct {
358		Rollup   *common.RollupVariables
359		Auction  *common.AuctionVariables
360		WDelayer *common.WDelayerVariables
361	}
362	stats := s.Stats()
363	assert.Equal(t, false, stats.Synced())
364
365	// Test Sync for rollup genesis block
366	syncBlock, discards, err := s.Sync2(ctx, nil)
367	require.Nil(t, err)
368	require.Nil(t, discards)
369	require.NotNil(t, syncBlock)
370	require.Nil(t, syncBlock.Rollup.Vars)
371	require.Nil(t, syncBlock.Auction.Vars)
372	require.Nil(t, syncBlock.WDelayer.Vars)
373	assert.Equal(t, int64(1), syncBlock.Block.Num)
374	stats = s.Stats()
375	assert.Equal(t, int64(1), stats.Eth.FirstBlockNum)
376	assert.Equal(t, int64(1), stats.Eth.LastBlock.Num)
377	assert.Equal(t, int64(1), stats.Sync.LastBlock.Num)
378	vars.Rollup, vars.Auction, vars.WDelayer = s.SCVars()
379	assert.Equal(t, clientSetup.RollupVariables, vars.Rollup)
380	assert.Equal(t, clientSetup.AuctionVariables, vars.Auction)
381	assert.Equal(t, clientSetup.WDelayerVariables, vars.WDelayer)
382
383	dbBlocks, err := s.historyDB.GetAllBlocks()
384	require.Nil(t, err)
385	assert.Equal(t, 2, len(dbBlocks))
386	assert.Equal(t, int64(1), dbBlocks[1].Num)
387
388	// Sync again and expect no new blocks
389	syncBlock, discards, err = s.Sync2(ctx, nil)
390	require.Nil(t, err)
391	require.Nil(t, discards)
392	require.Nil(t, syncBlock)
393
394	//
395	// Generate blockchain and smart contract data, and fill the test smart contracts
396	//
397
398	// Generate blockchain data with til
399	set1 := `
400		Type: Blockchain
401
402		AddToken(1)
403		AddToken(2)
404		AddToken(3)
405
406		CreateAccountDeposit(1) C: 2000 // Idx=256+2=258
407		CreateAccountDeposit(2) A: 2000 // Idx=256+3=259
408		CreateAccountDeposit(1) D: 500  // Idx=256+4=260
409		CreateAccountDeposit(2) B: 500  // Idx=256+5=261
410		CreateAccountDeposit(2) C: 500  // Idx=256+6=262
411
412		CreateAccountCoordinator(1) A // Idx=256+0=256
413		CreateAccountCoordinator(1) B // Idx=256+1=257
414
415		> batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{5}
416		> batchL1 // forge defined L1UserTxs{5}, freeze L1UserTxs{nil}
417		> block // blockNum=2
418
419		CreateAccountDepositTransfer(1) E-A: 1000, 200 // Idx=256+7=263
420		ForceTransfer(1) C-B: 80
421		ForceExit(1) A: 100
422		ForceExit(1) B: 80
423		ForceTransfer(1) A-D: 100
424
425		Transfer(1) C-A: 100 (200)
426		Exit(1) C: 50 (200)
427		Exit(1) D: 30 (200)
428
429		> batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{3}
430		> batchL1 // forge L1UserTxs{3}, freeze defined L1UserTxs{nil}
431		> block // blockNum=3
432	`
433	tc := til.NewContext(common.RollupConstMaxL1UserTx)
434	tilCfgExtra := til.ConfigExtra{
435		BootCoordAddr: bootCoordAddr,
436		CoordUser:     "A",
437	}
438	blocks, err := tc.GenerateBlocks(set1)
439	require.Nil(t, err)
440	// Sanity check
441	require.Equal(t, 2, len(blocks))
442	// blocks 0 (blockNum=2)
443	i := 0
444	require.Equal(t, 2, int(blocks[i].Block.Num))
445	require.Equal(t, 3, len(blocks[i].Rollup.AddedTokens))
446	require.Equal(t, 5, len(blocks[i].Rollup.L1UserTxs))
447	require.Equal(t, 2, len(blocks[i].Rollup.Batches))
448	require.Equal(t, 2, len(blocks[i].Rollup.Batches[0].L1CoordinatorTxs))
449	// blocks 1 (blockNum=3)
450	i = 1
451	require.Equal(t, 3, int(blocks[i].Block.Num))
452	require.Equal(t, 5, len(blocks[i].Rollup.L1UserTxs))
453	require.Equal(t, 2, len(blocks[i].Rollup.Batches))
454	require.Equal(t, 3, len(blocks[i].Rollup.Batches[0].L2Txs))
455
456	// Generate extra required data
457	ethAddTokens(blocks, client)
458
459	err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
460	assert.NoError(t, err)
461	tc.FillBlocksL1UserTxsBatchNum(blocks)
462	err = tc.FillBlocksForgedL1UserTxs(blocks)
463	assert.NoError(t, err)
464
465	// Add block data to the smart contracts
466	ethAddBlocks(t, blocks, client, clientSetup)
467
468	//
469	// Sync to synchronize the current state from the test smart contracts,
470	// and check the outcome
471	//
472
473	// Block 2
474
475	syncBlock, discards, err = s.Sync2(ctx, nil)
476	require.Nil(t, err)
477	require.Nil(t, discards)
478	require.NotNil(t, syncBlock)
479	assert.Nil(t, syncBlock.Rollup.Vars)
480	assert.Nil(t, syncBlock.Auction.Vars)
481	assert.Nil(t, syncBlock.WDelayer.Vars)
482	assert.Equal(t, int64(2), syncBlock.Block.Num)
483	stats = s.Stats()
484	assert.Equal(t, int64(1), stats.Eth.FirstBlockNum)
485	assert.Equal(t, int64(3), stats.Eth.LastBlock.Num)
486	assert.Equal(t, int64(2), stats.Sync.LastBlock.Num)
487
488	checkSyncBlock(t, s, 2, &blocks[0], syncBlock)
489
490	// Block 3
491
492	syncBlock, discards, err = s.Sync2(ctx, nil)
493	require.Nil(t, err)
494	require.Nil(t, discards)
495	require.NotNil(t, syncBlock)
496	assert.Nil(t, syncBlock.Rollup.Vars)
497	assert.Nil(t, syncBlock.Auction.Vars)
498	assert.Nil(t, syncBlock.WDelayer.Vars)
499	assert.Equal(t, int64(3), syncBlock.Block.Num)
500	stats = s.Stats()
501	assert.Equal(t, int64(1), stats.Eth.FirstBlockNum)
502	assert.Equal(t, int64(3), stats.Eth.LastBlock.Num)
503	assert.Equal(t, int64(3), stats.Sync.LastBlock.Num)
504
505	checkSyncBlock(t, s, 3, &blocks[1], syncBlock)
506
507	// Block 4
508	// Generate 2 withdraws manually
509	_, err = client.RollupWithdrawMerkleProof(tc.Users["A"].BJJ.Public(), 1, 4, 256, big.NewInt(100), []*big.Int{}, true)
510	require.Nil(t, err)
511	_, err = client.RollupWithdrawMerkleProof(tc.Users["C"].BJJ.Public(), 1, 3, 258, big.NewInt(50), []*big.Int{}, false)
512	require.Nil(t, err)
513	client.CtlMineBlock()
514
515	syncBlock, discards, err = s.Sync2(ctx, nil)
516	require.Nil(t, err)
517	require.Nil(t, discards)
518	require.NotNil(t, syncBlock)
519	assert.Nil(t, syncBlock.Rollup.Vars)
520	assert.Nil(t, syncBlock.Auction.Vars)
521	assert.Nil(t, syncBlock.WDelayer.Vars)
522	assert.Equal(t, int64(4), syncBlock.Block.Num)
523	stats = s.Stats()
524	assert.Equal(t, int64(1), stats.Eth.FirstBlockNum)
525	assert.Equal(t, int64(4), stats.Eth.LastBlock.Num)
526	assert.Equal(t, int64(4), stats.Sync.LastBlock.Num)
527	vars.Rollup, vars.Auction, vars.WDelayer = s.SCVars()
528	assert.Equal(t, clientSetup.RollupVariables, vars.Rollup)
529	assert.Equal(t, clientSetup.AuctionVariables, vars.Auction)
530	assert.Equal(t, clientSetup.WDelayerVariables, vars.WDelayer)
531
532	dbExits, err := s.historyDB.GetAllExits()
533	require.Nil(t, err)
534	foundA1, foundC1 := false, false
535	for _, exit := range dbExits {
536		if exit.AccountIdx == 256 && exit.BatchNum == 4 {
537			foundA1 = true
538			assert.Equal(t, int64(4), *exit.InstantWithdrawn)
539		}
540		if exit.AccountIdx == 258 && exit.BatchNum == 3 {
541			foundC1 = true
542			assert.Equal(t, int64(4), *exit.DelayedWithdrawRequest)
543		}
544	}
545	assert.True(t, foundA1)
546	assert.True(t, foundC1)
547
548	// Block 5
549	// Update variables manually
550	rollupVars, auctionVars, wDelayerVars, err := s.historyDB.GetSCVars()
551	require.Nil(t, err)
552	rollupVars.ForgeL1L2BatchTimeout = 42
553	_, err = client.RollupUpdateForgeL1L2BatchTimeout(rollupVars.ForgeL1L2BatchTimeout)
554	require.Nil(t, err)
555
556	auctionVars.OpenAuctionSlots = 17
557	_, err = client.AuctionSetOpenAuctionSlots(auctionVars.OpenAuctionSlots)
558	require.Nil(t, err)
559
560	wDelayerVars.WithdrawalDelay = 99
561	_, err = client.WDelayerChangeWithdrawalDelay(wDelayerVars.WithdrawalDelay)
562	require.Nil(t, err)
563
564	client.CtlMineBlock()
565
566	syncBlock, discards, err = s.Sync2(ctx, nil)
567	require.Nil(t, err)
568	require.Nil(t, discards)
569	require.NotNil(t, syncBlock)
570	assert.NotNil(t, syncBlock.Rollup.Vars)
571	assert.NotNil(t, syncBlock.Auction.Vars)
572	assert.NotNil(t, syncBlock.WDelayer.Vars)
573	assert.Equal(t, int64(5), syncBlock.Block.Num)
574	stats = s.Stats()
575	assert.Equal(t, int64(1), stats.Eth.FirstBlockNum)
576	assert.Equal(t, int64(5), stats.Eth.LastBlock.Num)
577	assert.Equal(t, int64(5), stats.Sync.LastBlock.Num)
578	vars.Rollup, vars.Auction, vars.WDelayer = s.SCVars()
579	assert.NotEqual(t, clientSetup.RollupVariables, vars.Rollup)
580	assert.NotEqual(t, clientSetup.AuctionVariables, vars.Auction)
581	assert.NotEqual(t, clientSetup.WDelayerVariables, vars.WDelayer)
582
583	dbRollupVars, dbAuctionVars, dbWDelayerVars, err := s.historyDB.GetSCVars()
584	require.Nil(t, err)
585	// Set EthBlockNum for Vars to the blockNum in which they were updated (should be 5)
586	rollupVars.EthBlockNum = syncBlock.Block.Num
587	auctionVars.EthBlockNum = syncBlock.Block.Num
588	wDelayerVars.EthBlockNum = syncBlock.Block.Num
589	assert.Equal(t, rollupVars, dbRollupVars)
590	assert.Equal(t, auctionVars, dbAuctionVars)
591	assert.Equal(t, wDelayerVars, dbWDelayerVars)
592
593	//
594	// Reorg test
595	//
596
597	// Redo blocks 2-5 (as a reorg) only leaving:
598	// - 2 create account transactions
599	// - 2 add tokens
600	// We add a 6th block so that the synchronizer can detect the reorg
601	set2 := `
602		Type: Blockchain
603
604		AddToken(1)
605		AddToken(2)
606
607		CreateAccountDeposit(1) C: 2000 // Idx=256+1=257
608
609		CreateAccountCoordinator(1) A // Idx=256+0=256
610
611		> batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{1}
612		> batchL1 // forge defined L1UserTxs{1}, freeze L1UserTxs{nil}
613		> block // blockNum=2
614		> block // blockNum=3
615		> block // blockNum=4
616		> block // blockNum=5
617		> block // blockNum=6
618	`
619	tc = til.NewContext(common.RollupConstMaxL1UserTx)
620	tilCfgExtra = til.ConfigExtra{
621		BootCoordAddr: bootCoordAddr,
622		CoordUser:     "A",
623	}
624	blocks, err = tc.GenerateBlocks(set2)
625	require.Nil(t, err)
626
627	for i := 0; i < 4; i++ {
628		client.CtlRollback()
629	}
630	block := client.CtlLastBlock()
631	require.Equal(t, int64(1), block.Num)
632
633	// Generate extra required data
634	ethAddTokens(blocks, client)
635
636	err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
637	assert.NoError(t, err)
638	tc.FillBlocksL1UserTxsBatchNum(blocks)
639
640	// Add block data to the smart contracts
641	ethAddBlocks(t, blocks, client, clientSetup)
642
643	// First sync detects the reorg and discards 4 blocks
644	syncBlock, discards, err = s.Sync2(ctx, nil)
645	require.Nil(t, err)
646	expetedDiscards := int64(4)
647	require.Equal(t, &expetedDiscards, discards)
648	require.Nil(t, syncBlock)
649	stats = s.Stats()
650	assert.Equal(t, false, stats.Synced())
651	assert.Equal(t, int64(6), stats.Eth.LastBlock.Num)
652	vars.Rollup, vars.Auction, vars.WDelayer = s.SCVars()
653	assert.Equal(t, clientSetup.RollupVariables, vars.Rollup)
654	assert.Equal(t, clientSetup.AuctionVariables, vars.Auction)
655	assert.Equal(t, clientSetup.WDelayerVariables, vars.WDelayer)
656
657	// At this point, the DB only has data up to block 1
658	dbBlock, err := s.historyDB.GetLastBlock()
659	require.Nil(t, err)
660	assert.Equal(t, int64(1), dbBlock.Num)
661
662	// Accounts in HistoryDB and StateDB must be empty
663	dbAccounts, err := s.historyDB.GetAllAccounts()
664	require.Nil(t, err)
665	sdbAccounts, err := s.stateDB.GetAccounts()
666	require.Nil(t, err)
667	assert.Equal(t, 0, len(dbAccounts))
668	assertEqualAccountsHistoryDBStateDB(t, dbAccounts, sdbAccounts)
669
670	// Sync blocks 2-6
671	for i := 0; i < 5; i++ {
672		syncBlock, discards, err = s.Sync2(ctx, nil)
673		require.Nil(t, err)
674		require.Nil(t, discards)
675		require.NotNil(t, syncBlock)
676		assert.Nil(t, syncBlock.Rollup.Vars)
677		assert.Nil(t, syncBlock.Auction.Vars)
678		assert.Nil(t, syncBlock.WDelayer.Vars)
679		assert.Equal(t, int64(2+i), syncBlock.Block.Num)
680
681		stats = s.Stats()
682		assert.Equal(t, int64(1), stats.Eth.FirstBlockNum)
683		assert.Equal(t, int64(6), stats.Eth.LastBlock.Num)
684		assert.Equal(t, int64(2+i), stats.Sync.LastBlock.Num)
685		if i == 4 {
686			assert.Equal(t, true, stats.Synced())
687		} else {
688			assert.Equal(t, false, stats.Synced())
689		}
690
691		vars.Rollup, vars.Auction, vars.WDelayer = s.SCVars()
692		assert.Equal(t, clientSetup.RollupVariables, vars.Rollup)
693		assert.Equal(t, clientSetup.AuctionVariables, vars.Auction)
694		assert.Equal(t, clientSetup.WDelayerVariables, vars.WDelayer)
695	}
696
697	dbBlock, err = s.historyDB.GetLastBlock()
698	require.Nil(t, err)
699	assert.Equal(t, int64(6), dbBlock.Num)
700
701	// Accounts in HistoryDB and StateDB is only 2 entries
702	dbAccounts, err = s.historyDB.GetAllAccounts()
703	require.Nil(t, err)
704	sdbAccounts, err = s.stateDB.GetAccounts()
705	require.Nil(t, err)
706	assert.Equal(t, 2, len(dbAccounts))
707	assertEqualAccountsHistoryDBStateDB(t, dbAccounts, sdbAccounts)
708}