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		[5]common.Bucket{},
473	}
474	//nolint:govet
475	auction := &common.AuctionVariables{
476		0,
477		ethCommon.BigToAddress(big.NewInt(2)),
478		ethCommon.BigToAddress(big.NewInt(3)),
479		[6]*big.Int{
480			big.NewInt(1), big.NewInt(2), big.NewInt(3),
481			big.NewInt(4), big.NewInt(5), big.NewInt(6),
482		},
483		2,
484		4320,
485		[3]uint16{10, 11, 12},
486		1000,
487		20,
488	}
489	//nolint:govet
490	wDelayer := &common.WDelayerVariables{
491		0,
492		ethCommon.BigToAddress(big.NewInt(2)),
493		ethCommon.BigToAddress(big.NewInt(3)),
494		ethCommon.BigToAddress(big.NewInt(4)),
495		13,
496		14,
497		false,
498	}
499	err = historyDB.SetInitialSCVars(rollup, auction, wDelayer)
500	require.Nil(t, err)
501	dbRollup, dbAuction, dbWDelayer, err := historyDB.GetSCVars()
502	assert.Nil(t, err)
503	require.Equal(t, rollup, dbRollup)
504	require.Equal(t, auction, dbAuction)
505	require.Equal(t, wDelayer, dbWDelayer)
506}
507
508func TestUpdateExitTree(t *testing.T) {
509	test.WipeDB(historyDB.DB())
510
511	set := `
512		Type: Blockchain
513
514		AddToken(1)
515
516		CreateAccountDeposit(1) C: 2000 // Idx=256+2=258
517		CreateAccountDeposit(1) D: 500  // Idx=256+3=259
518
519		CreateAccountCoordinator(1) A // Idx=256+0=256
520		CreateAccountCoordinator(1) B // Idx=256+1=257
521
522		> batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{5}
523		> batchL1 // forge defined L1UserTxs{5}, freeze L1UserTxs{nil}
524		> block // blockNum=2
525
526		ForceExit(1) A: 100
527		ForceExit(1) B: 80
528
529		Exit(1) C: 50 (200)
530		Exit(1) D: 30 (200)
531
532		> batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{3}
533		> batchL1 // forge L1UserTxs{3}, freeze defined L1UserTxs{nil}
534		> block // blockNum=3
535
536		> block // blockNum=4 (empty block)
537	`
538
539	tc := til.NewContext(common.RollupConstMaxL1UserTx)
540	tilCfgExtra := til.ConfigExtra{
541		BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
542		CoordUser:     "A",
543	}
544	blocks, err := tc.GenerateBlocks(set)
545	require.Nil(t, err)
546	err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
547	assert.Nil(t, err)
548
549	// Add all blocks except for the last one
550	for i := range blocks[:len(blocks)-1] {
551		err = historyDB.AddBlockSCData(&blocks[i])
552		require.Nil(t, err)
553	}
554
555	// Add withdraws to the last block, and insert block into the DB
556	block := &blocks[len(blocks)-1]
557	require.Equal(t, int64(4), block.Block.EthBlockNum)
558	block.Rollup.Withdrawals = append(block.Rollup.Withdrawals,
559		common.WithdrawInfo{Idx: 256, NumExitRoot: 4, InstantWithdraw: true},
560		common.WithdrawInfo{Idx: 257, NumExitRoot: 4, InstantWithdraw: false},
561		common.WithdrawInfo{Idx: 258, NumExitRoot: 3, InstantWithdraw: true},
562		common.WithdrawInfo{Idx: 259, NumExitRoot: 3, InstantWithdraw: false},
563	)
564	err = historyDB.addBlock(historyDB.db, &block.Block)
565	require.Nil(t, err)
566
567	// update exit trees in DB
568	instantWithdrawn := []exitID{}
569	delayedWithdrawRequest := []exitID{}
570	for _, withdraw := range block.Rollup.Withdrawals {
571		exitID := exitID{
572			batchNum: int64(withdraw.NumExitRoot),
573			idx:      int64(withdraw.Idx),
574		}
575		if withdraw.InstantWithdraw {
576			instantWithdrawn = append(instantWithdrawn, exitID)
577		} else {
578			delayedWithdrawRequest = append(delayedWithdrawRequest, exitID)
579		}
580	}
581	err = historyDB.updateExitTree(historyDB.db, block.Block.EthBlockNum, instantWithdrawn, delayedWithdrawRequest)
582	require.Nil(t, err)
583
584	// Check that exits in DB match with the expected values
585	dbExits, err := historyDB.GetAllExits()
586	require.Nil(t, err)
587	assert.Equal(t, 4, len(dbExits))
588	dbExitsByIdx := make(map[common.Idx]common.ExitInfo)
589	for _, dbExit := range dbExits {
590		dbExitsByIdx[dbExit.AccountIdx] = dbExit
591	}
592	for _, withdraw := range block.Rollup.Withdrawals {
593		assert.Equal(t, withdraw.NumExitRoot, dbExitsByIdx[withdraw.Idx].BatchNum)
594		if withdraw.InstantWithdraw {
595			assert.Equal(t, &block.Block.EthBlockNum, dbExitsByIdx[withdraw.Idx].InstantWithdrawn)
596		} else {
597			assert.Equal(t, &block.Block.EthBlockNum, dbExitsByIdx[withdraw.Idx].DelayedWithdrawRequest)
598		}
599	}
600}
601
602// setTestBlocks WARNING: this will delete the blocks and recreate them
603func setTestBlocks(from, to int64) []common.Block {
604	test.WipeDB(historyDB.DB())
605	blocks := test.GenBlocks(from, to)
606	if err := historyDB.AddBlocks(blocks); err != nil {
607		panic(err)
608	}
609	return blocks
610}