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