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].EthBlockNum)
 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.EthBlockNum, 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
325	// Test Sync for rollup genesis block
326	syncBlock, discards, err := s.Sync2(ctx, nil)
327	require.Nil(t, err)
328	require.Nil(t, discards)
329	require.NotNil(t, syncBlock)
330	assert.Equal(t, int64(1), syncBlock.Block.EthBlockNum)
331	dbBlocks, err := s.historyDB.GetAllBlocks()
332	require.Nil(t, err)
333	assert.Equal(t, 2, len(dbBlocks))
334	assert.Equal(t, int64(1), dbBlocks[1].EthBlockNum)
335
336	// Sync again and expect no new blocks
337	syncBlock, discards, err = s.Sync2(ctx, nil)
338	require.Nil(t, err)
339	require.Nil(t, discards)
340	require.Nil(t, syncBlock)
341
342	//
343	// Generate blockchain and smart contract data, and fill the test smart contracts
344	//
345
346	// Generate blockchain data with til
347	set1 := `
348		Type: Blockchain
349
350		AddToken(1)
351		AddToken(2)
352		AddToken(3)
353
354		CreateAccountDeposit(1) C: 2000 // Idx=256+2=258
355		CreateAccountDeposit(2) A: 2000 // Idx=256+3=259
356		CreateAccountDeposit(1) D: 500  // Idx=256+4=260
357		CreateAccountDeposit(2) B: 500  // Idx=256+5=261
358		CreateAccountDeposit(2) C: 500  // Idx=256+6=262
359
360		CreateAccountCoordinator(1) A // Idx=256+0=256
361		CreateAccountCoordinator(1) B // Idx=256+1=257
362
363		> batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{5}
364		> batchL1 // forge defined L1UserTxs{5}, freeze L1UserTxs{nil}
365		> block // blockNum=2
366
367		CreateAccountDepositTransfer(1) E-A: 1000, 200 // Idx=256+7=263
368		ForceExit(1) A: 100
369		ForceExit(1) B: 80
370		ForceTransfer(1) A-D: 100
371
372		Transfer(1) C-A: 100 (200)
373		Exit(1) C: 50 (200)
374		Exit(1) D: 30 (200)
375
376		> batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{3}
377		> batchL1 // forge L1UserTxs{3}, freeze defined L1UserTxs{nil}
378		> block // blockNum=3
379	`
380	tc := til.NewContext(common.RollupConstMaxL1UserTx)
381	tilCfgExtra := til.ConfigExtra{
382		BootCoordAddr: bootCoordAddr,
383		CoordUser:     "A",
384	}
385	blocks, err := tc.GenerateBlocks(set1)
386	require.Nil(t, err)
387	// Sanity check
388	require.Equal(t, 2, len(blocks))
389	// blocks 0 (blockNum=2)
390	i := 0
391	require.Equal(t, 2, int(blocks[i].Block.EthBlockNum))
392	require.Equal(t, 3, len(blocks[i].Rollup.AddedTokens))
393	require.Equal(t, 5, len(blocks[i].Rollup.L1UserTxs))
394	require.Equal(t, 2, len(blocks[i].Rollup.Batches))
395	require.Equal(t, 2, len(blocks[i].Rollup.Batches[0].L1CoordinatorTxs))
396	// blocks 1 (blockNum=3)
397	i = 1
398	require.Equal(t, 3, int(blocks[i].Block.EthBlockNum))
399	require.Equal(t, 4, len(blocks[i].Rollup.L1UserTxs))
400	require.Equal(t, 2, len(blocks[i].Rollup.Batches))
401	require.Equal(t, 3, len(blocks[i].Rollup.Batches[0].L2Txs))
402
403	// Generate extra required data
404	ethAddTokens(blocks, client)
405
406	err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
407	assert.Nil(t, err)
408	tc.FillBlocksL1UserTxsBatchNum(blocks)
409
410	// Add block data to the smart contracts
411	ethAddBlocks(t, blocks, client, clientSetup)
412
413	//
414	// Sync to synchronize the current state from the test smart contracts,
415	// and check the outcome
416	//
417
418	// Block 2
419
420	syncBlock, discards, err = s.Sync2(ctx, nil)
421	require.Nil(t, err)
422	require.Nil(t, discards)
423	require.NotNil(t, syncBlock)
424	assert.Equal(t, int64(2), syncBlock.Block.EthBlockNum)
425
426	checkSyncBlock(t, s, 2, &blocks[0], syncBlock)
427
428	// Block 3
429
430	syncBlock, discards, err = s.Sync2(ctx, nil)
431	require.Nil(t, err)
432	require.Nil(t, discards)
433	require.NotNil(t, syncBlock)
434	assert.Equal(t, int64(3), syncBlock.Block.EthBlockNum)
435
436	checkSyncBlock(t, s, 3, &blocks[1], syncBlock)
437
438	// Block 4
439	// Generate 2 withdraws manually
440	_, err = client.RollupWithdrawMerkleProof(tc.Users["A"].BJJ.Public(), 1, 4, 256, big.NewInt(100), []*big.Int{}, true)
441	require.Nil(t, err)
442	_, err = client.RollupWithdrawMerkleProof(tc.Users["C"].BJJ.Public(), 1, 3, 258, big.NewInt(50), []*big.Int{}, false)
443	require.Nil(t, err)
444	client.CtlMineBlock()
445
446	syncBlock, discards, err = s.Sync2(ctx, nil)
447	require.Nil(t, err)
448	require.Nil(t, discards)
449	require.NotNil(t, syncBlock)
450	assert.Equal(t, int64(4), syncBlock.Block.EthBlockNum)
451	dbExits, err := s.historyDB.GetAllExits()
452	require.Nil(t, err)
453	foundA1, foundC1 := false, false
454	for _, exit := range dbExits {
455		if exit.AccountIdx == 256 && exit.BatchNum == 4 {
456			foundA1 = true
457			assert.Equal(t, int64(4), *exit.InstantWithdrawn)
458		}
459		if exit.AccountIdx == 258 && exit.BatchNum == 3 {
460			foundC1 = true
461			assert.Equal(t, int64(4), *exit.DelayedWithdrawRequest)
462		}
463	}
464	assert.True(t, foundA1)
465	assert.True(t, foundC1)
466
467	// Block 5
468	// Update variables manually
469	rollupVars, auctionVars, wDelayerVars, err := s.historyDB.GetSCVars()
470	require.Nil(t, err)
471	rollupVars.ForgeL1L2BatchTimeout = 42
472	_, err = client.RollupUpdateForgeL1L2BatchTimeout(rollupVars.ForgeL1L2BatchTimeout)
473	require.Nil(t, err)
474
475	auctionVars.OpenAuctionSlots = 17
476	_, err = client.AuctionSetOpenAuctionSlots(auctionVars.OpenAuctionSlots)
477	require.Nil(t, err)
478
479	wDelayerVars.WithdrawalDelay = 99
480	_, err = client.WDelayerChangeWithdrawalDelay(wDelayerVars.WithdrawalDelay)
481	require.Nil(t, err)
482
483	client.CtlMineBlock()
484
485	syncBlock, discards, err = s.Sync2(ctx, nil)
486	require.Nil(t, err)
487	require.Nil(t, discards)
488	require.NotNil(t, syncBlock)
489	assert.Equal(t, int64(5), syncBlock.Block.EthBlockNum)
490
491	dbRollupVars, dbAuctionVars, dbWDelayerVars, err := s.historyDB.GetSCVars()
492	require.Nil(t, err)
493	// Set EthBlockNum for Vars to the blockNum in which they were updated (should be 5)
494	rollupVars.EthBlockNum = syncBlock.Block.EthBlockNum
495	auctionVars.EthBlockNum = syncBlock.Block.EthBlockNum
496	wDelayerVars.EthBlockNum = syncBlock.Block.EthBlockNum
497	assert.Equal(t, rollupVars, dbRollupVars)
498	assert.Equal(t, auctionVars, dbAuctionVars)
499	assert.Equal(t, wDelayerVars, dbWDelayerVars)
500
501	//
502	// Reorg test
503	//
504
505	// Redo blocks 2-5 (as a reorg) only leaving:
506	// - 2 create account transactions
507	// - 2 add tokens
508	// We add a 6th block so that the synchronizer can detect the reorg
509	set2 := `
510		Type: Blockchain
511
512		AddToken(1)
513		AddToken(2)
514
515		CreateAccountDeposit(1) C: 2000 // Idx=256+1=257
516
517		CreateAccountCoordinator(1) A // Idx=256+0=256
518
519		> batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{1}
520		> batchL1 // forge defined L1UserTxs{1}, freeze L1UserTxs{nil}
521		> block // blockNum=2
522		> block // blockNum=3
523		> block // blockNum=4
524		> block // blockNum=5
525		> block // blockNum=6
526	`
527	tc = til.NewContext(common.RollupConstMaxL1UserTx)
528	tilCfgExtra = til.ConfigExtra{
529		BootCoordAddr: bootCoordAddr,
530		CoordUser:     "A",
531	}
532	blocks, err = tc.GenerateBlocks(set2)
533	require.Nil(t, err)
534
535	for i := 0; i < 4; i++ {
536		client.CtlRollback()
537	}
538	blockNum := client.CtlLastBlock()
539	require.Equal(t, int64(1), blockNum)
540
541	// Generate extra required data
542	ethAddTokens(blocks, client)
543
544	err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
545	assert.Nil(t, err)
546	tc.FillBlocksL1UserTxsBatchNum(blocks)
547
548	// Add block data to the smart contracts
549	ethAddBlocks(t, blocks, client, clientSetup)
550
551	// First sync detects the reorg and discards 4 blocks
552	syncBlock, discards, err = s.Sync2(ctx, nil)
553	require.Nil(t, err)
554	expetedDiscards := int64(4)
555	require.Equal(t, &expetedDiscards, discards)
556	require.Nil(t, syncBlock)
557
558	// At this point, the DB only has data up to block 1
559	dbBlock, err := s.historyDB.GetLastBlock()
560	require.Nil(t, err)
561	assert.Equal(t, int64(1), dbBlock.EthBlockNum)
562
563	// Accounts in HistoryDB and StateDB must be empty
564	dbAccounts, err := s.historyDB.GetAllAccounts()
565	require.Nil(t, err)
566	sdbAccounts, err := s.stateDB.GetAccounts()
567	require.Nil(t, err)
568	assert.Equal(t, 0, len(dbAccounts))
569	assertEqualAccountsHistoryDBStateDB(t, dbAccounts, sdbAccounts)
570
571	// Sync blocks 2-6
572	for i := 0; i < 5; i++ {
573		syncBlock, discards, err = s.Sync2(ctx, nil)
574		require.Nil(t, err)
575		require.Nil(t, discards)
576		require.NotNil(t, syncBlock)
577		assert.Equal(t, int64(2+i), syncBlock.Block.EthBlockNum)
578	}
579
580	dbBlock, err = s.historyDB.GetLastBlock()
581	require.Nil(t, err)
582	assert.Equal(t, int64(6), dbBlock.EthBlockNum)
583
584	// Accounts in HistoryDB and StateDB is only 2 entries
585	dbAccounts, err = s.historyDB.GetAllAccounts()
586	require.Nil(t, err)
587	sdbAccounts, err = s.stateDB.GetAccounts()
588	require.Nil(t, err)
589	assert.Equal(t, 2, len(dbAccounts))
590	assertEqualAccountsHistoryDBStateDB(t, dbAccounts, sdbAccounts)
591}