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