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