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