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