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	assert.NoError(t, historyDB.Reorg(fromBlock-1))
 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 := test.GenTokens(nTokens, blocks)
120	err = historyDB.AddTokens(tokens)
121	assert.NoError(t, err)
122	feeBatch := batches[0]
123	feeBatch.BatchNum = 9999
124	feeBatch.CollectedFees = make(map[common.TokenID]*big.Int)
125	var total float64
126	for i, token := range tokens {
127		value := 3.019237 * float64(i)
128		assert.NoError(t, historyDB.UpdateTokenValue(token.Symbol, value))
129		bigAmount := big.NewInt(345000000)
130		feeBatch.CollectedFees[token.TokenID] = bigAmount
131		f := new(big.Float).SetInt(bigAmount)
132		amount, _ := f.Float64()
133		total += value * (amount / math.Pow(10, float64(token.Decimals)))
134	}
135	err = historyDB.AddBatch(&feeBatch)
136	assert.NoError(t, err)
137	fetchedBatches, err = historyDB.GetBatches(feeBatch.BatchNum-1, feeBatch.BatchNum+1)
138	assert.NoError(t, err)
139	for _, fetchedBatch := range fetchedBatches {
140		if fetchedBatch.BatchNum == feeBatch.BatchNum {
141			assert.Equal(t, total, *fetchedBatch.TotalFeesUSD)
142		}
143	}
144}
145
146func TestBids(t *testing.T) {
147	const fromBlock int64 = 1
148	const toBlock int64 = 5
149	// Prepare blocks in the DB
150	blocks := setTestBlocks(fromBlock, toBlock)
151	// Generate fake coordinators
152	const nCoords = 5
153	coords := test.GenCoordinators(nCoords, blocks)
154	err := historyDB.AddCoordinators(coords)
155	assert.NoError(t, err)
156	// Generate fake bids
157	const nBids = 20
158	bids := test.GenBids(nBids, blocks, coords)
159	err = historyDB.AddBids(bids)
160	assert.NoError(t, err)
161	// Fetch bids
162	fetchedBids, err := historyDB.GetBids()
163	assert.NoError(t, err)
164	// Compare fetched bids vs generated bids
165	for i, bid := range fetchedBids {
166		assert.Equal(t, bids[i], bid)
167	}
168}
169
170func TestTokens(t *testing.T) {
171	const fromBlock int64 = 1
172	const toBlock int64 = 5
173	// Prepare blocks in the DB
174	blocks := setTestBlocks(fromBlock, toBlock)
175	// Generate fake tokens
176	const nTokens = 5
177	tokens := test.GenTokens(nTokens, blocks)
178	err := historyDB.AddTokens(tokens)
179	assert.NoError(t, err)
180	limit := uint(10)
181	// Fetch tokens6
182	fetchedTokens, _, err := historyDB.GetTokens(nil, nil, "", nil, &limit, OrderAsc)
183	assert.NoError(t, err)
184	// Compare fetched tokens vs generated tokens
185	// All the tokens should have USDUpdate setted by the DB trigger
186	for i, token := range fetchedTokens {
187		assert.Equal(t, tokens[i].TokenID, token.TokenID)
188		assert.Equal(t, tokens[i].EthBlockNum, token.EthBlockNum)
189		assert.Equal(t, tokens[i].EthAddr, token.EthAddr)
190		assert.Equal(t, tokens[i].Name, token.Name)
191		assert.Equal(t, tokens[i].Symbol, token.Symbol)
192		assert.Nil(t, token.USD)
193		assert.Nil(t, token.USDUpdate)
194	}
195}
196
197func TestAccounts(t *testing.T) {
198	const fromBlock int64 = 1
199	const toBlock int64 = 5
200	// Prepare blocks in the DB
201	blocks := setTestBlocks(fromBlock, toBlock)
202	// Generate fake tokens
203	const nTokens = 5
204	tokens := test.GenTokens(nTokens, blocks)
205	err := historyDB.AddTokens(tokens)
206	assert.NoError(t, err)
207	// Generate fake batches
208	const nBatches = 10
209	batches := test.GenBatches(nBatches, blocks)
210	err = historyDB.AddBatches(batches)
211	assert.NoError(t, err)
212	// Generate fake accounts
213	const nAccounts = 3
214	accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
215	err = historyDB.AddAccounts(accs)
216	assert.NoError(t, err)
217	// Fetch accounts
218	fetchedAccs, err := historyDB.GetAccounts()
219	assert.NoError(t, err)
220	// Compare fetched accounts vs generated accounts
221	for i, acc := range fetchedAccs {
222		accs[i].Balance = nil
223		assert.Equal(t, accs[i], acc)
224	}
225}
226
227func TestTxs(t *testing.T) {
228	const fromBlock int64 = 1
229	const toBlock int64 = 5
230	// Prepare blocks in the DB
231	blocks := setTestBlocks(fromBlock, toBlock)
232	// Generate fake tokens
233	const nTokens = 500
234	tokens := test.GenTokens(nTokens, blocks)
235	err := historyDB.AddTokens(tokens)
236	assert.NoError(t, err)
237	// Generate fake batches
238	const nBatches = 10
239	batches := test.GenBatches(nBatches, blocks)
240	err = historyDB.AddBatches(batches)
241	assert.NoError(t, err)
242	// Generate fake accounts
243	const nAccounts = 3
244	accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
245	err = historyDB.AddAccounts(accs)
246	assert.NoError(t, err)
247
248	/*
249		Uncomment once the transaction generation is fixed
250		!! test that batches that forge user L1s !!
251		!! Missing tests to check that historic USD is not set if USDUpdate is too old (24h) !!
252
253		// Generate fake L1 txs
254		const nL1s = 64
255		_, l1txs := test.GenL1Txs(256, nL1s, 0, nil, accs, tokens, blocks, batches)
256		err = historyDB.AddL1Txs(l1txs)
257		assert.NoError(t, err)
258		// Generate fake L2 txs
259		const nL2s = 2048 - nL1s
260		_, l2txs := test.GenL2Txs(256, nL2s, 0, nil, accs, tokens, blocks, batches)
261		err = historyDB.AddL2Txs(l2txs)
262		assert.NoError(t, err)
263		// Compare fetched txs vs generated txs.
264		fetchAndAssertTxs(t, l1txs, l2txs)
265		// Test trigger: L1 integrity
266		// from_eth_addr can't be null
267		l1txs[0].FromEthAddr = ethCommon.Address{}
268		err = historyDB.AddL1Txs(l1txs)
269		assert.Error(t, err)
270		l1txs[0].FromEthAddr = ethCommon.BigToAddress(big.NewInt(int64(5)))
271		// from_bjj can't be null
272		l1txs[0].FromBJJ = nil
273		err = historyDB.AddL1Txs(l1txs)
274		assert.Error(t, err)
275		privK := babyjub.NewRandPrivKey()
276		l1txs[0].FromBJJ = privK.Public()
277		// load_amount can't be null
278		l1txs[0].LoadAmount = nil
279		err = historyDB.AddL1Txs(l1txs)
280		assert.Error(t, err)
281		// Test trigger: L2 integrity
282		// batch_num can't be null
283		l2txs[0].BatchNum = 0
284		err = historyDB.AddL2Txs(l2txs)
285		assert.Error(t, err)
286		l2txs[0].BatchNum = 1
287		// nonce can't be null
288		l2txs[0].Nonce = 0
289		err = historyDB.AddL2Txs(l2txs)
290		assert.Error(t, err)
291		// Test trigger: forge L1 txs
292		// add next batch to DB
293		batchNum, toForgeL1TxsNum := test.GetNextToForgeNumAndBatch(batches)
294		batch := batches[0]
295		batch.BatchNum = batchNum
296		batch.ForgeL1TxsNum = toForgeL1TxsNum
297		assert.NoError(t, historyDB.AddBatch(&batch)) // This should update nL1s / 2 rows
298		// Set batch num in txs that should have been marked as forged in the DB
299		for i := 0; i < len(l1txs); i++ {
300			fetchedTx, err := historyDB.GetTx(l1txs[i].TxID)
301			assert.NoError(t, err)
302			if l1txs[i].ToForgeL1TxsNum == toForgeL1TxsNum {
303				assert.Equal(t, batchNum, *fetchedTx.BatchNum)
304			} else {
305				if fetchedTx.BatchNum != nil {
306					assert.NotEqual(t, batchNum, *fetchedTx.BatchNum)
307				}
308			}
309		}
310
311		// Test helper functions for Synchronizer
312		// GetLastTxsPosition
313		expectedPosition := -1
314		var choosenToForgeL1TxsNum int64 = -1
315		for _, tx := range l1txs {
316			if choosenToForgeL1TxsNum == -1 && tx.ToForgeL1TxsNum > 0 {
317				choosenToForgeL1TxsNum = tx.ToForgeL1TxsNum
318				expectedPosition = tx.Position
319			} else if choosenToForgeL1TxsNum == tx.ToForgeL1TxsNum && expectedPosition < tx.Position {
320				expectedPosition = tx.Position
321			}
322		}
323		position, err := historyDB.GetLastTxsPosition(choosenToForgeL1TxsNum)
324		assert.NoError(t, err)
325		assert.Equal(t, expectedPosition, position)
326
327		// GetL1UserTxs: not needed? tests were broken
328		// txs, err := historyDB.GetL1UserTxs(2)
329		// assert.NoError(t, err)
330		// assert.NotZero(t, len(txs))
331		// assert.NoError(t, err)
332		// assert.Equal(t, 22, position)
333		// // Test Update L1 TX Batch_num
334		// assert.Equal(t, common.BatchNum(0), txs[0].BatchNum)
335		// txs[0].BatchNum = common.BatchNum(1)
336		// txs, err = historyDB.GetL1UserTxs(2)
337		// assert.NoError(t, err)
338		// assert.NotZero(t, len(txs))
339		// assert.Equal(t, common.BatchNum(1), txs[0].BatchNum)
340	*/
341}
342
343/*
344func fetchAndAssertTxs(t *testing.T, l1txs []common.L1Tx, l2txs []common.L2Tx) {
345	for i := 0; i < len(l1txs); i++ {
346		tx := l1txs[i].Tx()
347		fmt.Println("ASDF", i, tx.TxID)
348		fetchedTx, err := historyDB.GetTx(tx.TxID)
349		require.NoError(t, err)
350		test.AssertUSD(t, tx.USD, fetchedTx.USD)
351		test.AssertUSD(t, tx.LoadAmountUSD, fetchedTx.LoadAmountUSD)
352		assert.Equal(t, tx, fetchedTx)
353	}
354	for i := 0; i < len(l2txs); i++ {
355		tx := l2txs[i].Tx()
356		fetchedTx, err := historyDB.GetTx(tx.TxID)
357		tx.TokenID = fetchedTx.TokenID
358		assert.NoError(t, err)
359		test.AssertUSD(t, fetchedTx.USD, tx.USD)
360		test.AssertUSD(t, fetchedTx.FeeUSD, tx.FeeUSD)
361		assert.Equal(t, tx, fetchedTx)
362	}
363}
364*/
365
366func TestExitTree(t *testing.T) {
367	nBatches := 17
368	blocks := setTestBlocks(0, 10)
369	batches := test.GenBatches(nBatches, blocks)
370	err := historyDB.AddBatches(batches)
371	const nTokens = 50
372	tokens := test.GenTokens(nTokens, blocks)
373	assert.NoError(t, historyDB.AddTokens(tokens))
374	assert.NoError(t, err)
375	const nAccounts = 3
376	accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
377	assert.NoError(t, historyDB.AddAccounts(accs))
378	exitTree := test.GenExitTree(nBatches, batches, accs)
379	err = historyDB.AddExitTree(exitTree)
380	assert.NoError(t, err)
381}
382
383func TestGetL1UserTxs(t *testing.T) {
384	require.NoError(t, cleanHistoryDB())
385
386	set := `
387		Type: Blockchain
388		AddToken(1)
389		AddToken(2)
390		AddToken(3)
391
392		CreateAccountDeposit(1) A: 20
393		CreateAccountDeposit(2) A: 20
394		CreateAccountDeposit(1) B: 5
395		CreateAccountDeposit(1) C: 5
396		CreateAccountDeposit(1) D: 5
397
398		> block
399	`
400	tc := til.NewContext(128)
401	blocks, err := tc.GenerateBlocks(set)
402	require.Nil(t, err)
403	// Sanity check
404	require.Equal(t, 1, len(blocks))
405	require.Equal(t, 5, len(blocks[0].L1UserTxs))
406	// fmt.Printf("DBG Blocks: %+v\n", blocks)
407
408	toForgeL1TxsNum := int64(1)
409
410	for i := range blocks {
411		err = historyDB.AddBlockSCData(&blocks[i])
412		require.Nil(t, err)
413	}
414
415	l1UserTxs, err := historyDB.GetL1UserTxs(toForgeL1TxsNum)
416	require.Nil(t, err)
417	assert.Equal(t, 5, len(l1UserTxs))
418	assert.Equal(t, blocks[0].L1UserTxs, l1UserTxs)
419
420	// No l1UserTxs for this toForgeL1TxsNum
421	l1UserTxs, err = historyDB.GetL1UserTxs(2)
422	require.Nil(t, err)
423	assert.Equal(t, 0, len(l1UserTxs))
424}
425
426// setTestBlocks WARNING: this will delete the blocks and recreate them
427func setTestBlocks(from, to int64) []common.Block {
428	if err := cleanHistoryDB(); err != nil {
429		panic(err)
430	}
431	blocks := test.GenBlocks(from, to)
432	if err := historyDB.AddBlocks(blocks); err != nil {
433		panic(err)
434	}
435	return blocks
436}
437
438func cleanHistoryDB() error {
439	return historyDB.Reorg(-1)
440}