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