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