arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/db/historydb/historydb_test.go
db/historydb/historydb_test.goRaw
  1package historydb
  2
  3import (
  4	"database/sql"
  5	"math"
  6	"math/big"
  7	"os"
  8	"testing"
  9	"time"
 10
 11	ethCommon "github.com/ethereum/go-ethereum/common"
 12	"github.com/hermeznetwork/hermez-node/common"
 13	dbUtils "github.com/hermeznetwork/hermez-node/db"
 14	"github.com/hermeznetwork/hermez-node/log"
 15	"github.com/hermeznetwork/hermez-node/test"
 16	"github.com/hermeznetwork/hermez-node/test/til"
 17	"github.com/stretchr/testify/assert"
 18	"github.com/stretchr/testify/require"
 19)
 20
 21var historyDB *HistoryDB
 22
 23// In order to run the test you need to run a Posgres DB with
 24// a database named "history" that is accessible by
 25// user: "hermez"
 26// pass: set it using the env var POSTGRES_PASS
 27// This can be achieved by running: POSTGRES_PASS=your_strong_pass && sudo docker run --rm --name hermez-db-test -p 5432:5432 -e POSTGRES_DB=history -e POSTGRES_USER=hermez -e POSTGRES_PASSWORD=$POSTGRES_PASS -d postgres && sleep 2s && sudo docker exec -it hermez-db-test psql -a history -U hermez -c "CREATE DATABASE l2;"
 28// After running the test you can stop the container by running: sudo docker kill hermez-db-test
 29// If you already did that for the L2DB you don't have to do it again
 30
 31func TestMain(m *testing.M) {
 32	// init DB
 33	pass := os.Getenv("POSTGRES_PASS")
 34	db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
 35	if err != nil {
 36		panic(err)
 37	}
 38	historyDB = NewHistoryDB(db)
 39	if err != nil {
 40		panic(err)
 41	}
 42	// Run tests
 43	result := m.Run()
 44	// Close DB
 45	if err := db.Close(); err != nil {
 46		log.Error("Error closing the history DB:", err)
 47	}
 48	os.Exit(result)
 49}
 50
 51func TestBlocks(t *testing.T) {
 52	var fromBlock, toBlock int64
 53	fromBlock = 1
 54	toBlock = 5
 55	// Delete peviously created rows (clean previous test execs)
 56	test.WipeDB(historyDB.DB())
 57	// Generate fake blocks
 58	blocks := test.GenBlocks(fromBlock, toBlock)
 59	// Save timestamp of a block with UTC and change it without UTC
 60	timestamp := time.Now().Add(time.Second * 13)
 61	blocks[fromBlock].Timestamp = timestamp
 62	// Insert blocks into DB
 63	for i := 0; i < len(blocks); i++ {
 64		err := historyDB.AddBlock(&blocks[i])
 65		assert.NoError(t, err)
 66	}
 67	// Get all blocks from DB
 68	fetchedBlocks, err := historyDB.GetBlocks(fromBlock, toBlock)
 69	assert.Equal(t, len(blocks), len(fetchedBlocks))
 70	// Compare generated vs getted blocks
 71	assert.NoError(t, err)
 72	for i := range fetchedBlocks {
 73		assertEqualBlock(t, &blocks[i], &fetchedBlocks[i])
 74	}
 75	// Compare saved timestamp vs getted
 76	nameZoneUTC, offsetUTC := timestamp.UTC().Zone()
 77	zoneFetchedBlock, offsetFetchedBlock := fetchedBlocks[fromBlock].Timestamp.Zone()
 78	assert.Equal(t, nameZoneUTC, zoneFetchedBlock)
 79	assert.Equal(t, offsetUTC, offsetFetchedBlock)
 80	// Get blocks from the DB one by one
 81	for i := fromBlock; i < toBlock; i++ {
 82		fetchedBlock, err := historyDB.GetBlock(i)
 83		assert.NoError(t, err)
 84		assertEqualBlock(t, &blocks[i-1], fetchedBlock)
 85	}
 86	// Get last block
 87	lastBlock, err := historyDB.GetLastBlock()
 88	assert.NoError(t, err)
 89	assertEqualBlock(t, &blocks[len(blocks)-1], lastBlock)
 90}
 91
 92func assertEqualBlock(t *testing.T, expected *common.Block, actual *common.Block) {
 93	assert.Equal(t, expected.EthBlockNum, actual.EthBlockNum)
 94	assert.Equal(t, expected.Hash, actual.Hash)
 95	assert.Equal(t, expected.Timestamp.Unix(), actual.Timestamp.Unix())
 96}
 97
 98func TestBatches(t *testing.T) {
 99	const fromBlock int64 = 1
100	const toBlock int64 = 3
101	// Prepare blocks in the DB
102	blocks := setTestBlocks(fromBlock, toBlock)
103	// Generate fake batches
104	const nBatches = 9
105	batches := test.GenBatches(nBatches, blocks)
106	// Test GetLastL1TxsNum with no batches
107	fetchedLastL1TxsNum, err := historyDB.GetLastL1TxsNum()
108	assert.NoError(t, err)
109	assert.Nil(t, fetchedLastL1TxsNum)
110	// Add batches to the DB
111	err = historyDB.AddBatches(batches)
112	assert.NoError(t, err)
113	// Get batches from the DB
114	fetchedBatches, err := historyDB.GetBatches(0, common.BatchNum(nBatches))
115	assert.NoError(t, err)
116	for i, fetchedBatch := range fetchedBatches {
117		assert.Equal(t, batches[i], fetchedBatch)
118	}
119	// Test GetLastBatchNum
120	fetchedLastBatchNum, err := historyDB.GetLastBatchNum()
121	assert.NoError(t, err)
122	assert.Equal(t, batches[len(batches)-1].BatchNum, fetchedLastBatchNum)
123	// Test GetLastL1TxsNum
124	fetchedLastL1TxsNum, err = historyDB.GetLastL1TxsNum()
125	assert.NoError(t, err)
126	assert.Equal(t, *batches[nBatches-1].ForgeL1TxsNum, *fetchedLastL1TxsNum)
127	// Test total fee
128	// Generate fake tokens
129	const nTokens = 5
130	tokens, ethToken := test.GenTokens(nTokens, blocks)
131	err = historyDB.AddTokens(tokens)
132	assert.NoError(t, err)
133	tokens = append([]common.Token{ethToken}, tokens...)
134	feeBatch := batches[0]
135	feeBatch.BatchNum = 9999
136	feeBatch.CollectedFees = make(map[common.TokenID]*big.Int)
137	var total float64
138	for i, token := range tokens {
139		value := 3.019237 * float64(i)
140		assert.NoError(t, historyDB.UpdateTokenValue(token.Symbol, value))
141		bigAmount := big.NewInt(345000000)
142		feeBatch.CollectedFees[token.TokenID] = bigAmount
143		f := new(big.Float).SetInt(bigAmount)
144		amount, _ := f.Float64()
145		total += value * (amount / math.Pow(10, float64(token.Decimals)))
146	}
147	err = historyDB.AddBatch(&feeBatch)
148	assert.NoError(t, err)
149	fetchedBatches, err = historyDB.GetBatches(feeBatch.BatchNum-1, feeBatch.BatchNum+1)
150	assert.NoError(t, err)
151	for _, fetchedBatch := range fetchedBatches {
152		if fetchedBatch.BatchNum == feeBatch.BatchNum {
153			assert.Equal(t, total, *fetchedBatch.TotalFeesUSD)
154		}
155	}
156}
157
158func TestBids(t *testing.T) {
159	const fromBlock int64 = 1
160	const toBlock int64 = 5
161	// Prepare blocks in the DB
162	blocks := setTestBlocks(fromBlock, toBlock)
163	// Generate fake coordinators
164	const nCoords = 5
165	coords := test.GenCoordinators(nCoords, blocks)
166	err := historyDB.AddCoordinators(coords)
167	assert.NoError(t, err)
168	// Generate fake bids
169	const nBids = 20
170	bids := test.GenBids(nBids, blocks, coords)
171	err = historyDB.AddBids(bids)
172	assert.NoError(t, err)
173	// Fetch bids
174	fetchedBids, err := historyDB.GetAllBids()
175	assert.NoError(t, err)
176	// Compare fetched bids vs generated bids
177	for i, bid := range fetchedBids {
178		assert.Equal(t, bids[i], bid)
179	}
180}
181
182func TestTokens(t *testing.T) {
183	const fromBlock int64 = 1
184	const toBlock int64 = 5
185	// Prepare blocks in the DB
186	blocks := setTestBlocks(fromBlock, toBlock)
187	// Generate fake tokens
188	const nTokens = 5
189	tokens, ethToken := test.GenTokens(nTokens, blocks)
190	err := historyDB.AddTokens(tokens)
191	assert.NoError(t, err)
192	tokens = append([]common.Token{ethToken}, tokens...)
193	limit := uint(10)
194	// Fetch tokens
195	fetchedTokens, _, err := historyDB.GetTokens(nil, nil, "", nil, &limit, OrderAsc)
196	assert.NoError(t, err)
197	// Compare fetched tokens vs generated tokens
198	// All the tokens should have USDUpdate setted by the DB trigger
199	for i, token := range fetchedTokens {
200		assert.Equal(t, tokens[i].TokenID, token.TokenID)
201		assert.Equal(t, tokens[i].EthBlockNum, token.EthBlockNum)
202		assert.Equal(t, tokens[i].EthAddr, token.EthAddr)
203		assert.Equal(t, tokens[i].Name, token.Name)
204		assert.Equal(t, tokens[i].Symbol, token.Symbol)
205		assert.Nil(t, token.USD)
206		assert.Nil(t, token.USDUpdate)
207	}
208
209	// Update token value
210	for i, token := range tokens {
211		value := 1.01 * float64(i)
212		assert.NoError(t, historyDB.UpdateTokenValue(token.Symbol, value))
213	}
214	// Fetch tokens
215	fetchedTokens, _, err = historyDB.GetTokens(nil, nil, "", nil, &limit, OrderAsc)
216	assert.NoError(t, err)
217	// Compare fetched tokens vs generated tokens
218	// All the tokens should have USDUpdate setted by the DB trigger
219	for i, token := range fetchedTokens {
220		value := 1.01 * float64(i)
221		assert.Equal(t, value, *token.USD)
222		nameZone, offset := token.USDUpdate.Zone()
223		assert.Equal(t, "UTC", nameZone)
224		assert.Equal(t, 0, offset)
225	}
226}
227
228func TestAccounts(t *testing.T) {
229	const fromBlock int64 = 1
230	const toBlock int64 = 5
231	// Prepare blocks in the DB
232	blocks := setTestBlocks(fromBlock, toBlock)
233	// Generate fake tokens
234	const nTokens = 5
235	tokens, ethToken := test.GenTokens(nTokens, blocks)
236	err := historyDB.AddTokens(tokens)
237	assert.NoError(t, err)
238	tokens = append([]common.Token{ethToken}, tokens...)
239	// Generate fake batches
240	const nBatches = 10
241	batches := test.GenBatches(nBatches, blocks)
242	err = historyDB.AddBatches(batches)
243	assert.NoError(t, err)
244	// Generate fake accounts
245	const nAccounts = 3
246	accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
247	err = historyDB.AddAccounts(accs)
248	assert.NoError(t, err)
249	// Fetch accounts
250	fetchedAccs, err := historyDB.GetAccounts()
251	assert.NoError(t, err)
252	// Compare fetched accounts vs generated accounts
253	for i, acc := range fetchedAccs {
254		accs[i].Balance = nil
255		assert.Equal(t, accs[i], acc)
256	}
257}
258
259func TestTxs(t *testing.T) {
260	const fromBlock int64 = 1
261	const toBlock int64 = 5
262	// Prepare blocks in the DB
263	blocks := setTestBlocks(fromBlock, toBlock)
264	// Generate fake tokens
265	const nTokens = 500
266	tokens, ethToken := test.GenTokens(nTokens, blocks)
267	err := historyDB.AddTokens(tokens)
268	assert.NoError(t, err)
269	tokens = append([]common.Token{ethToken}, tokens...)
270	// Generate fake batches
271	const nBatches = 10
272	batches := test.GenBatches(nBatches, blocks)
273	err = historyDB.AddBatches(batches)
274	assert.NoError(t, err)
275	// Generate fake accounts
276	const nAccounts = 3
277	accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
278	err = historyDB.AddAccounts(accs)
279	assert.NoError(t, err)
280
281	/*
282		Uncomment once the transaction generation is fixed
283		!! test that batches that forge user L1s !!
284		!! Missing tests to check that historic USD is not set if USDUpdate is too old (24h) !!
285
286		// Generate fake L1 txs
287		const nL1s = 64
288		_, l1txs := test.GenL1Txs(256, nL1s, 0, nil, accs, tokens, blocks, batches)
289		err = historyDB.AddL1Txs(l1txs)
290		assert.NoError(t, err)
291		// Generate fake L2 txs
292		const nL2s = 2048 - nL1s
293		_, l2txs := test.GenL2Txs(256, nL2s, 0, nil, accs, tokens, blocks, batches)
294		err = historyDB.AddL2Txs(l2txs)
295		assert.NoError(t, err)
296		// Compare fetched txs vs generated txs.
297		fetchAndAssertTxs(t, l1txs, l2txs)
298		// Test trigger: L1 integrity
299		// from_eth_addr can't be null
300		l1txs[0].FromEthAddr = ethCommon.Address{}
301		err = historyDB.AddL1Txs(l1txs)
302		assert.Error(t, err)
303		l1txs[0].FromEthAddr = ethCommon.BigToAddress(big.NewInt(int64(5)))
304		// from_bjj can't be null
305		l1txs[0].FromBJJ = nil
306		err = historyDB.AddL1Txs(l1txs)
307		assert.Error(t, err)
308		privK := babyjub.NewRandPrivKey()
309		l1txs[0].FromBJJ = privK.Public()
310		// load_amount can't be null
311		l1txs[0].LoadAmount = nil
312		err = historyDB.AddL1Txs(l1txs)
313		assert.Error(t, err)
314		// Test trigger: L2 integrity
315		// batch_num can't be null
316		l2txs[0].BatchNum = 0
317		err = historyDB.AddL2Txs(l2txs)
318		assert.Error(t, err)
319		l2txs[0].BatchNum = 1
320		// nonce can't be null
321		l2txs[0].Nonce = 0
322		err = historyDB.AddL2Txs(l2txs)
323		assert.Error(t, err)
324		// Test trigger: forge L1 txs
325		// add next batch to DB
326		batchNum, toForgeL1TxsNum := test.GetNextToForgeNumAndBatch(batches)
327		batch := batches[0]
328		batch.BatchNum = batchNum
329		batch.ForgeL1TxsNum = toForgeL1TxsNum
330		assert.NoError(t, historyDB.AddBatch(&batch)) // This should update nL1s / 2 rows
331		// Set batch num in txs that should have been marked as forged in the DB
332		for i := 0; i < len(l1txs); i++ {
333			fetchedTx, err := historyDB.GetTx(l1txs[i].TxID)
334			assert.NoError(t, err)
335			if l1txs[i].ToForgeL1TxsNum == toForgeL1TxsNum {
336				assert.Equal(t, batchNum, *fetchedTx.BatchNum)
337			} else {
338				if fetchedTx.BatchNum != nil {
339					assert.NotEqual(t, batchNum, *fetchedTx.BatchNum)
340				}
341			}
342		}
343
344		// Test helper functions for Synchronizer
345		// GetLastTxsPosition
346		expectedPosition := -1
347		var choosenToForgeL1TxsNum int64 = -1
348		for _, tx := range l1txs {
349			if choosenToForgeL1TxsNum == -1 && tx.ToForgeL1TxsNum > 0 {
350				choosenToForgeL1TxsNum = tx.ToForgeL1TxsNum
351				expectedPosition = tx.Position
352			} else if choosenToForgeL1TxsNum == tx.ToForgeL1TxsNum && expectedPosition < tx.Position {
353				expectedPosition = tx.Position
354			}
355		}
356		position, err := historyDB.GetLastTxsPosition(choosenToForgeL1TxsNum)
357		assert.NoError(t, err)
358		assert.Equal(t, expectedPosition, position)
359
360		// GetL1UserTxs: not needed? tests were broken
361		// txs, err := historyDB.GetL1UserTxs(2)
362		// assert.NoError(t, err)
363		// assert.NotZero(t, len(txs))
364		// assert.NoError(t, err)
365		// assert.Equal(t, 22, position)
366		// // Test Update L1 TX Batch_num
367		// assert.Equal(t, common.BatchNum(0), txs[0].BatchNum)
368		// txs[0].BatchNum = common.BatchNum(1)
369		// txs, err = historyDB.GetL1UserTxs(2)
370		// assert.NoError(t, err)
371		// assert.NotZero(t, len(txs))
372		// assert.Equal(t, common.BatchNum(1), txs[0].BatchNum)
373	*/
374}
375
376/*
377func fetchAndAssertTxs(t *testing.T, l1txs []common.L1Tx, l2txs []common.L2Tx) {
378	for i := 0; i < len(l1txs); i++ {
379		tx := l1txs[i].Tx()
380		fmt.Println("ASDF", i, tx.TxID)
381		fetchedTx, err := historyDB.GetTx(tx.TxID)
382		require.NoError(t, err)
383		test.AssertUSD(t, tx.USD, fetchedTx.USD)
384		test.AssertUSD(t, tx.LoadAmountUSD, fetchedTx.LoadAmountUSD)
385		assert.Equal(t, tx, fetchedTx)
386	}
387	for i := 0; i < len(l2txs); i++ {
388		tx := l2txs[i].Tx()
389		fetchedTx, err := historyDB.GetTx(tx.TxID)
390		tx.TokenID = fetchedTx.TokenID
391		assert.NoError(t, err)
392		test.AssertUSD(t, fetchedTx.USD, tx.USD)
393		test.AssertUSD(t, fetchedTx.FeeUSD, tx.FeeUSD)
394		assert.Equal(t, tx, fetchedTx)
395	}
396}
397*/
398
399func TestExitTree(t *testing.T) {
400	nBatches := 17
401	blocks := setTestBlocks(1, 10)
402	batches := test.GenBatches(nBatches, blocks)
403	err := historyDB.AddBatches(batches)
404	assert.NoError(t, err)
405	const nTokens = 50
406	tokens, ethToken := test.GenTokens(nTokens, blocks)
407	err = historyDB.AddTokens(tokens)
408	assert.NoError(t, err)
409	tokens = append([]common.Token{ethToken}, tokens...)
410	const nAccounts = 3
411	accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
412	assert.NoError(t, historyDB.AddAccounts(accs))
413	exitTree := test.GenExitTree(nBatches, batches, accs)
414	err = historyDB.AddExitTree(exitTree)
415	assert.NoError(t, err)
416}
417
418func TestGetL1UserTxs(t *testing.T) {
419	test.WipeDB(historyDB.DB())
420
421	set := `
422		Type: Blockchain
423		AddToken(1)
424		AddToken(2)
425		AddToken(3)
426
427		CreateAccountDeposit(1) A: 20
428		CreateAccountDeposit(2) A: 20
429		CreateAccountDeposit(1) B: 5
430		CreateAccountDeposit(1) C: 5
431		CreateAccountDeposit(1) D: 5
432
433		> block
434	`
435	tc := til.NewContext(128)
436	blocks, err := tc.GenerateBlocks(set)
437	require.Nil(t, err)
438	// Sanity check
439	require.Equal(t, 1, len(blocks))
440	require.Equal(t, 5, len(blocks[0].Rollup.L1UserTxs))
441	// fmt.Printf("DBG Blocks: %+v\n", blocks)
442
443	toForgeL1TxsNum := int64(1)
444
445	for i := range blocks {
446		err = historyDB.AddBlockSCData(&blocks[i])
447		require.Nil(t, err)
448	}
449
450	l1UserTxs, err := historyDB.GetL1UserTxs(toForgeL1TxsNum)
451	require.Nil(t, err)
452	assert.Equal(t, 5, len(l1UserTxs))
453	assert.Equal(t, blocks[0].Rollup.L1UserTxs, l1UserTxs)
454
455	// No l1UserTxs for this toForgeL1TxsNum
456	l1UserTxs, err = historyDB.GetL1UserTxs(2)
457	require.Nil(t, err)
458	assert.Equal(t, 0, len(l1UserTxs))
459}
460
461func TestSetInitialSCVars(t *testing.T) {
462	test.WipeDB(historyDB.DB())
463	_, _, _, err := historyDB.GetSCVars()
464	assert.Equal(t, sql.ErrNoRows, err)
465
466	//nolint:govet
467	rollup := &common.RollupVariables{
468		0,
469		big.NewInt(10),
470		12,
471		13,
472	}
473	//nolint:govet
474	auction := &common.AuctionVariables{
475		0,
476		ethCommon.BigToAddress(big.NewInt(2)),
477		ethCommon.BigToAddress(big.NewInt(3)),
478		[6]*big.Int{
479			big.NewInt(1), big.NewInt(2), big.NewInt(3),
480			big.NewInt(4), big.NewInt(5), big.NewInt(6),
481		},
482		2,
483		4320,
484		[3]uint16{10, 11, 12},
485		1000,
486		20,
487	}
488	//nolint:govet
489	wDelayer := &common.WDelayerVariables{
490		0,
491		ethCommon.BigToAddress(big.NewInt(2)),
492		ethCommon.BigToAddress(big.NewInt(3)),
493		ethCommon.BigToAddress(big.NewInt(4)),
494		13,
495		14,
496		false,
497	}
498	err = historyDB.SetInitialSCVars(rollup, auction, wDelayer)
499	require.Nil(t, err)
500	dbRollup, dbAuction, dbWDelayer, err := historyDB.GetSCVars()
501	assert.Nil(t, err)
502	require.Equal(t, rollup, dbRollup)
503	require.Equal(t, auction, dbAuction)
504	require.Equal(t, wDelayer, dbWDelayer)
505}
506
507func TestUpdateExitTree(t *testing.T) {
508	test.WipeDB(historyDB.DB())
509
510	set := `
511		Type: Blockchain
512
513		AddToken(1)
514
515		CreateAccountDeposit(1) C: 2000 // Idx=256+2=258
516		CreateAccountDeposit(1) D: 500  // Idx=256+3=259
517
518		CreateAccountCoordinator(1) A // Idx=256+0=256
519		CreateAccountCoordinator(1) B // Idx=256+1=257
520
521		> batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{5}
522		> batchL1 // forge defined L1UserTxs{5}, freeze L1UserTxs{nil}
523		> block // blockNum=2
524
525		ForceExit(1) A: 100
526		ForceExit(1) B: 80
527
528		Exit(1) C: 50 (200)
529		Exit(1) D: 30 (200)
530
531		> batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{3}
532		> batchL1 // forge L1UserTxs{3}, freeze defined L1UserTxs{nil}
533		> block // blockNum=3
534
535		> block // blockNum=4 (empty block)
536	`
537
538	tc := til.NewContext(common.RollupConstMaxL1UserTx)
539	tilCfgExtra := til.ConfigExtra{
540		BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
541		CoordUser:     "A",
542	}
543	blocks, err := tc.GenerateBlocks(set)
544	require.Nil(t, err)
545	err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
546	assert.Nil(t, err)
547
548	// Add all blocks except for the last one
549	for i := range blocks[:len(blocks)-1] {
550		err = historyDB.AddBlockSCData(&blocks[i])
551		require.Nil(t, err)
552	}
553
554	// Add withdraws to the last block, and insert block into the DB
555	block := &blocks[len(blocks)-1]
556	require.Equal(t, int64(4), block.Block.EthBlockNum)
557	block.Rollup.Withdrawals = append(block.Rollup.Withdrawals,
558		common.WithdrawInfo{Idx: 256, NumExitRoot: 4, InstantWithdraw: true},
559		common.WithdrawInfo{Idx: 257, NumExitRoot: 4, InstantWithdraw: false},
560		common.WithdrawInfo{Idx: 258, NumExitRoot: 3, InstantWithdraw: true},
561		common.WithdrawInfo{Idx: 259, NumExitRoot: 3, InstantWithdraw: false},
562	)
563	err = historyDB.addBlock(historyDB.db, &block.Block)
564	require.Nil(t, err)
565
566	// update exit trees in DB
567	instantWithdrawn := []exitID{}
568	delayedWithdrawRequest := []exitID{}
569	for _, withdraw := range block.Rollup.Withdrawals {
570		exitID := exitID{
571			batchNum: int64(withdraw.NumExitRoot),
572			idx:      int64(withdraw.Idx),
573		}
574		if withdraw.InstantWithdraw {
575			instantWithdrawn = append(instantWithdrawn, exitID)
576		} else {
577			delayedWithdrawRequest = append(delayedWithdrawRequest, exitID)
578		}
579	}
580	err = historyDB.updateExitTree(historyDB.db, block.Block.EthBlockNum, instantWithdrawn, delayedWithdrawRequest)
581	require.Nil(t, err)
582
583	// Check that exits in DB match with the expected values
584	dbExits, err := historyDB.GetAllExits()
585	require.Nil(t, err)
586	assert.Equal(t, 4, len(dbExits))
587	dbExitsByIdx := make(map[common.Idx]common.ExitInfo)
588	for _, dbExit := range dbExits {
589		dbExitsByIdx[dbExit.AccountIdx] = dbExit
590	}
591	for _, withdraw := range block.Rollup.Withdrawals {
592		assert.Equal(t, withdraw.NumExitRoot, dbExitsByIdx[withdraw.Idx].BatchNum)
593		if withdraw.InstantWithdraw {
594			assert.Equal(t, &block.Block.EthBlockNum, dbExitsByIdx[withdraw.Idx].InstantWithdrawn)
595		} else {
596			assert.Equal(t, &block.Block.EthBlockNum, dbExitsByIdx[withdraw.Idx].DelayedWithdrawRequest)
597		}
598	}
599}
600
601// setTestBlocks WARNING: this will delete the blocks and recreate them
602func setTestBlocks(from, to int64) []common.Block {
603	test.WipeDB(historyDB.DB())
604	blocks := test.GenBlocks(from, to)
605	if err := historyDB.AddBlocks(blocks); err != nil {
606		panic(err)
607	}
608	return blocks
609}