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