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 = 0
 54	toBlock = 7
 55	// Reset DB
 56	test.WipeDB(historyDB.DB())
 57	// Generate blocks using til
 58	set1 := `
 59		Type: Blockchain
 60		// block 0 is stored as default in the DB
 61		// block 1 does not exist
 62		> block // blockNum=2
 63		> block // blockNum=3 
 64		> block // blockNum=4
 65		> block // blockNum=5
 66		> block // blockNum=6
 67	`
 68	tc := til.NewContext(1)
 69	blocks, err := tc.GenerateBlocks(set1)
 70	require.NoError(t, err)
 71	// Save timestamp of a block with UTC and change it without UTC
 72	timestamp := time.Now().Add(time.Second * 13)
 73	blocks[fromBlock].Block.Timestamp = timestamp
 74	// Insert blocks into DB
 75	for i := 0; i < len(blocks); i++ {
 76		err := historyDB.AddBlock(&blocks[i].Block)
 77		assert.NoError(t, err)
 78	}
 79	// Add block 0 to the generated blocks
 80	blocks = append(
 81		[]common.BlockData{common.BlockData{Block: test.Block0}}, //nolint:gofmt
 82		blocks...,
 83	)
 84	// Get all blocks from DB
 85	fetchedBlocks, err := historyDB.GetBlocks(fromBlock, toBlock)
 86	assert.Equal(t, len(blocks), len(fetchedBlocks))
 87	// Compare generated vs getted blocks
 88	assert.NoError(t, err)
 89	for i := range fetchedBlocks {
 90		assertEqualBlock(t, &blocks[i].Block, &fetchedBlocks[i])
 91	}
 92	// Compare saved timestamp vs getted
 93	nameZoneUTC, offsetUTC := timestamp.UTC().Zone()
 94	zoneFetchedBlock, offsetFetchedBlock := fetchedBlocks[fromBlock].Timestamp.Zone()
 95	assert.Equal(t, nameZoneUTC, zoneFetchedBlock)
 96	assert.Equal(t, offsetUTC, offsetFetchedBlock)
 97	// Get blocks from the DB one by one
 98	for i := int64(2); i < toBlock; i++ { // avoid block 0 for simplicity
 99		fetchedBlock, err := historyDB.GetBlock(i)
100		assert.NoError(t, err)
101		assertEqualBlock(t, &blocks[i-1].Block, fetchedBlock)
102	}
103	// Get last block
104	lastBlock, err := historyDB.GetLastBlock()
105	assert.NoError(t, err)
106	assertEqualBlock(t, &blocks[len(blocks)-1].Block, lastBlock)
107}
108
109func assertEqualBlock(t *testing.T, expected *common.Block, actual *common.Block) {
110	assert.Equal(t, expected.Num, actual.Num)
111	assert.Equal(t, expected.Hash, actual.Hash)
112	assert.Equal(t, expected.Timestamp.Unix(), actual.Timestamp.Unix())
113}
114
115func TestBatches(t *testing.T) {
116	// Reset DB
117	test.WipeDB(historyDB.DB())
118	// Generate batches using til (and blocks for foreign key)
119	set := `
120		Type: Blockchain
121		
122		AddToken(1) // Will have value in USD
123		AddToken(2) // Will NOT have value in USD
124		CreateAccountDeposit(1) A: 2000
125		CreateAccountDeposit(2) A: 2000
126		CreateAccountDeposit(1) B: 1000
127		CreateAccountDeposit(2) B: 1000
128		> batchL1 
129		> batchL1 
130		Transfer(1) A-B: 100 (5)
131		Transfer(2) B-A: 100 (199)
132		> batch   // batchNum=2, L2 only batch, forges transfers (mixed case of with(out) USD value)
133		> block
134		Transfer(1) A-B: 100 (5)
135		> batch   // batchNum=3, L2 only batch, forges transfer (with USD value)
136		Transfer(2) B-A: 100 (199)
137		> batch   // batchNum=4, L2 only batch, forges transfer (without USD value)
138		> block
139	`
140	tc := til.NewContext(common.RollupConstMaxL1UserTx)
141	tilCfgExtra := til.ConfigExtra{
142		BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
143		CoordUser:     "A",
144	}
145	blocks, err := tc.GenerateBlocks(set)
146	require.Nil(t, err)
147	err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
148	assert.Nil(t, err)
149	// Insert to DB
150	batches := []common.Batch{}
151	tokensValue := make(map[common.TokenID]float64)
152	lastL1TxsNum := new(int64)
153	lastL1BatchBlockNum := int64(0)
154	for _, block := range blocks {
155		// Insert block
156		assert.NoError(t, historyDB.AddBlock(&block.Block))
157		// Insert tokens
158		for i, token := range block.Rollup.AddedTokens {
159			assert.NoError(t, historyDB.AddToken(&token)) //nolint:gosec
160			if i%2 != 0 {
161				// Set value to the token
162				value := (float64(i) + 5) * 5.389329
163				assert.NoError(t, historyDB.UpdateTokenValue(token.Symbol, value))
164				tokensValue[token.TokenID] = value / math.Pow(10, float64(token.Decimals))
165			}
166		}
167		// Combine all generated batches into single array
168		for _, batch := range block.Rollup.Batches {
169			batches = append(batches, batch.Batch)
170			forgeTxsNum := batch.Batch.ForgeL1TxsNum
171			if forgeTxsNum != nil && (lastL1TxsNum == nil || *lastL1TxsNum < *forgeTxsNum) {
172				*lastL1TxsNum = *forgeTxsNum
173				lastL1BatchBlockNum = batch.Batch.EthBlockNum
174			}
175		}
176	}
177	// Insert batches
178	assert.NoError(t, historyDB.AddBatches(batches))
179	// Set expected total fee
180	for _, batch := range batches {
181		total := .0
182		for tokenID, amount := range batch.CollectedFees {
183			af := new(big.Float).SetInt(amount)
184			amountFloat, _ := af.Float64()
185			total += tokensValue[tokenID] * amountFloat
186		}
187		batch.TotalFeesUSD = &total
188	}
189	// Get batches from the DB
190	fetchedBatches, err := historyDB.GetBatches(0, common.BatchNum(len(batches)+1))
191	assert.NoError(t, err)
192	assert.Equal(t, len(batches), len(fetchedBatches))
193	for i, fetchedBatch := range fetchedBatches {
194		assert.Equal(t, batches[i], fetchedBatch)
195	}
196	// Test GetLastBatchNum
197	fetchedLastBatchNum, err := historyDB.GetLastBatchNum()
198	assert.NoError(t, err)
199	assert.Equal(t, batches[len(batches)-1].BatchNum, fetchedLastBatchNum)
200	// Test GetLastL1TxsNum
201	fetchedLastL1TxsNum, err := historyDB.GetLastL1TxsNum()
202	assert.NoError(t, err)
203	assert.Equal(t, lastL1TxsNum, fetchedLastL1TxsNum)
204	// Test GetLastL1BatchBlockNum
205	fetchedLastL1BatchBlockNum, err := historyDB.GetLastL1BatchBlockNum()
206	assert.NoError(t, err)
207	assert.Equal(t, lastL1BatchBlockNum, fetchedLastL1BatchBlockNum)
208}
209
210func TestBids(t *testing.T) {
211	const fromBlock int64 = 1
212	const toBlock int64 = 5
213	// Prepare blocks in the DB
214	blocks := setTestBlocks(fromBlock, toBlock)
215	// Generate fake coordinators
216	const nCoords = 5
217	coords := test.GenCoordinators(nCoords, blocks)
218	err := historyDB.AddCoordinators(coords)
219	assert.NoError(t, err)
220	// Generate fake bids
221	const nBids = 20
222	bids := test.GenBids(nBids, blocks, coords)
223	err = historyDB.AddBids(bids)
224	assert.NoError(t, err)
225	// Fetch bids
226	fetchedBids, err := historyDB.GetAllBids()
227	assert.NoError(t, err)
228	// Compare fetched bids vs generated bids
229	for i, bid := range fetchedBids {
230		assert.Equal(t, bids[i], bid)
231	}
232}
233
234func TestTokens(t *testing.T) {
235	const fromBlock int64 = 1
236	const toBlock int64 = 5
237	// Prepare blocks in the DB
238	blocks := setTestBlocks(fromBlock, toBlock)
239	// Generate fake tokens
240	const nTokens = 5
241	tokens, ethToken := test.GenTokens(nTokens, blocks)
242	err := historyDB.AddTokens(tokens)
243	assert.NoError(t, err)
244	tokens = append([]common.Token{ethToken}, tokens...)
245	limit := uint(10)
246	// Fetch tokens
247	fetchedTokens, _, err := historyDB.GetTokens(nil, nil, "", nil, &limit, OrderAsc)
248	assert.NoError(t, err)
249	// Compare fetched tokens vs generated tokens
250	// All the tokens should have USDUpdate setted by the DB trigger
251	for i, token := range fetchedTokens {
252		assert.Equal(t, tokens[i].TokenID, token.TokenID)
253		assert.Equal(t, tokens[i].EthBlockNum, token.EthBlockNum)
254		assert.Equal(t, tokens[i].EthAddr, token.EthAddr)
255		assert.Equal(t, tokens[i].Name, token.Name)
256		assert.Equal(t, tokens[i].Symbol, token.Symbol)
257		assert.Nil(t, token.USD)
258		assert.Nil(t, token.USDUpdate)
259	}
260
261	// Update token value
262	for i, token := range tokens {
263		value := 1.01 * float64(i)
264		assert.NoError(t, historyDB.UpdateTokenValue(token.Symbol, value))
265	}
266	// Fetch tokens
267	fetchedTokens, _, err = historyDB.GetTokens(nil, nil, "", nil, &limit, OrderAsc)
268	assert.NoError(t, err)
269	// Compare fetched tokens vs generated tokens
270	// All the tokens should have USDUpdate setted by the DB trigger
271	for i, token := range fetchedTokens {
272		value := 1.01 * float64(i)
273		assert.Equal(t, value, *token.USD)
274		nameZone, offset := token.USDUpdate.Zone()
275		assert.Equal(t, "UTC", nameZone)
276		assert.Equal(t, 0, offset)
277	}
278}
279
280func TestAccounts(t *testing.T) {
281	const fromBlock int64 = 1
282	const toBlock int64 = 5
283	// Prepare blocks in the DB
284	blocks := setTestBlocks(fromBlock, toBlock)
285	// Generate fake tokens
286	const nTokens = 5
287	tokens, ethToken := test.GenTokens(nTokens, blocks)
288	err := historyDB.AddTokens(tokens)
289	assert.NoError(t, err)
290	tokens = append([]common.Token{ethToken}, tokens...)
291	// Generate fake batches
292	const nBatches = 10
293	batches := test.GenBatches(nBatches, blocks)
294	err = historyDB.AddBatches(batches)
295	assert.NoError(t, err)
296	// Generate fake accounts
297	const nAccounts = 3
298	accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
299	err = historyDB.AddAccounts(accs)
300	assert.NoError(t, err)
301	// Fetch accounts
302	fetchedAccs, err := historyDB.GetAllAccounts()
303	assert.NoError(t, err)
304	// Compare fetched accounts vs generated accounts
305	for i, acc := range fetchedAccs {
306		accs[i].Balance = nil
307		assert.Equal(t, accs[i], acc)
308	}
309}
310
311func TestTxs(t *testing.T) {
312	// Reset DB
313	test.WipeDB(historyDB.DB())
314
315	set := `
316		Type: Blockchain
317		
318		AddToken(1)
319		AddToken(2)
320		CreateAccountDeposit(1) A: 10
321		CreateAccountDeposit(1) B: 10
322		> batchL1
323		> batchL1
324		> block
325				
326		CreateAccountDepositTransfer(1) C-A: 20, 10
327		CreateAccountCoordinator(1) User0
328		> batchL1
329		> batchL1
330		> block
331
332		Deposit(1) B: 10
333		Deposit(1) C: 10
334		Transfer(1) C-A : 10 (1)
335		Transfer(1) B-C : 10 (1)
336		Transfer(1) A-B : 10 (1)
337		Exit(1) A: 10 (1)
338		> batch
339		> block
340		
341		DepositTransfer(1) A-B: 10, 10
342		> batchL1
343		> block
344
345		ForceTransfer(1) A-B: 10
346		ForceExit(1) A: 5
347		> batchL1
348		> batchL1
349		> block
350
351		CreateAccountDeposit(2) D: 10
352		> batchL1
353		> block
354
355		CreateAccountDeposit(2) E: 10
356		> batchL1
357		> batchL1
358		> block
359
360	`
361	tc := til.NewContext(common.RollupConstMaxL1UserTx)
362	tilCfgExtra := til.ConfigExtra{
363		BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
364		CoordUser:     "A",
365	}
366	blocks, err := tc.GenerateBlocks(set)
367	require.Nil(t, err)
368	err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
369	assert.Nil(t, err)
370
371	// Sanity check
372	require.Equal(t, 7, len(blocks))
373	require.Equal(t, 2, len(blocks[0].Rollup.L1UserTxs))
374	require.Equal(t, 1, len(blocks[1].Rollup.L1UserTxs))
375	require.Equal(t, 2, len(blocks[2].Rollup.L1UserTxs))
376	require.Equal(t, 1, len(blocks[3].Rollup.L1UserTxs))
377	require.Equal(t, 2, len(blocks[4].Rollup.L1UserTxs))
378	require.Equal(t, 1, len(blocks[5].Rollup.L1UserTxs))
379	require.Equal(t, 1, len(blocks[6].Rollup.L1UserTxs))
380
381	var null *common.BatchNum = nil
382	var txID common.TxID
383
384	// Insert blocks into DB
385	for i := range blocks {
386		if i == len(blocks)-1 {
387			blocks[i].Block.Timestamp = time.Now()
388			dbL1Txs, err := historyDB.GetAllL1UserTxs()
389			assert.NoError(t, err)
390			// Check batch_num is nil before forging
391			assert.Equal(t, null, dbL1Txs[len(dbL1Txs)-1].BatchNum)
392			// Save this TxId
393			txID = dbL1Txs[len(dbL1Txs)-1].TxID
394		}
395		err = historyDB.AddBlockSCData(&blocks[i])
396		assert.NoError(t, err)
397	}
398
399	// Check blocks
400	dbBlocks, err := historyDB.GetAllBlocks()
401	assert.NoError(t, err)
402	assert.Equal(t, len(blocks)+1, len(dbBlocks))
403
404	// Check batches
405	batches, err := historyDB.GetAllBatches()
406	assert.NoError(t, err)
407	assert.Equal(t, 11, len(batches))
408
409	// Check L1 Transactions
410	dbL1Txs, err := historyDB.GetAllL1UserTxs()
411	assert.NoError(t, err)
412	assert.Equal(t, 10, len(dbL1Txs))
413
414	// Tx Type
415	assert.Equal(t, common.TxTypeCreateAccountDeposit, dbL1Txs[0].Type)
416	assert.Equal(t, common.TxTypeCreateAccountDeposit, dbL1Txs[1].Type)
417	assert.Equal(t, common.TxTypeCreateAccountDepositTransfer, dbL1Txs[2].Type)
418	assert.Equal(t, common.TxTypeDeposit, dbL1Txs[3].Type)
419	assert.Equal(t, common.TxTypeDeposit, dbL1Txs[4].Type)
420	assert.Equal(t, common.TxTypeDepositTransfer, dbL1Txs[5].Type)
421	assert.Equal(t, common.TxTypeForceTransfer, dbL1Txs[6].Type)
422	assert.Equal(t, common.TxTypeForceExit, dbL1Txs[7].Type)
423	assert.Equal(t, common.TxTypeCreateAccountDeposit, dbL1Txs[8].Type)
424	assert.Equal(t, common.TxTypeCreateAccountDeposit, dbL1Txs[9].Type)
425
426	// Tx ID
427	assert.Equal(t, "0x000000000000000001000000", dbL1Txs[0].TxID.String())
428	assert.Equal(t, "0x000000000000000001000100", dbL1Txs[1].TxID.String())
429	assert.Equal(t, "0x000000000000000003000000", dbL1Txs[2].TxID.String())
430	assert.Equal(t, "0x000000000000000005000000", dbL1Txs[3].TxID.String())
431	assert.Equal(t, "0x000000000000000005000100", dbL1Txs[4].TxID.String())
432	assert.Equal(t, "0x000000000000000005000200", dbL1Txs[5].TxID.String())
433	assert.Equal(t, "0x000000000000000006000000", dbL1Txs[6].TxID.String())
434	assert.Equal(t, "0x000000000000000006000100", dbL1Txs[7].TxID.String())
435	assert.Equal(t, "0x000000000000000008000000", dbL1Txs[8].TxID.String())
436	assert.Equal(t, "0x000000000000000009000000", dbL1Txs[9].TxID.String())
437
438	// Tx From IDx
439	assert.Equal(t, common.Idx(0), dbL1Txs[0].FromIdx)
440	assert.Equal(t, common.Idx(0), dbL1Txs[1].FromIdx)
441	assert.Equal(t, common.Idx(0), dbL1Txs[2].FromIdx)
442	assert.NotEqual(t, common.Idx(0), dbL1Txs[3].FromIdx)
443	assert.NotEqual(t, common.Idx(0), dbL1Txs[4].FromIdx)
444	assert.NotEqual(t, common.Idx(0), dbL1Txs[5].FromIdx)
445	assert.NotEqual(t, common.Idx(0), dbL1Txs[6].FromIdx)
446	assert.NotEqual(t, common.Idx(0), dbL1Txs[7].FromIdx)
447	assert.Equal(t, common.Idx(0), dbL1Txs[8].FromIdx)
448	assert.Equal(t, common.Idx(0), dbL1Txs[9].FromIdx)
449	assert.Equal(t, common.Idx(0), dbL1Txs[9].FromIdx)
450	assert.Equal(t, dbL1Txs[5].FromIdx, dbL1Txs[6].FromIdx)
451	assert.Equal(t, dbL1Txs[5].FromIdx, dbL1Txs[7].FromIdx)
452
453	// Tx to IDx
454	assert.Equal(t, dbL1Txs[2].ToIdx, dbL1Txs[5].FromIdx)
455	assert.Equal(t, dbL1Txs[5].ToIdx, dbL1Txs[3].FromIdx)
456	assert.Equal(t, dbL1Txs[6].ToIdx, dbL1Txs[3].FromIdx)
457
458	// Token ID
459	assert.Equal(t, common.TokenID(1), dbL1Txs[0].TokenID)
460	assert.Equal(t, common.TokenID(1), dbL1Txs[1].TokenID)
461	assert.Equal(t, common.TokenID(1), dbL1Txs[2].TokenID)
462	assert.Equal(t, common.TokenID(1), dbL1Txs[3].TokenID)
463	assert.Equal(t, common.TokenID(1), dbL1Txs[4].TokenID)
464	assert.Equal(t, common.TokenID(1), dbL1Txs[5].TokenID)
465	assert.Equal(t, common.TokenID(1), dbL1Txs[6].TokenID)
466	assert.Equal(t, common.TokenID(1), dbL1Txs[7].TokenID)
467	assert.Equal(t, common.TokenID(2), dbL1Txs[8].TokenID)
468	assert.Equal(t, common.TokenID(2), dbL1Txs[9].TokenID)
469
470	// Batch Number
471	var bn common.BatchNum = common.BatchNum(2)
472
473	assert.Equal(t, &bn, dbL1Txs[0].BatchNum)
474	assert.Equal(t, &bn, dbL1Txs[1].BatchNum)
475
476	bn = common.BatchNum(4)
477	assert.Equal(t, &bn, dbL1Txs[2].BatchNum)
478
479	bn = common.BatchNum(7)
480	assert.Equal(t, &bn, dbL1Txs[3].BatchNum)
481	assert.Equal(t, &bn, dbL1Txs[4].BatchNum)
482	assert.Equal(t, &bn, dbL1Txs[5].BatchNum)
483
484	bn = common.BatchNum(8)
485	assert.Equal(t, &bn, dbL1Txs[6].BatchNum)
486	assert.Equal(t, &bn, dbL1Txs[7].BatchNum)
487
488	bn = common.BatchNum(10)
489	assert.Equal(t, &bn, dbL1Txs[8].BatchNum)
490
491	bn = common.BatchNum(11)
492	assert.Equal(t, &bn, dbL1Txs[9].BatchNum)
493
494	// eth_block_num
495	assert.Equal(t, int64(2), dbL1Txs[0].EthBlockNum)
496	assert.Equal(t, int64(2), dbL1Txs[1].EthBlockNum)
497	assert.Equal(t, int64(3), dbL1Txs[2].EthBlockNum)
498	assert.Equal(t, int64(4), dbL1Txs[3].EthBlockNum)
499	assert.Equal(t, int64(4), dbL1Txs[4].EthBlockNum)
500	assert.Equal(t, int64(5), dbL1Txs[5].EthBlockNum)
501	assert.Equal(t, int64(6), dbL1Txs[6].EthBlockNum)
502	assert.Equal(t, int64(6), dbL1Txs[7].EthBlockNum)
503	assert.Equal(t, int64(7), dbL1Txs[8].EthBlockNum)
504	assert.Equal(t, int64(8), dbL1Txs[9].EthBlockNum)
505
506	// User Origin
507	assert.Equal(t, true, dbL1Txs[0].UserOrigin)
508	assert.Equal(t, true, dbL1Txs[1].UserOrigin)
509	assert.Equal(t, true, dbL1Txs[2].UserOrigin)
510	assert.Equal(t, true, dbL1Txs[3].UserOrigin)
511	assert.Equal(t, true, dbL1Txs[4].UserOrigin)
512	assert.Equal(t, true, dbL1Txs[5].UserOrigin)
513	assert.Equal(t, true, dbL1Txs[6].UserOrigin)
514	assert.Equal(t, true, dbL1Txs[7].UserOrigin)
515	assert.Equal(t, true, dbL1Txs[8].UserOrigin)
516	assert.Equal(t, true, dbL1Txs[9].UserOrigin)
517
518	// Load Amount
519	assert.Equal(t, big.NewInt(10), dbL1Txs[0].LoadAmount)
520	assert.Equal(t, big.NewInt(10), dbL1Txs[1].LoadAmount)
521	assert.Equal(t, big.NewInt(20), dbL1Txs[2].LoadAmount)
522	assert.Equal(t, big.NewInt(10), dbL1Txs[3].LoadAmount)
523	assert.Equal(t, big.NewInt(10), dbL1Txs[4].LoadAmount)
524	assert.Equal(t, big.NewInt(10), dbL1Txs[5].LoadAmount)
525	assert.Equal(t, big.NewInt(0), dbL1Txs[6].LoadAmount)
526	assert.Equal(t, big.NewInt(0), dbL1Txs[7].LoadAmount)
527	assert.Equal(t, big.NewInt(10), dbL1Txs[8].LoadAmount)
528	assert.Equal(t, big.NewInt(10), dbL1Txs[9].LoadAmount)
529
530	// Check saved txID's batch_num is not nil
531	assert.Equal(t, txID, dbL1Txs[len(dbL1Txs)-2].TxID)
532	assert.NotEqual(t, null, dbL1Txs[len(dbL1Txs)-2].BatchNum)
533
534	// Check Coordinator TXs
535	coordTxs, err := historyDB.GetAllL1CoordinatorTxs()
536	assert.NoError(t, err)
537	assert.Equal(t, 1, len(coordTxs))
538	assert.Equal(t, common.TxTypeCreateAccountDeposit, coordTxs[0].Type)
539	assert.Equal(t, false, coordTxs[0].UserOrigin)
540
541	// Check L2 TXs
542	dbL2Txs, err := historyDB.GetAllL2Txs()
543	assert.NoError(t, err)
544	assert.Equal(t, 4, len(dbL2Txs))
545
546	// Tx Type
547	assert.Equal(t, common.TxTypeTransfer, dbL2Txs[0].Type)
548	assert.Equal(t, common.TxTypeTransfer, dbL2Txs[1].Type)
549	assert.Equal(t, common.TxTypeTransfer, dbL2Txs[2].Type)
550	assert.Equal(t, common.TxTypeExit, dbL2Txs[3].Type)
551
552	// Tx ID
553	assert.Equal(t, "0x020000000001030000000001", dbL2Txs[0].TxID.String())
554	assert.Equal(t, "0x020000000001010000000001", dbL2Txs[1].TxID.String())
555	assert.Equal(t, "0x020000000001000000000001", dbL2Txs[2].TxID.String())
556	assert.Equal(t, "0x020000000001000000000002", dbL2Txs[3].TxID.String())
557
558	// Tx From and To IDx
559	assert.Equal(t, dbL2Txs[0].ToIdx, dbL2Txs[2].FromIdx)
560	assert.Equal(t, dbL2Txs[1].ToIdx, dbL2Txs[0].FromIdx)
561	assert.Equal(t, dbL2Txs[2].ToIdx, dbL2Txs[1].FromIdx)
562
563	// Batch Number
564	assert.Equal(t, common.BatchNum(5), dbL2Txs[0].BatchNum)
565	assert.Equal(t, common.BatchNum(5), dbL2Txs[1].BatchNum)
566	assert.Equal(t, common.BatchNum(5), dbL2Txs[2].BatchNum)
567	assert.Equal(t, common.BatchNum(5), dbL2Txs[3].BatchNum)
568
569	// eth_block_num
570	assert.Equal(t, int64(4), dbL2Txs[0].EthBlockNum)
571	assert.Equal(t, int64(4), dbL2Txs[1].EthBlockNum)
572	assert.Equal(t, int64(4), dbL2Txs[2].EthBlockNum)
573
574	// Amount
575	assert.Equal(t, big.NewInt(10), dbL2Txs[0].Amount)
576	assert.Equal(t, big.NewInt(10), dbL2Txs[1].Amount)
577	assert.Equal(t, big.NewInt(10), dbL2Txs[2].Amount)
578	assert.Equal(t, big.NewInt(10), dbL2Txs[3].Amount)
579}
580
581func TestExitTree(t *testing.T) {
582	nBatches := 17
583	blocks := setTestBlocks(1, 10)
584	batches := test.GenBatches(nBatches, blocks)
585	err := historyDB.AddBatches(batches)
586	assert.NoError(t, err)
587	const nTokens = 50
588	tokens, ethToken := test.GenTokens(nTokens, blocks)
589	err = historyDB.AddTokens(tokens)
590	assert.NoError(t, err)
591	tokens = append([]common.Token{ethToken}, tokens...)
592	const nAccounts = 3
593	accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
594	assert.NoError(t, historyDB.AddAccounts(accs))
595	exitTree := test.GenExitTree(nBatches, batches, accs, blocks)
596	err = historyDB.AddExitTree(exitTree)
597	assert.NoError(t, err)
598}
599
600func TestGetL1UserTxs(t *testing.T) {
601	test.WipeDB(historyDB.DB())
602
603	set := `
604		Type: Blockchain
605		AddToken(1)
606		AddToken(2)
607		AddToken(3)
608
609		CreateAccountDeposit(1) A: 20
610		CreateAccountDeposit(2) A: 20
611		CreateAccountDeposit(1) B: 5
612		CreateAccountDeposit(1) C: 5
613		CreateAccountDeposit(1) D: 5
614
615		> block
616	`
617	tc := til.NewContext(128)
618	blocks, err := tc.GenerateBlocks(set)
619	require.Nil(t, err)
620	// Sanity check
621	require.Equal(t, 1, len(blocks))
622	require.Equal(t, 5, len(blocks[0].Rollup.L1UserTxs))
623
624	toForgeL1TxsNum := int64(1)
625
626	for i := range blocks {
627		err = historyDB.AddBlockSCData(&blocks[i])
628		require.Nil(t, err)
629	}
630
631	l1UserTxs, err := historyDB.GetL1UserTxs(toForgeL1TxsNum)
632	require.Nil(t, err)
633	assert.Equal(t, 5, len(l1UserTxs))
634	assert.Equal(t, blocks[0].Rollup.L1UserTxs, l1UserTxs)
635
636	// No l1UserTxs for this toForgeL1TxsNum
637	l1UserTxs, err = historyDB.GetL1UserTxs(2)
638	require.Nil(t, err)
639	assert.Equal(t, 0, len(l1UserTxs))
640}
641
642func exampleInitSCVars() (*common.RollupVariables, *common.AuctionVariables, *common.WDelayerVariables) {
643	//nolint:govet
644	rollup := &common.RollupVariables{
645		0,
646		big.NewInt(10),
647		12,
648		13,
649		[5]common.Bucket{},
650	}
651	//nolint:govet
652	auction := &common.AuctionVariables{
653		0,
654		ethCommon.BigToAddress(big.NewInt(2)),
655		ethCommon.BigToAddress(big.NewInt(3)),
656		[6]*big.Int{
657			big.NewInt(1), big.NewInt(2), big.NewInt(3),
658			big.NewInt(4), big.NewInt(5), big.NewInt(6),
659		},
660		0,
661		2,
662		4320,
663		[3]uint16{10, 11, 12},
664		1000,
665		20,
666	}
667	//nolint:govet
668	wDelayer := &common.WDelayerVariables{
669		0,
670		ethCommon.BigToAddress(big.NewInt(2)),
671		ethCommon.BigToAddress(big.NewInt(3)),
672		ethCommon.BigToAddress(big.NewInt(4)),
673		13,
674		14,
675		false,
676	}
677	return rollup, auction, wDelayer
678}
679
680func TestSetInitialSCVars(t *testing.T) {
681	test.WipeDB(historyDB.DB())
682	_, _, _, err := historyDB.GetSCVars()
683	assert.Equal(t, sql.ErrNoRows, err)
684	rollup, auction, wDelayer := exampleInitSCVars()
685	err = historyDB.SetInitialSCVars(rollup, auction, wDelayer)
686	require.Nil(t, err)
687	dbRollup, dbAuction, dbWDelayer, err := historyDB.GetSCVars()
688	assert.Nil(t, err)
689	require.Equal(t, rollup, dbRollup)
690	require.Equal(t, auction, dbAuction)
691	require.Equal(t, wDelayer, dbWDelayer)
692}
693
694func TestUpdateExitTree(t *testing.T) {
695	test.WipeDB(historyDB.DB())
696
697	set := `
698		Type: Blockchain
699
700		AddToken(1)
701
702		CreateAccountDeposit(1) C: 2000 // Idx=256+2=258
703		CreateAccountDeposit(1) D: 500  // Idx=256+3=259
704
705		CreateAccountCoordinator(1) A // Idx=256+0=256
706		CreateAccountCoordinator(1) B // Idx=256+1=257
707
708		> batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{5}
709		> batchL1 // forge defined L1UserTxs{5}, freeze L1UserTxs{nil}
710		> block // blockNum=2
711
712		ForceExit(1) A: 100
713		ForceExit(1) B: 80
714
715		Exit(1) C: 50 (172)
716		Exit(1) D: 30 (172)
717
718		> batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{3}
719		> batchL1 // forge L1UserTxs{3}, freeze defined L1UserTxs{nil}
720		> block // blockNum=3
721
722		> block // blockNum=4 (empty block)
723		> block // blockNum=5 (empty block)
724	`
725
726	tc := til.NewContext(common.RollupConstMaxL1UserTx)
727	tilCfgExtra := til.ConfigExtra{
728		BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
729		CoordUser:     "A",
730	}
731	blocks, err := tc.GenerateBlocks(set)
732	require.Nil(t, err)
733	err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
734	assert.Nil(t, err)
735
736	// Add all blocks except for the last two
737	for i := range blocks[:len(blocks)-2] {
738		err = historyDB.AddBlockSCData(&blocks[i])
739		require.Nil(t, err)
740	}
741
742	// Add withdraws to the second-to-last block, and insert block into the DB
743	block := &blocks[len(blocks)-2]
744	require.Equal(t, int64(4), block.Block.Num)
745	tokenAddr := blocks[0].Rollup.AddedTokens[0].EthAddr
746	// block.WDelayer.Deposits = append(block.WDelayer.Deposits,
747	// 	common.WDelayerTransfer{Owner: tc.UsersByIdx[257].Addr, Token: tokenAddr, Amount: big.NewInt(80)}, // 257
748	// 	common.WDelayerTransfer{Owner: tc.UsersByIdx[259].Addr, Token: tokenAddr, Amount: big.NewInt(15)}, // 259
749	// )
750	block.Rollup.Withdrawals = append(block.Rollup.Withdrawals,
751		common.WithdrawInfo{Idx: 256, NumExitRoot: 4, InstantWithdraw: true},
752		common.WithdrawInfo{Idx: 257, NumExitRoot: 4, InstantWithdraw: false,
753			Owner: tc.UsersByIdx[257].Addr, Token: tokenAddr},
754		common.WithdrawInfo{Idx: 258, NumExitRoot: 3, InstantWithdraw: true},
755		common.WithdrawInfo{Idx: 259, NumExitRoot: 3, InstantWithdraw: false,
756			Owner: tc.UsersByIdx[259].Addr, Token: tokenAddr},
757	)
758	err = historyDB.addBlock(historyDB.db, &block.Block)
759	require.Nil(t, err)
760
761	err = historyDB.updateExitTree(historyDB.db, block.Block.Num,
762		block.Rollup.Withdrawals, block.WDelayer.Withdrawals)
763	require.Nil(t, err)
764
765	// Check that exits in DB match with the expected values
766	dbExits, err := historyDB.GetAllExits()
767	require.Nil(t, err)
768	assert.Equal(t, 4, len(dbExits))
769	dbExitsByIdx := make(map[common.Idx]common.ExitInfo)
770	for _, dbExit := range dbExits {
771		dbExitsByIdx[dbExit.AccountIdx] = dbExit
772	}
773	for _, withdraw := range block.Rollup.Withdrawals {
774		assert.Equal(t, withdraw.NumExitRoot, dbExitsByIdx[withdraw.Idx].BatchNum)
775		if withdraw.InstantWithdraw {
776			assert.Equal(t, &block.Block.Num, dbExitsByIdx[withdraw.Idx].InstantWithdrawn)
777		} else {
778			assert.Equal(t, &block.Block.Num, dbExitsByIdx[withdraw.Idx].DelayedWithdrawRequest)
779		}
780	}
781
782	// Add delayed withdraw to the last block, and insert block into the DB
783	block = &blocks[len(blocks)-1]
784	require.Equal(t, int64(5), block.Block.Num)
785	block.WDelayer.Withdrawals = append(block.WDelayer.Withdrawals,
786		common.WDelayerTransfer{
787			Owner:  tc.UsersByIdx[257].Addr,
788			Token:  tokenAddr,
789			Amount: big.NewInt(80),
790		})
791	err = historyDB.addBlock(historyDB.db, &block.Block)
792	require.Nil(t, err)
793
794	err = historyDB.updateExitTree(historyDB.db, block.Block.Num,
795		block.Rollup.Withdrawals, block.WDelayer.Withdrawals)
796	require.Nil(t, err)
797
798	// Check that delayed withdrawn has been set
799	dbExits, err = historyDB.GetAllExits()
800	require.Nil(t, err)
801	for _, dbExit := range dbExits {
802		dbExitsByIdx[dbExit.AccountIdx] = dbExit
803	}
804	require.Equal(t, &block.Block.Num, dbExitsByIdx[257].DelayedWithdrawn)
805}
806
807func TestGetBestBidCoordinator(t *testing.T) {
808	test.WipeDB(historyDB.DB())
809
810	rollup, auction, wDelayer := exampleInitSCVars()
811	err := historyDB.SetInitialSCVars(rollup, auction, wDelayer)
812	require.Nil(t, err)
813
814	tc := til.NewContext(common.RollupConstMaxL1UserTx)
815	blocks, err := tc.GenerateBlocks(`
816		Type: Blockchain
817		> block // blockNum=2
818	`)
819	require.Nil(t, err)
820	err = historyDB.AddBlockSCData(&blocks[0])
821	require.Nil(t, err)
822
823	coords := []common.Coordinator{
824		{
825			Bidder:      ethCommon.BigToAddress(big.NewInt(1)),
826			Forger:      ethCommon.BigToAddress(big.NewInt(2)),
827			EthBlockNum: 2,
828			URL:         "foo",
829		},
830		{
831			Bidder:      ethCommon.BigToAddress(big.NewInt(3)),
832			Forger:      ethCommon.BigToAddress(big.NewInt(4)),
833			EthBlockNum: 2,
834			URL:         "bar",
835		},
836	}
837	err = historyDB.addCoordinators(historyDB.db, coords)
838	require.Nil(t, err)
839	err = historyDB.addBids(historyDB.db, []common.Bid{
840		{
841			SlotNum:     10,
842			BidValue:    big.NewInt(10),
843			EthBlockNum: 2,
844			Bidder:      coords[0].Bidder,
845		},
846		{
847			SlotNum:     10,
848			BidValue:    big.NewInt(20),
849			EthBlockNum: 2,
850			Bidder:      coords[1].Bidder,
851		},
852	})
853	require.Nil(t, err)
854
855	forger10, err := historyDB.GetBestBidCoordinator(10)
856	require.Nil(t, err)
857	require.Equal(t, coords[1].Forger, forger10.Forger)
858	require.Equal(t, coords[1].Bidder, forger10.Bidder)
859	require.Equal(t, coords[1].URL, forger10.URL)
860
861	_, err = historyDB.GetBestBidCoordinator(11)
862	require.Equal(t, sql.ErrNoRows, err)
863}
864
865// setTestBlocks WARNING: this will delete the blocks and recreate them
866func setTestBlocks(from, to int64) []common.Block {
867	test.WipeDB(historyDB.DB())
868	blocks := test.GenBlocks(from, to)
869	if err := historyDB.AddBlocks(blocks); err != nil {
870		panic(err)
871	}
872	return blocks
873}