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