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	// Fetch tokens
149	fetchedTokens, err := historyDB.GetTokens()
150	assert.NoError(t, err)
151	// Compare fetched tokens vs generated tokens
152	// All the tokens should have USDUpdate setted by the DB trigger
153	for i, token := range fetchedTokens {
154		assert.Equal(t, tokens[i].TokenID, token.TokenID)
155		assert.Equal(t, tokens[i].EthBlockNum, token.EthBlockNum)
156		assert.Equal(t, tokens[i].EthAddr, token.EthAddr)
157		assert.Equal(t, tokens[i].Name, token.Name)
158		assert.Equal(t, tokens[i].Symbol, token.Symbol)
159		assert.Nil(t, token.USD)
160		assert.Nil(t, token.USDUpdate)
161	}
162}
163
164func TestAccounts(t *testing.T) {
165	const fromBlock int64 = 1
166	const toBlock int64 = 5
167	// Prepare blocks in the DB
168	blocks := setTestBlocks(fromBlock, toBlock)
169	// Generate fake tokens
170	const nTokens = 5
171	tokens := test.GenTokens(nTokens, blocks)
172	err := historyDB.AddTokens(tokens)
173	assert.NoError(t, err)
174	// Generate fake batches
175	const nBatches = 10
176	batches := test.GenBatches(nBatches, blocks)
177	err = historyDB.AddBatches(batches)
178	assert.NoError(t, err)
179	// Generate fake accounts
180	const nAccounts = 3
181	accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
182	err = historyDB.AddAccounts(accs)
183	assert.NoError(t, err)
184	// Fetch accounts
185	fetchedAccs, err := historyDB.GetAccounts()
186	assert.NoError(t, err)
187	// Compare fetched accounts vs generated accounts
188	for i, acc := range fetchedAccs {
189		assert.Equal(t, accs[i], acc)
190	}
191}
192
193func TestTxs(t *testing.T) {
194	const fromBlock int64 = 1
195	const toBlock int64 = 5
196	// Prepare blocks in the DB
197	blocks := setTestBlocks(fromBlock, toBlock)
198	// Generate fake tokens
199	const nTokens = 500
200	tokens := test.GenTokens(nTokens, blocks)
201	err := historyDB.AddTokens(tokens)
202	assert.NoError(t, err)
203	// Generate fake batches
204	const nBatches = 10
205	batches := test.GenBatches(nBatches, blocks)
206	err = historyDB.AddBatches(batches)
207	assert.NoError(t, err)
208	// Generate fake accounts
209	const nAccounts = 3
210	accs := test.GenAccounts(nAccounts, 0, tokens, nil, nil, batches)
211	err = historyDB.AddAccounts(accs)
212	assert.NoError(t, err)
213
214	/*
215		Uncomment once the transaction generation is fixed
216		!! Missing tests to check that historic USD is not set if USDUpdate is too old (24h) !!
217
218		// Generate fake L1 txs
219		const nL1s = 64
220		_, l1txs := test.GenL1Txs(256, nL1s, 0, nil, accs, tokens, blocks, batches)
221		err = historyDB.AddL1Txs(l1txs)
222		assert.NoError(t, err)
223		// Generate fake L2 txs
224		const nL2s = 2048 - nL1s
225		_, l2txs := test.GenL2Txs(256, nL2s, 0, nil, accs, tokens, blocks, batches)
226		err = historyDB.AddL2Txs(l2txs)
227		assert.NoError(t, err)
228		// Compare fetched txs vs generated txs.
229		fetchAndAssertTxs(t, l1txs, l2txs)
230		// Test trigger: L1 integrity
231		// from_eth_addr can't be null
232		l1txs[0].FromEthAddr = ethCommon.Address{}
233		err = historyDB.AddL1Txs(l1txs)
234		assert.Error(t, err)
235		l1txs[0].FromEthAddr = ethCommon.BigToAddress(big.NewInt(int64(5)))
236		// from_bjj can't be null
237		l1txs[0].FromBJJ = nil
238		err = historyDB.AddL1Txs(l1txs)
239		assert.Error(t, err)
240		privK := babyjub.NewRandPrivKey()
241		l1txs[0].FromBJJ = privK.Public()
242		// load_amount can't be null
243		l1txs[0].LoadAmount = nil
244		err = historyDB.AddL1Txs(l1txs)
245		assert.Error(t, err)
246		// Test trigger: L2 integrity
247		// batch_num can't be null
248		l2txs[0].BatchNum = 0
249		err = historyDB.AddL2Txs(l2txs)
250		assert.Error(t, err)
251		l2txs[0].BatchNum = 1
252		// nonce can't be null
253		l2txs[0].Nonce = 0
254		err = historyDB.AddL2Txs(l2txs)
255		assert.Error(t, err)
256		// Test trigger: forge L1 txs
257		// add next batch to DB
258		batchNum, toForgeL1TxsNum := test.GetNextToForgeNumAndBatch(batches)
259		batch := batches[0]
260		batch.BatchNum = batchNum
261		batch.ForgeL1TxsNum = toForgeL1TxsNum
262		assert.NoError(t, historyDB.AddBatch(&batch)) // This should update nL1s / 2 rows
263		// Set batch num in txs that should have been marked as forged in the DB
264		for i := 0; i < len(l1txs); i++ {
265			fetchedTx, err := historyDB.GetTx(l1txs[i].TxID)
266			assert.NoError(t, err)
267			if l1txs[i].ToForgeL1TxsNum == toForgeL1TxsNum {
268				assert.Equal(t, batchNum, *fetchedTx.BatchNum)
269			} else {
270				if fetchedTx.BatchNum != nil {
271					assert.NotEqual(t, batchNum, *fetchedTx.BatchNum)
272				}
273			}
274		}
275
276		// Test helper functions for Synchronizer
277		// GetLastTxsPosition
278		expectedPosition := -1
279		var choosenToForgeL1TxsNum int64 = -1
280		for _, tx := range l1txs {
281			if choosenToForgeL1TxsNum == -1 && tx.ToForgeL1TxsNum > 0 {
282				choosenToForgeL1TxsNum = tx.ToForgeL1TxsNum
283				expectedPosition = tx.Position
284			} else if choosenToForgeL1TxsNum == tx.ToForgeL1TxsNum && expectedPosition < tx.Position {
285				expectedPosition = tx.Position
286			}
287		}
288		position, err := historyDB.GetLastTxsPosition(choosenToForgeL1TxsNum)
289		assert.NoError(t, err)
290		assert.Equal(t, expectedPosition, position)
291
292		// GetL1UserTxs: not needed? tests were broken
293		// txs, err := historyDB.GetL1UserTxs(2)
294		// assert.NoError(t, err)
295		// assert.NotZero(t, len(txs))
296		// assert.NoError(t, err)
297		// assert.Equal(t, 22, position)
298		// // Test Update L1 TX Batch_num
299		// assert.Equal(t, common.BatchNum(0), txs[0].BatchNum)
300		// txs[0].BatchNum = common.BatchNum(1)
301		// txs, err = historyDB.GetL1UserTxs(2)
302		// assert.NoError(t, err)
303		// assert.NotZero(t, len(txs))
304		// assert.Equal(t, common.BatchNum(1), txs[0].BatchNum)
305	*/
306}
307
308/*
309func fetchAndAssertTxs(t *testing.T, l1txs []common.L1Tx, l2txs []common.L2Tx) {
310	for i := 0; i < len(l1txs); i++ {
311		tx := l1txs[i].Tx()
312		fmt.Println("ASDF", i, tx.TxID)
313		fetchedTx, err := historyDB.GetTx(tx.TxID)
314		require.NoError(t, err)
315		test.AssertUSD(t, tx.USD, fetchedTx.USD)
316		test.AssertUSD(t, tx.LoadAmountUSD, fetchedTx.LoadAmountUSD)
317		assert.Equal(t, tx, fetchedTx)
318	}
319	for i := 0; i < len(l2txs); i++ {
320		tx := l2txs[i].Tx()
321		fetchedTx, err := historyDB.GetTx(tx.TxID)
322		tx.TokenID = fetchedTx.TokenID
323		assert.NoError(t, err)
324		test.AssertUSD(t, fetchedTx.USD, tx.USD)
325		test.AssertUSD(t, fetchedTx.FeeUSD, tx.FeeUSD)
326		assert.Equal(t, tx, fetchedTx)
327	}
328}
329*/
330
331func TestExitTree(t *testing.T) {
332	nBatches := 17
333	blocks := setTestBlocks(0, 10)
334	batches := test.GenBatches(nBatches, blocks)
335	err := historyDB.AddBatches(batches)
336	assert.NoError(t, err)
337
338	exitTree := test.GenExitTree(nBatches)
339	err = historyDB.AddExitTree(exitTree)
340	assert.NoError(t, err)
341}
342
343// setTestBlocks WARNING: this will delete the blocks and recreate them
344func setTestBlocks(from, to int64) []common.Block {
345	if err := cleanHistoryDB(); err != nil {
346		panic(err)
347	}
348	blocks := test.GenBlocks(from, to)
349	if err := historyDB.AddBlocks(blocks); err != nil {
350		panic(err)
351	}
352	return blocks
353}
354
355func cleanHistoryDB() error {
356	return historyDB.Reorg(-1)
357}