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	// Deposit Amount
520	assert.Equal(t, big.NewInt(10), dbL1Txs[0].DepositAmount)
521	assert.Equal(t, big.NewInt(10), dbL1Txs[1].DepositAmount)
522	assert.Equal(t, big.NewInt(20), dbL1Txs[2].DepositAmount)
523	assert.Equal(t, big.NewInt(10), dbL1Txs[3].DepositAmount)
524	assert.Equal(t, big.NewInt(10), dbL1Txs[4].DepositAmount)
525	assert.Equal(t, big.NewInt(10), dbL1Txs[5].DepositAmount)
526	assert.Equal(t, big.NewInt(0), dbL1Txs[6].DepositAmount)
527	assert.Equal(t, big.NewInt(0), dbL1Txs[7].DepositAmount)
528	assert.Equal(t, big.NewInt(10), dbL1Txs[8].DepositAmount)
529	assert.Equal(t, big.NewInt(10), dbL1Txs[9].DepositAmount)
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 TestGetUnforgedL1UserTxs(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.GetUnforgedL1UserTxs(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.GetUnforgedL1UserTxs(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	// Add second batch to trigger the update of the batch_num,
732	// while avoiding the implicit call of setL1UserTxEffectiveAmounts
733	err = historyDB.addBlock(historyDB.db, &blocks[1].Block)
734	assert.NoError(t, err)
735	err = historyDB.addBatch(historyDB.db, &blocks[1].Rollup.Batches[0].Batch)
736	assert.NoError(t, err)
737	require.Nil(t, err)
738
739	// Set the Effective{Amount,DepositAmount} of the L1UserTxs that are forged in the second block
740	l1Txs := blocks[1].Rollup.Batches[0].L1UserTxs
741	require.Equal(t, 3, len(l1Txs))
742	// Change some values to test all cases
743	l1Txs[1].EffectiveAmount = big.NewInt(0)
744	l1Txs[2].EffectiveDepositAmount = big.NewInt(0)
745	l1Txs[2].EffectiveAmount = big.NewInt(0)
746	err = historyDB.setL1UserTxEffectiveAmounts(historyDB.db, l1Txs)
747	require.NoError(t, err)
748
749	dbL1Txs, err := historyDB.GetAllL1UserTxs()
750	require.NoError(t, err)
751	for i, tx := range dbL1Txs {
752		log.Infof("%d %v %v", i, tx.EffectiveAmount, tx.EffectiveDepositAmount)
753		assert.NotNil(t, tx.EffectiveAmount)
754		assert.NotNil(t, tx.EffectiveDepositAmount)
755		switch tx.TxID {
756		case l1Txs[0].TxID:
757			assert.Equal(t, l1Txs[0].DepositAmount, tx.EffectiveDepositAmount)
758			assert.Equal(t, l1Txs[0].Amount, tx.EffectiveAmount)
759		case l1Txs[1].TxID:
760			assert.Equal(t, l1Txs[1].DepositAmount, tx.EffectiveDepositAmount)
761			assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
762		case l1Txs[2].TxID:
763			assert.Equal(t, big.NewInt(0), tx.EffectiveDepositAmount)
764			assert.Equal(t, big.NewInt(0), tx.EffectiveAmount)
765		}
766	}
767}
768
769func TestUpdateExitTree(t *testing.T) {
770	test.WipeDB(historyDB.DB())
771
772	set := `
773		Type: Blockchain
774
775		AddToken(1)
776
777		CreateAccountDeposit(1) C: 2000 // Idx=256+2=258
778		CreateAccountDeposit(1) D: 500  // Idx=256+3=259
779
780		CreateAccountCoordinator(1) A // Idx=256+0=256
781		CreateAccountCoordinator(1) B // Idx=256+1=257
782
783		> batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{5}
784		> batchL1 // forge defined L1UserTxs{5}, freeze L1UserTxs{nil}
785		> block // blockNum=2
786
787		ForceExit(1) A: 100
788		ForceExit(1) B: 80
789
790		Exit(1) C: 50 (172)
791		Exit(1) D: 30 (172)
792
793		> batchL1 // forge L1UserTxs{nil}, freeze defined L1UserTxs{3}
794		> batchL1 // forge L1UserTxs{3}, freeze defined L1UserTxs{nil}
795		> block // blockNum=3
796
797		> block // blockNum=4 (empty block)
798		> block // blockNum=5 (empty block)
799	`
800
801	tc := til.NewContext(common.RollupConstMaxL1UserTx)
802	tilCfgExtra := til.ConfigExtra{
803		BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
804		CoordUser:     "A",
805	}
806	blocks, err := tc.GenerateBlocks(set)
807	require.Nil(t, err)
808	err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
809	assert.Nil(t, err)
810
811	// Add all blocks except for the last two
812	for i := range blocks[:len(blocks)-2] {
813		err = historyDB.AddBlockSCData(&blocks[i])
814		require.Nil(t, err)
815	}
816
817	// Add withdraws to the second-to-last block, and insert block into the DB
818	block := &blocks[len(blocks)-2]
819	require.Equal(t, int64(4), block.Block.Num)
820	tokenAddr := blocks[0].Rollup.AddedTokens[0].EthAddr
821	// block.WDelayer.Deposits = append(block.WDelayer.Deposits,
822	// 	common.WDelayerTransfer{Owner: tc.UsersByIdx[257].Addr, Token: tokenAddr, Amount: big.NewInt(80)}, // 257
823	// 	common.WDelayerTransfer{Owner: tc.UsersByIdx[259].Addr, Token: tokenAddr, Amount: big.NewInt(15)}, // 259
824	// )
825	block.Rollup.Withdrawals = append(block.Rollup.Withdrawals,
826		common.WithdrawInfo{Idx: 256, NumExitRoot: 4, InstantWithdraw: true},
827		common.WithdrawInfo{Idx: 257, NumExitRoot: 4, InstantWithdraw: false,
828			Owner: tc.UsersByIdx[257].Addr, Token: tokenAddr},
829		common.WithdrawInfo{Idx: 258, NumExitRoot: 3, InstantWithdraw: true},
830		common.WithdrawInfo{Idx: 259, NumExitRoot: 3, InstantWithdraw: false,
831			Owner: tc.UsersByIdx[259].Addr, Token: tokenAddr},
832	)
833	err = historyDB.addBlock(historyDB.db, &block.Block)
834	require.Nil(t, err)
835
836	err = historyDB.updateExitTree(historyDB.db, block.Block.Num,
837		block.Rollup.Withdrawals, block.WDelayer.Withdrawals)
838	require.Nil(t, err)
839
840	// Check that exits in DB match with the expected values
841	dbExits, err := historyDB.GetAllExits()
842	require.Nil(t, err)
843	assert.Equal(t, 4, len(dbExits))
844	dbExitsByIdx := make(map[common.Idx]common.ExitInfo)
845	for _, dbExit := range dbExits {
846		dbExitsByIdx[dbExit.AccountIdx] = dbExit
847	}
848	for _, withdraw := range block.Rollup.Withdrawals {
849		assert.Equal(t, withdraw.NumExitRoot, dbExitsByIdx[withdraw.Idx].BatchNum)
850		if withdraw.InstantWithdraw {
851			assert.Equal(t, &block.Block.Num, dbExitsByIdx[withdraw.Idx].InstantWithdrawn)
852		} else {
853			assert.Equal(t, &block.Block.Num, dbExitsByIdx[withdraw.Idx].DelayedWithdrawRequest)
854		}
855	}
856
857	// Add delayed withdraw to the last block, and insert block into the DB
858	block = &blocks[len(blocks)-1]
859	require.Equal(t, int64(5), block.Block.Num)
860	block.WDelayer.Withdrawals = append(block.WDelayer.Withdrawals,
861		common.WDelayerTransfer{
862			Owner:  tc.UsersByIdx[257].Addr,
863			Token:  tokenAddr,
864			Amount: big.NewInt(80),
865		})
866	err = historyDB.addBlock(historyDB.db, &block.Block)
867	require.Nil(t, err)
868
869	err = historyDB.updateExitTree(historyDB.db, block.Block.Num,
870		block.Rollup.Withdrawals, block.WDelayer.Withdrawals)
871	require.Nil(t, err)
872
873	// Check that delayed withdrawn has been set
874	dbExits, err = historyDB.GetAllExits()
875	require.Nil(t, err)
876	for _, dbExit := range dbExits {
877		dbExitsByIdx[dbExit.AccountIdx] = dbExit
878	}
879	require.Equal(t, &block.Block.Num, dbExitsByIdx[257].DelayedWithdrawn)
880}
881
882func TestGetBestBidCoordinator(t *testing.T) {
883	test.WipeDB(historyDB.DB())
884
885	rollup, auction, wDelayer := exampleInitSCVars()
886	err := historyDB.SetInitialSCVars(rollup, auction, wDelayer)
887	require.Nil(t, err)
888
889	tc := til.NewContext(common.RollupConstMaxL1UserTx)
890	blocks, err := tc.GenerateBlocks(`
891		Type: Blockchain
892		> block // blockNum=2
893	`)
894	require.Nil(t, err)
895	err = historyDB.AddBlockSCData(&blocks[0])
896	require.Nil(t, err)
897
898	coords := []common.Coordinator{
899		{
900			Bidder:      ethCommon.BigToAddress(big.NewInt(1)),
901			Forger:      ethCommon.BigToAddress(big.NewInt(2)),
902			EthBlockNum: 2,
903			URL:         "foo",
904		},
905		{
906			Bidder:      ethCommon.BigToAddress(big.NewInt(3)),
907			Forger:      ethCommon.BigToAddress(big.NewInt(4)),
908			EthBlockNum: 2,
909			URL:         "bar",
910		},
911	}
912	err = historyDB.addCoordinators(historyDB.db, coords)
913	require.Nil(t, err)
914	err = historyDB.addBids(historyDB.db, []common.Bid{
915		{
916			SlotNum:     10,
917			BidValue:    big.NewInt(10),
918			EthBlockNum: 2,
919			Bidder:      coords[0].Bidder,
920		},
921		{
922			SlotNum:     10,
923			BidValue:    big.NewInt(20),
924			EthBlockNum: 2,
925			Bidder:      coords[1].Bidder,
926		},
927	})
928	require.Nil(t, err)
929
930	forger10, err := historyDB.GetBestBidCoordinator(10)
931	require.Nil(t, err)
932	require.Equal(t, coords[1].Forger, forger10.Forger)
933	require.Equal(t, coords[1].Bidder, forger10.Bidder)
934	require.Equal(t, coords[1].URL, forger10.URL)
935
936	_, err = historyDB.GetBestBidCoordinator(11)
937	require.Equal(t, sql.ErrNoRows, tracerr.Unwrap(err))
938}
939
940// setTestBlocks WARNING: this will delete the blocks and recreate them
941func setTestBlocks(from, to int64) []common.Block {
942	test.WipeDB(historyDB.DB())
943	blocks := test.GenBlocks(from, to)
944	if err := historyDB.AddBlocks(blocks); err != nil {
945		panic(err)
946	}
947	return blocks
948}