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		accs[i].Balance = nil
221		assert.Equal(t, accs[i], acc)
222	}
223}
224
225func TestTxs(t *testing.T) {
226	const fromBlock int64 = 1
227	const toBlock int64 = 5
228	// Prepare blocks in the DB
229	blocks := setTestBlocks(fromBlock, toBlock)
230	// Generate fake tokens
231	const nTokens = 500
232	tokens := test.GenTokens(nTokens, blocks)
233	err := historyDB.AddTokens(tokens)
234	assert.NoError(t, err)
235	// Generate fake batches
236	const nBatches = 10
237	batches := test.GenBatches(nBatches, blocks)
238	err = historyDB.AddBatches(batches)
239	assert.NoError(t, err)
240	// Generate fake accounts
241	const nAccounts = 3
242	accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
243	err = historyDB.AddAccounts(accs)
244	assert.NoError(t, err)
245
246	/*
247		Uncomment once the transaction generation is fixed
248		!! test that batches that forge user L1s !!
249		!! Missing tests to check that historic USD is not set if USDUpdate is too old (24h) !!
250
251		// Generate fake L1 txs
252		const nL1s = 64
253		_, l1txs := test.GenL1Txs(256, nL1s, 0, nil, accs, tokens, blocks, batches)
254		err = historyDB.AddL1Txs(l1txs)
255		assert.NoError(t, err)
256		// Generate fake L2 txs
257		const nL2s = 2048 - nL1s
258		_, l2txs := test.GenL2Txs(256, nL2s, 0, nil, accs, tokens, blocks, batches)
259		err = historyDB.AddL2Txs(l2txs)
260		assert.NoError(t, err)
261		// Compare fetched txs vs generated txs.
262		fetchAndAssertTxs(t, l1txs, l2txs)
263		// Test trigger: L1 integrity
264		// from_eth_addr can't be null
265		l1txs[0].FromEthAddr = ethCommon.Address{}
266		err = historyDB.AddL1Txs(l1txs)
267		assert.Error(t, err)
268		l1txs[0].FromEthAddr = ethCommon.BigToAddress(big.NewInt(int64(5)))
269		// from_bjj can't be null
270		l1txs[0].FromBJJ = nil
271		err = historyDB.AddL1Txs(l1txs)
272		assert.Error(t, err)
273		privK := babyjub.NewRandPrivKey()
274		l1txs[0].FromBJJ = privK.Public()
275		// load_amount can't be null
276		l1txs[0].LoadAmount = nil
277		err = historyDB.AddL1Txs(l1txs)
278		assert.Error(t, err)
279		// Test trigger: L2 integrity
280		// batch_num can't be null
281		l2txs[0].BatchNum = 0
282		err = historyDB.AddL2Txs(l2txs)
283		assert.Error(t, err)
284		l2txs[0].BatchNum = 1
285		// nonce can't be null
286		l2txs[0].Nonce = 0
287		err = historyDB.AddL2Txs(l2txs)
288		assert.Error(t, err)
289		// Test trigger: forge L1 txs
290		// add next batch to DB
291		batchNum, toForgeL1TxsNum := test.GetNextToForgeNumAndBatch(batches)
292		batch := batches[0]
293		batch.BatchNum = batchNum
294		batch.ForgeL1TxsNum = toForgeL1TxsNum
295		assert.NoError(t, historyDB.AddBatch(&batch)) // This should update nL1s / 2 rows
296		// Set batch num in txs that should have been marked as forged in the DB
297		for i := 0; i < len(l1txs); i++ {
298			fetchedTx, err := historyDB.GetTx(l1txs[i].TxID)
299			assert.NoError(t, err)
300			if l1txs[i].ToForgeL1TxsNum == toForgeL1TxsNum {
301				assert.Equal(t, batchNum, *fetchedTx.BatchNum)
302			} else {
303				if fetchedTx.BatchNum != nil {
304					assert.NotEqual(t, batchNum, *fetchedTx.BatchNum)
305				}
306			}
307		}
308
309		// Test helper functions for Synchronizer
310		// GetLastTxsPosition
311		expectedPosition := -1
312		var choosenToForgeL1TxsNum int64 = -1
313		for _, tx := range l1txs {
314			if choosenToForgeL1TxsNum == -1 && tx.ToForgeL1TxsNum > 0 {
315				choosenToForgeL1TxsNum = tx.ToForgeL1TxsNum
316				expectedPosition = tx.Position
317			} else if choosenToForgeL1TxsNum == tx.ToForgeL1TxsNum && expectedPosition < tx.Position {
318				expectedPosition = tx.Position
319			}
320		}
321		position, err := historyDB.GetLastTxsPosition(choosenToForgeL1TxsNum)
322		assert.NoError(t, err)
323		assert.Equal(t, expectedPosition, position)
324
325		// GetL1UserTxs: not needed? tests were broken
326		// txs, err := historyDB.GetL1UserTxs(2)
327		// assert.NoError(t, err)
328		// assert.NotZero(t, len(txs))
329		// assert.NoError(t, err)
330		// assert.Equal(t, 22, position)
331		// // Test Update L1 TX Batch_num
332		// assert.Equal(t, common.BatchNum(0), txs[0].BatchNum)
333		// txs[0].BatchNum = common.BatchNum(1)
334		// txs, err = historyDB.GetL1UserTxs(2)
335		// assert.NoError(t, err)
336		// assert.NotZero(t, len(txs))
337		// assert.Equal(t, common.BatchNum(1), txs[0].BatchNum)
338	*/
339}
340
341/*
342func fetchAndAssertTxs(t *testing.T, l1txs []common.L1Tx, l2txs []common.L2Tx) {
343	for i := 0; i < len(l1txs); i++ {
344		tx := l1txs[i].Tx()
345		fmt.Println("ASDF", i, tx.TxID)
346		fetchedTx, err := historyDB.GetTx(tx.TxID)
347		require.NoError(t, err)
348		test.AssertUSD(t, tx.USD, fetchedTx.USD)
349		test.AssertUSD(t, tx.LoadAmountUSD, fetchedTx.LoadAmountUSD)
350		assert.Equal(t, tx, fetchedTx)
351	}
352	for i := 0; i < len(l2txs); i++ {
353		tx := l2txs[i].Tx()
354		fetchedTx, err := historyDB.GetTx(tx.TxID)
355		tx.TokenID = fetchedTx.TokenID
356		assert.NoError(t, err)
357		test.AssertUSD(t, fetchedTx.USD, tx.USD)
358		test.AssertUSD(t, fetchedTx.FeeUSD, tx.FeeUSD)
359		assert.Equal(t, tx, fetchedTx)
360	}
361}
362*/
363
364func TestExitTree(t *testing.T) {
365	nBatches := 17
366	blocks := setTestBlocks(0, 10)
367	batches := test.GenBatches(nBatches, blocks)
368	err := historyDB.AddBatches(batches)
369	const nTokens = 50
370	tokens := test.GenTokens(nTokens, blocks)
371	assert.NoError(t, historyDB.AddTokens(tokens))
372	assert.NoError(t, err)
373	const nAccounts = 3
374	accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
375	assert.NoError(t, historyDB.AddAccounts(accs))
376	exitTree := test.GenExitTree(nBatches, batches, accs)
377	err = historyDB.AddExitTree(exitTree)
378	assert.NoError(t, err)
379}
380
381// setTestBlocks WARNING: this will delete the blocks and recreate them
382func setTestBlocks(from, to int64) []common.Block {
383	if err := cleanHistoryDB(); err != nil {
384		panic(err)
385	}
386	blocks := test.GenBlocks(from, to)
387	if err := historyDB.AddBlocks(blocks); err != nil {
388		panic(err)
389	}
390	return blocks
391}
392
393func cleanHistoryDB() error {
394	return historyDB.Reorg(-1)
395}