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
 10	ethCommon "github.com/ethereum/go-ethereum/common"
 11	"github.com/hermeznetwork/hermez-node/common"
 12	dbUtils "github.com/hermeznetwork/hermez-node/db"
 13	"github.com/hermeznetwork/hermez-node/log"
 14	"github.com/hermeznetwork/hermez-node/test"
 15	"github.com/hermeznetwork/hermez-node/test/til"
 16	"github.com/stretchr/testify/assert"
 17	"github.com/stretchr/testify/require"
 18)
 19
 20var historyDB *HistoryDB
 21
 22// In order to run the test you need to run a Posgres DB with
 23// a database named "history" that is accessible by
 24// user: "hermez"
 25// pass: set it using the env var POSTGRES_PASS
 26// 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;"
 27// After running the test you can stop the container by running: sudo docker kill hermez-db-test
 28// If you already did that for the L2DB you don't have to do it again
 29
 30func TestMain(m *testing.M) {
 31	// init DB
 32	pass := os.Getenv("POSTGRES_PASS")
 33	db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
 34	if err != nil {
 35		panic(err)
 36	}
 37	historyDB = NewHistoryDB(db)
 38	if err != nil {
 39		panic(err)
 40	}
 41	// Run tests
 42	result := m.Run()
 43	// Close DB
 44	if err := db.Close(); err != nil {
 45		log.Error("Error closing the history DB:", err)
 46	}
 47	os.Exit(result)
 48}
 49
 50func TestBlocks(t *testing.T) {
 51	var fromBlock, toBlock int64
 52	fromBlock = 1
 53	toBlock = 5
 54	// Delete peviously created rows (clean previous test execs)
 55	test.WipeDB(historyDB.DB())
 56	// Generate fake blocks
 57	blocks := test.GenBlocks(fromBlock, toBlock)
 58	// Insert blocks into DB
 59	for i := 0; i < len(blocks); i++ {
 60		err := historyDB.AddBlock(&blocks[i])
 61		assert.NoError(t, err)
 62	}
 63	// Get all blocks from DB
 64	fetchedBlocks, err := historyDB.GetBlocks(fromBlock, toBlock)
 65	assert.Equal(t, len(blocks), len(fetchedBlocks))
 66	// Compare generated vs getted blocks
 67	assert.NoError(t, err)
 68	for i := range fetchedBlocks {
 69		assertEqualBlock(t, &blocks[i], &fetchedBlocks[i])
 70	}
 71	// Get blocks from the DB one by one
 72	for i := fromBlock; i < toBlock; i++ {
 73		fetchedBlock, err := historyDB.GetBlock(i)
 74		assert.NoError(t, err)
 75		assertEqualBlock(t, &blocks[i-1], fetchedBlock)
 76	}
 77	// Get last block
 78	lastBlock, err := historyDB.GetLastBlock()
 79	assert.NoError(t, err)
 80	assertEqualBlock(t, &blocks[len(blocks)-1], lastBlock)
 81}
 82
 83func assertEqualBlock(t *testing.T, expected *common.Block, actual *common.Block) {
 84	assert.Equal(t, expected.EthBlockNum, actual.EthBlockNum)
 85	assert.Equal(t, expected.Hash, actual.Hash)
 86	assert.Equal(t, expected.Timestamp.Unix(), actual.Timestamp.Unix())
 87}
 88
 89func TestBatches(t *testing.T) {
 90	const fromBlock int64 = 1
 91	const toBlock int64 = 3
 92	// Prepare blocks in the DB
 93	blocks := setTestBlocks(fromBlock, toBlock)
 94	// Generate fake batches
 95	const nBatches = 9
 96	batches := test.GenBatches(nBatches, blocks)
 97	// Test GetLastL1TxsNum with no batches
 98	fetchedLastL1TxsNum, err := historyDB.GetLastL1TxsNum()
 99	assert.NoError(t, err)
100	assert.Nil(t, fetchedLastL1TxsNum)
101	// Add batches to the DB
102	err = historyDB.AddBatches(batches)
103	assert.NoError(t, err)
104	// Get batches from the DB
105	fetchedBatches, err := historyDB.GetBatches(0, common.BatchNum(nBatches))
106	assert.NoError(t, err)
107	for i, fetchedBatch := range fetchedBatches {
108		assert.Equal(t, batches[i], fetchedBatch)
109	}
110	// Test GetLastBatchNum
111	fetchedLastBatchNum, err := historyDB.GetLastBatchNum()
112	assert.NoError(t, err)
113	assert.Equal(t, batches[len(batches)-1].BatchNum, fetchedLastBatchNum)
114	// Test GetLastL1TxsNum
115	fetchedLastL1TxsNum, err = historyDB.GetLastL1TxsNum()
116	assert.NoError(t, err)
117	assert.Equal(t, *batches[nBatches-1].ForgeL1TxsNum, *fetchedLastL1TxsNum)
118	// Test total fee
119	// Generate fake tokens
120	const nTokens = 5
121	tokens, ethToken := test.GenTokens(nTokens, blocks)
122	err = historyDB.AddTokens(tokens)
123	assert.NoError(t, err)
124	tokens = append([]common.Token{ethToken}, tokens...)
125	feeBatch := batches[0]
126	feeBatch.BatchNum = 9999
127	feeBatch.CollectedFees = make(map[common.TokenID]*big.Int)
128	var total float64
129	for i, token := range tokens {
130		value := 3.019237 * float64(i)
131		assert.NoError(t, historyDB.UpdateTokenValue(token.Symbol, value))
132		bigAmount := big.NewInt(345000000)
133		feeBatch.CollectedFees[token.TokenID] = bigAmount
134		f := new(big.Float).SetInt(bigAmount)
135		amount, _ := f.Float64()
136		total += value * (amount / math.Pow(10, float64(token.Decimals)))
137	}
138	err = historyDB.AddBatch(&feeBatch)
139	assert.NoError(t, err)
140	fetchedBatches, err = historyDB.GetBatches(feeBatch.BatchNum-1, feeBatch.BatchNum+1)
141	assert.NoError(t, err)
142	for _, fetchedBatch := range fetchedBatches {
143		if fetchedBatch.BatchNum == feeBatch.BatchNum {
144			assert.Equal(t, total, *fetchedBatch.TotalFeesUSD)
145		}
146	}
147}
148
149func TestBids(t *testing.T) {
150	const fromBlock int64 = 1
151	const toBlock int64 = 5
152	// Prepare blocks in the DB
153	blocks := setTestBlocks(fromBlock, toBlock)
154	// Generate fake coordinators
155	const nCoords = 5
156	coords := test.GenCoordinators(nCoords, blocks)
157	err := historyDB.AddCoordinators(coords)
158	assert.NoError(t, err)
159	// Generate fake bids
160	const nBids = 20
161	bids := test.GenBids(nBids, blocks, coords)
162	err = historyDB.AddBids(bids)
163	assert.NoError(t, err)
164	// Fetch bids
165	fetchedBids, err := historyDB.GetAllBids()
166	assert.NoError(t, err)
167	// Compare fetched bids vs generated bids
168	for i, bid := range fetchedBids {
169		assert.Equal(t, bids[i], bid)
170	}
171}
172
173func TestTokens(t *testing.T) {
174	const fromBlock int64 = 1
175	const toBlock int64 = 5
176	// Prepare blocks in the DB
177	blocks := setTestBlocks(fromBlock, toBlock)
178	// Generate fake tokens
179	const nTokens = 5
180	tokens, ethToken := test.GenTokens(nTokens, blocks)
181	err := historyDB.AddTokens(tokens)
182	assert.NoError(t, err)
183	tokens = append([]common.Token{ethToken}, tokens...)
184	limit := uint(10)
185	// Fetch tokens6
186	fetchedTokens, _, err := historyDB.GetTokens(nil, nil, "", nil, &limit, OrderAsc)
187	assert.NoError(t, err)
188	// Compare fetched tokens vs generated tokens
189	// All the tokens should have USDUpdate setted by the DB trigger
190	for i, token := range fetchedTokens {
191		assert.Equal(t, tokens[i].TokenID, token.TokenID)
192		assert.Equal(t, tokens[i].EthBlockNum, token.EthBlockNum)
193		assert.Equal(t, tokens[i].EthAddr, token.EthAddr)
194		assert.Equal(t, tokens[i].Name, token.Name)
195		assert.Equal(t, tokens[i].Symbol, token.Symbol)
196		assert.Nil(t, token.USD)
197		assert.Nil(t, token.USDUpdate)
198	}
199}
200
201func TestAccounts(t *testing.T) {
202	const fromBlock int64 = 1
203	const toBlock int64 = 5
204	// Prepare blocks in the DB
205	blocks := setTestBlocks(fromBlock, toBlock)
206	// Generate fake tokens
207	const nTokens = 5
208	tokens, ethToken := test.GenTokens(nTokens, blocks)
209	err := historyDB.AddTokens(tokens)
210	assert.NoError(t, err)
211	tokens = append([]common.Token{ethToken}, tokens...)
212	// Generate fake batches
213	const nBatches = 10
214	batches := test.GenBatches(nBatches, blocks)
215	err = historyDB.AddBatches(batches)
216	assert.NoError(t, err)
217	// Generate fake accounts
218	const nAccounts = 3
219	accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
220	err = historyDB.AddAccounts(accs)
221	assert.NoError(t, err)
222	// Fetch accounts
223	fetchedAccs, err := historyDB.GetAccounts()
224	assert.NoError(t, err)
225	// Compare fetched accounts vs generated accounts
226	for i, acc := range fetchedAccs {
227		accs[i].Balance = nil
228		assert.Equal(t, accs[i], acc)
229	}
230}
231
232func TestTxs(t *testing.T) {
233	const fromBlock int64 = 1
234	const toBlock int64 = 5
235	// Prepare blocks in the DB
236	blocks := setTestBlocks(fromBlock, toBlock)
237	// Generate fake tokens
238	const nTokens = 500
239	tokens, ethToken := test.GenTokens(nTokens, blocks)
240	err := historyDB.AddTokens(tokens)
241	assert.NoError(t, err)
242	tokens = append([]common.Token{ethToken}, tokens...)
243	// Generate fake batches
244	const nBatches = 10
245	batches := test.GenBatches(nBatches, blocks)
246	err = historyDB.AddBatches(batches)
247	assert.NoError(t, err)
248	// Generate fake accounts
249	const nAccounts = 3
250	accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
251	err = historyDB.AddAccounts(accs)
252	assert.NoError(t, err)
253
254	/*
255		Uncomment once the transaction generation is fixed
256		!! test that batches that forge user L1s !!
257		!! Missing tests to check that historic USD is not set if USDUpdate is too old (24h) !!
258
259		// Generate fake L1 txs
260		const nL1s = 64
261		_, l1txs := test.GenL1Txs(256, nL1s, 0, nil, accs, tokens, blocks, batches)
262		err = historyDB.AddL1Txs(l1txs)
263		assert.NoError(t, err)
264		// Generate fake L2 txs
265		const nL2s = 2048 - nL1s
266		_, l2txs := test.GenL2Txs(256, nL2s, 0, nil, accs, tokens, blocks, batches)
267		err = historyDB.AddL2Txs(l2txs)
268		assert.NoError(t, err)
269		// Compare fetched txs vs generated txs.
270		fetchAndAssertTxs(t, l1txs, l2txs)
271		// Test trigger: L1 integrity
272		// from_eth_addr can't be null
273		l1txs[0].FromEthAddr = ethCommon.Address{}
274		err = historyDB.AddL1Txs(l1txs)
275		assert.Error(t, err)
276		l1txs[0].FromEthAddr = ethCommon.BigToAddress(big.NewInt(int64(5)))
277		// from_bjj can't be null
278		l1txs[0].FromBJJ = nil
279		err = historyDB.AddL1Txs(l1txs)
280		assert.Error(t, err)
281		privK := babyjub.NewRandPrivKey()
282		l1txs[0].FromBJJ = privK.Public()
283		// load_amount can't be null
284		l1txs[0].LoadAmount = nil
285		err = historyDB.AddL1Txs(l1txs)
286		assert.Error(t, err)
287		// Test trigger: L2 integrity
288		// batch_num can't be null
289		l2txs[0].BatchNum = 0
290		err = historyDB.AddL2Txs(l2txs)
291		assert.Error(t, err)
292		l2txs[0].BatchNum = 1
293		// nonce can't be null
294		l2txs[0].Nonce = 0
295		err = historyDB.AddL2Txs(l2txs)
296		assert.Error(t, err)
297		// Test trigger: forge L1 txs
298		// add next batch to DB
299		batchNum, toForgeL1TxsNum := test.GetNextToForgeNumAndBatch(batches)
300		batch := batches[0]
301		batch.BatchNum = batchNum
302		batch.ForgeL1TxsNum = toForgeL1TxsNum
303		assert.NoError(t, historyDB.AddBatch(&batch)) // This should update nL1s / 2 rows
304		// Set batch num in txs that should have been marked as forged in the DB
305		for i := 0; i < len(l1txs); i++ {
306			fetchedTx, err := historyDB.GetTx(l1txs[i].TxID)
307			assert.NoError(t, err)
308			if l1txs[i].ToForgeL1TxsNum == toForgeL1TxsNum {
309				assert.Equal(t, batchNum, *fetchedTx.BatchNum)
310			} else {
311				if fetchedTx.BatchNum != nil {
312					assert.NotEqual(t, batchNum, *fetchedTx.BatchNum)
313				}
314			}
315		}
316
317		// Test helper functions for Synchronizer
318		// GetLastTxsPosition
319		expectedPosition := -1
320		var choosenToForgeL1TxsNum int64 = -1
321		for _, tx := range l1txs {
322			if choosenToForgeL1TxsNum == -1 && tx.ToForgeL1TxsNum > 0 {
323				choosenToForgeL1TxsNum = tx.ToForgeL1TxsNum
324				expectedPosition = tx.Position
325			} else if choosenToForgeL1TxsNum == tx.ToForgeL1TxsNum && expectedPosition < tx.Position {
326				expectedPosition = tx.Position
327			}
328		}
329		position, err := historyDB.GetLastTxsPosition(choosenToForgeL1TxsNum)
330		assert.NoError(t, err)
331		assert.Equal(t, expectedPosition, position)
332
333		// GetL1UserTxs: not needed? tests were broken
334		// txs, err := historyDB.GetL1UserTxs(2)
335		// assert.NoError(t, err)
336		// assert.NotZero(t, len(txs))
337		// assert.NoError(t, err)
338		// assert.Equal(t, 22, position)
339		// // Test Update L1 TX Batch_num
340		// assert.Equal(t, common.BatchNum(0), txs[0].BatchNum)
341		// txs[0].BatchNum = common.BatchNum(1)
342		// txs, err = historyDB.GetL1UserTxs(2)
343		// assert.NoError(t, err)
344		// assert.NotZero(t, len(txs))
345		// assert.Equal(t, common.BatchNum(1), txs[0].BatchNum)
346	*/
347}
348
349/*
350func fetchAndAssertTxs(t *testing.T, l1txs []common.L1Tx, l2txs []common.L2Tx) {
351	for i := 0; i < len(l1txs); i++ {
352		tx := l1txs[i].Tx()
353		fmt.Println("ASDF", i, tx.TxID)
354		fetchedTx, err := historyDB.GetTx(tx.TxID)
355		require.NoError(t, err)
356		test.AssertUSD(t, tx.USD, fetchedTx.USD)
357		test.AssertUSD(t, tx.LoadAmountUSD, fetchedTx.LoadAmountUSD)
358		assert.Equal(t, tx, fetchedTx)
359	}
360	for i := 0; i < len(l2txs); i++ {
361		tx := l2txs[i].Tx()
362		fetchedTx, err := historyDB.GetTx(tx.TxID)
363		tx.TokenID = fetchedTx.TokenID
364		assert.NoError(t, err)
365		test.AssertUSD(t, fetchedTx.USD, tx.USD)
366		test.AssertUSD(t, fetchedTx.FeeUSD, tx.FeeUSD)
367		assert.Equal(t, tx, fetchedTx)
368	}
369}
370*/
371
372func TestExitTree(t *testing.T) {
373	nBatches := 17
374	blocks := setTestBlocks(1, 10)
375	batches := test.GenBatches(nBatches, blocks)
376	err := historyDB.AddBatches(batches)
377	assert.NoError(t, err)
378	const nTokens = 50
379	tokens, ethToken := test.GenTokens(nTokens, blocks)
380	err = historyDB.AddTokens(tokens)
381	assert.NoError(t, err)
382	tokens = append([]common.Token{ethToken}, tokens...)
383	const nAccounts = 3
384	accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
385	assert.NoError(t, historyDB.AddAccounts(accs))
386	exitTree := test.GenExitTree(nBatches, batches, accs)
387	err = historyDB.AddExitTree(exitTree)
388	assert.NoError(t, err)
389}
390
391func TestGetL1UserTxs(t *testing.T) {
392	test.WipeDB(historyDB.DB())
393
394	set := `
395		Type: Blockchain
396		AddToken(1)
397		AddToken(2)
398		AddToken(3)
399
400		CreateAccountDeposit(1) A: 20
401		CreateAccountDeposit(2) A: 20
402		CreateAccountDeposit(1) B: 5
403		CreateAccountDeposit(1) C: 5
404		CreateAccountDeposit(1) D: 5
405
406		> block
407	`
408	tc := til.NewContext(128)
409	blocks, err := tc.GenerateBlocks(set)
410	require.Nil(t, err)
411	// Sanity check
412	require.Equal(t, 1, len(blocks))
413	require.Equal(t, 5, len(blocks[0].Rollup.L1UserTxs))
414	// fmt.Printf("DBG Blocks: %+v\n", blocks)
415
416	toForgeL1TxsNum := int64(1)
417
418	for i := range blocks {
419		err = historyDB.AddBlockSCData(&blocks[i])
420		require.Nil(t, err)
421	}
422
423	l1UserTxs, err := historyDB.GetL1UserTxs(toForgeL1TxsNum)
424	require.Nil(t, err)
425	assert.Equal(t, 5, len(l1UserTxs))
426	assert.Equal(t, blocks[0].Rollup.L1UserTxs, l1UserTxs)
427
428	// No l1UserTxs for this toForgeL1TxsNum
429	l1UserTxs, err = historyDB.GetL1UserTxs(2)
430	require.Nil(t, err)
431	assert.Equal(t, 0, len(l1UserTxs))
432}
433
434func TestSetInitialSCVars(t *testing.T) {
435	test.WipeDB(historyDB.DB())
436	_, _, _, err := historyDB.GetSCVars()
437	assert.Equal(t, sql.ErrNoRows, err)
438
439	//nolint:govet
440	rollup := &common.RollupVariables{
441		0,
442		big.NewInt(10),
443		12,
444		13,
445	}
446	//nolint:govet
447	auction := &common.AuctionVariables{
448		0,
449		ethCommon.BigToAddress(big.NewInt(2)),
450		ethCommon.BigToAddress(big.NewInt(3)),
451		[6]*big.Int{
452			big.NewInt(1), big.NewInt(2), big.NewInt(3),
453			big.NewInt(4), big.NewInt(5), big.NewInt(6),
454		},
455		2,
456		4320,
457		[3]uint16{10, 11, 12},
458		1000,
459		20,
460	}
461	//nolint:govet
462	wDelayer := &common.WDelayerVariables{
463		0,
464		ethCommon.BigToAddress(big.NewInt(2)),
465		ethCommon.BigToAddress(big.NewInt(3)),
466		ethCommon.BigToAddress(big.NewInt(4)),
467		13,
468		14,
469		false,
470	}
471	err = historyDB.SetInitialSCVars(rollup, auction, wDelayer)
472	require.Nil(t, err)
473	dbRollup, dbAuction, dbWDelayer, err := historyDB.GetSCVars()
474	assert.Nil(t, err)
475	require.Equal(t, rollup, dbRollup)
476	require.Equal(t, auction, dbAuction)
477	require.Equal(t, wDelayer, dbWDelayer)
478}
479
480// setTestBlocks WARNING: this will delete the blocks and recreate them
481func setTestBlocks(from, to int64) []common.Block {
482	test.WipeDB(historyDB.DB())
483	blocks := test.GenBlocks(from, to)
484	if err := historyDB.AddBlocks(blocks); err != nil {
485		panic(err)
486	}
487	return blocks
488}