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