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