arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/db/l2db/l2db_test.go
db/l2db/l2db_test.goRaw
  1package l2db
  2
  3import (
  4	"math/big"
  5	"os"
  6	"testing"
  7	"time"
  8
  9	"github.com/hermeznetwork/hermez-node/common"
 10	dbUtils "github.com/hermeznetwork/hermez-node/db"
 11	"github.com/hermeznetwork/hermez-node/db/historydb"
 12	"github.com/hermeznetwork/hermez-node/log"
 13	"github.com/hermeznetwork/hermez-node/test"
 14	"github.com/jmoiron/sqlx"
 15	"github.com/stretchr/testify/assert"
 16)
 17
 18var l2DB *L2DB
 19var tokens []common.Token
 20var tokensUSD []historydb.TokenWithUSD
 21
 22func TestMain(m *testing.M) {
 23	// init DB
 24	pass := os.Getenv("POSTGRES_PASS")
 25	db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
 26	if err != nil {
 27		panic(err)
 28	}
 29	l2DB = NewL2DB(db, 10, 100, 24*time.Hour)
 30	tokens, tokensUSD = prepareHistoryDB(db)
 31	if err != nil {
 32		panic(err)
 33	}
 34	// Run tests
 35	result := m.Run()
 36	// Close DB
 37	if err := db.Close(); err != nil {
 38		log.Error("Error closing the history DB:", err)
 39	}
 40	os.Exit(result)
 41}
 42
 43func prepareHistoryDB(db *sqlx.DB) ([]common.Token, []historydb.TokenWithUSD) {
 44	historyDB := historydb.NewHistoryDB(db)
 45	const fromBlock int64 = 1
 46	const toBlock int64 = 5
 47	// Clean historyDB
 48	if err := historyDB.Reorg(-1); err != nil {
 49		panic(err)
 50	}
 51	// Store blocks to historyDB
 52	blocks := test.GenBlocks(fromBlock, toBlock)
 53	if err := historyDB.AddBlocks(blocks); err != nil {
 54		panic(err)
 55	}
 56	// Store tokens to historyDB
 57	const nTokens = 5
 58	tokens := test.GenTokens(nTokens, blocks)
 59	if err := historyDB.AddTokens(tokens); err != nil {
 60		panic(err)
 61	}
 62	readTokens := []historydb.TokenWithUSD{}
 63	for i, token := range tokens {
 64		readToken := historydb.TokenWithUSD{
 65			TokenID:     token.TokenID,
 66			EthBlockNum: token.EthBlockNum,
 67			EthAddr:     token.EthAddr,
 68			Name:        token.Name,
 69			Symbol:      token.Symbol,
 70			Decimals:    token.Decimals,
 71		}
 72		if i%2 != 0 {
 73			value := float64(i) * 5.4321
 74			if err := historyDB.UpdateTokenValue(token.Symbol, value); err != nil {
 75				panic(err)
 76			}
 77			now := time.Now().UTC()
 78			readToken.USDUpdate = &now
 79			readToken.USD = &value
 80		}
 81		readTokens = append(readTokens, readToken)
 82	}
 83	return tokens, readTokens
 84}
 85
 86func TestAddTxTest(t *testing.T) {
 87	// Gen poolTxs
 88	const nInserts = 20
 89	test.CleanL2DB(l2DB.DB())
 90	txs := test.GenPoolTxs(nInserts, tokens)
 91	for _, tx := range txs {
 92		err := l2DB.AddTxTest(tx)
 93		assert.NoError(t, err)
 94		fetchedTx, err := l2DB.GetTx(tx.TxID)
 95		assert.NoError(t, err)
 96		// assertReadTx(t, commonToRead(tx, tokens), fetchedTx)
 97		assertTx(t, tx, fetchedTx)
 98	}
 99}
100
101func assertTx(t *testing.T, expected, actual *common.PoolL2Tx) {
102	// Check that timestamp has been set within the last 3 seconds
103	assert.Less(t, time.Now().UTC().Unix()-3, actual.Timestamp.Unix())
104	assert.GreaterOrEqual(t, time.Now().UTC().Unix(), actual.Timestamp.Unix())
105	expected.Timestamp = actual.Timestamp
106	// Check absolute fee
107	// find token
108	token := historydb.TokenWithUSD{}
109	for _, tkn := range tokensUSD {
110		if expected.TokenID == tkn.TokenID {
111			token = tkn
112			break
113		}
114	}
115	// If the token has value in USD setted
116	if token.USDUpdate != nil {
117		assert.Equal(t, token.USDUpdate.Unix(), actual.AbsoluteFeeUpdate.Unix())
118		expected.AbsoluteFeeUpdate = actual.AbsoluteFeeUpdate
119		// Set expected fee
120		f := new(big.Float).SetInt(expected.Amount)
121		amountF, _ := f.Float64()
122		expected.AbsoluteFee = *token.USD * amountF * expected.Fee.Percentage()
123		test.AssertUSD(t, &expected.AbsoluteFee, &actual.AbsoluteFee)
124	}
125	assert.Equal(t, expected, actual)
126}
127
128func BenchmarkAddTxTest(b *testing.B) {
129	const nInserts = 20
130	test.CleanL2DB(l2DB.DB())
131	txs := test.GenPoolTxs(nInserts, tokens)
132	now := time.Now()
133	for _, tx := range txs {
134		_ = l2DB.AddTxTest(tx)
135	}
136	elapsedTime := time.Since(now)
137	log.Info("Time to insert 2048 txs:", elapsedTime)
138}
139
140func TestGetPending(t *testing.T) {
141	const nInserts = 20
142	test.CleanL2DB(l2DB.DB())
143	txs := test.GenPoolTxs(nInserts, tokens)
144	var pendingTxs []*common.PoolL2Tx
145	for _, tx := range txs {
146		err := l2DB.AddTxTest(tx)
147		assert.NoError(t, err)
148		if tx.State == common.PoolL2TxStatePending {
149			pendingTxs = append(pendingTxs, tx)
150		}
151	}
152	fetchedTxs, err := l2DB.GetPendingTxs()
153	assert.NoError(t, err)
154	assert.Equal(t, len(pendingTxs), len(fetchedTxs))
155	for i := range fetchedTxs {
156		assertTx(t, pendingTxs[i], &fetchedTxs[i])
157	}
158}
159
160/*
161	WARNING: this should be fixed once transaktio is ready
162func TestStartForging(t *testing.T) {
163	// Generate txs
164	const nInserts = 60
165	const fakeBatchNum common.BatchNum = 33
166	test.CleanL2DB(l2DB.DB())
167	txs := test.GenPoolTxs(nInserts, tokens)
168	var startForgingTxIDs []common.TxID
169	randomizer := 0
170	// Add txs to DB
171	for _, tx := range txs {
172		err := l2DB.AddTxTest(tx)
173		assert.NoError(t, err)
174		if tx.State == common.PoolL2TxStatePending && randomizer%2 == 0 {
175			randomizer++
176			startForgingTxIDs = append(startForgingTxIDs, tx.TxID)
177		}
178	}
179	// Start forging txs
180	err := l2DB.StartForging(startForgingTxIDs, fakeBatchNum)
181	assert.NoError(t, err)
182	// Fetch txs and check that they've been updated correctly
183	for _, id := range startForgingTxIDs {
184		fetchedTx, err := l2DB.GetTx(id)
185		assert.NoError(t, err)
186		assert.Equal(t, common.PoolL2TxStateForging, fetchedTx.State)
187		assert.Equal(t, fakeBatchNum, *fetchedTx.BatchNum)
188	}
189}
190*/
191
192/*
193	WARNING: this should be fixed once transaktio is ready
194func TestDoneForging(t *testing.T) {
195	// Generate txs
196	const nInserts = 60
197	const fakeBatchNum common.BatchNum = 33
198	test.CleanL2DB(l2DB.DB())
199	txs := test.GenPoolTxs(nInserts, tokens)
200	var doneForgingTxIDs []common.TxID
201	randomizer := 0
202	// Add txs to DB
203	for _, tx := range txs {
204		err := l2DB.AddTxTest(tx)
205		assert.NoError(t, err)
206		if tx.State == common.PoolL2TxStateForging && randomizer%2 == 0 {
207			randomizer++
208			doneForgingTxIDs = append(doneForgingTxIDs, tx.TxID)
209		}
210	}
211	// Start forging txs
212	err := l2DB.DoneForging(doneForgingTxIDs, fakeBatchNum)
213	assert.NoError(t, err)
214	// Fetch txs and check that they've been updated correctly
215	for _, id := range doneForgingTxIDs {
216		fetchedTx, err := l2DB.GetTx(id)
217		assert.NoError(t, err)
218		assert.Equal(t, common.PoolL2TxStateForged, fetchedTx.State)
219		assert.Equal(t, fakeBatchNum, *fetchedTx.BatchNum)
220	}
221}
222*/
223
224/*
225	WARNING: this should be fixed once transaktio is ready
226func TestInvalidate(t *testing.T) {
227	// Generate txs
228	const nInserts = 60
229	const fakeBatchNum common.BatchNum = 33
230	test.CleanL2DB(l2DB.DB())
231	txs := test.GenPoolTxs(nInserts, tokens)
232	var invalidTxIDs []common.TxID
233	randomizer := 0
234	// Add txs to DB
235	for _, tx := range txs {
236		err := l2DB.AddTxTest(tx)
237		assert.NoError(t, err)
238		if tx.State != common.PoolL2TxStateInvalid && randomizer%2 == 0 {
239			randomizer++
240			invalidTxIDs = append(invalidTxIDs, tx.TxID)
241		}
242	}
243	// Start forging txs
244	err := l2DB.InvalidateTxs(invalidTxIDs, fakeBatchNum)
245	assert.NoError(t, err)
246	// Fetch txs and check that they've been updated correctly
247	for _, id := range invalidTxIDs {
248		fetchedTx, err := l2DB.GetTx(id)
249		assert.NoError(t, err)
250		assert.Equal(t, common.PoolL2TxStateInvalid, fetchedTx.State)
251		assert.Equal(t, fakeBatchNum, *fetchedTx.BatchNum)
252	}
253}
254*/
255
256/*
257	WARNING: this should be fixed once transaktio is ready
258func TestCheckNonces(t *testing.T) {
259	// Generate txs
260	const nInserts = 60
261	const fakeBatchNum common.BatchNum = 33
262	test.CleanL2DB(l2DB.DB())
263	txs := test.GenPoolTxs(nInserts, tokens)
264	var invalidTxIDs []common.TxID
265	// Generate accounts
266	const nAccoutns = 2
267	const currentNonce = 2
268	accs := []common.Account{}
269	for i := 0; i < nAccoutns; i++ {
270		accs = append(accs, common.Account{
271			Idx:   common.Idx(i),
272			Nonce: currentNonce,
273		})
274	}
275	// Add txs to DB
276	for i := 0; i < len(txs); i++ {
277		if txs[i].State != common.PoolL2TxStateInvalid {
278			if i%2 == 0 { // Ensure transaction will be marked as invalid due to old nonce
279				txs[i].Nonce = accs[i%len(accs)].Nonce
280				txs[i].FromIdx = accs[i%len(accs)].Idx
281				invalidTxIDs = append(invalidTxIDs, txs[i].TxID)
282			} else { // Ensure transaction will NOT be marked as invalid due to old nonce
283				txs[i].Nonce = currentNonce + 1
284			}
285		}
286		err := l2DB.AddTxTest(txs[i])
287		assert.NoError(t, err)
288	}
289	// Start forging txs
290	err := l2DB.InvalidateTxs(invalidTxIDs, fakeBatchNum)
291	assert.NoError(t, err)
292	// Fetch txs and check that they've been updated correctly
293	for _, id := range invalidTxIDs {
294		fetchedTx, err := l2DB.GetTx(id)
295		assert.NoError(t, err)
296		assert.Equal(t, common.PoolL2TxStateInvalid, fetchedTx.State)
297		assert.Equal(t, fakeBatchNum, *fetchedTx.BatchNum)
298	}
299}
300*/
301
302func TestReorg(t *testing.T) {
303	// Generate txs
304	const nInserts = 20
305	const lastValidBatch common.BatchNum = 20
306	const reorgBatch common.BatchNum = lastValidBatch + 1
307	test.CleanL2DB(l2DB.DB())
308	txs := test.GenPoolTxs(nInserts, tokens)
309	// Add txs to the DB
310	reorgedTxIDs := []common.TxID{}
311	nonReorgedTxIDs := []common.TxID{}
312	for i := 0; i < len(txs); i++ {
313		err := l2DB.AddTxTest(txs[i])
314		assert.NoError(t, err)
315		var batchNum common.BatchNum
316		if txs[i].State == common.PoolL2TxStateForged || txs[i].State == common.PoolL2TxStateInvalid {
317			reorgedTxIDs = append(reorgedTxIDs, txs[i].TxID)
318			batchNum = reorgBatch
319		} else {
320			nonReorgedTxIDs = append(nonReorgedTxIDs, txs[i].TxID)
321			batchNum = lastValidBatch
322		}
323		_, err = l2DB.db.Exec(
324			"UPDATE tx_pool SET batch_num = $1 WHERE tx_id = $2;",
325			batchNum, txs[i].TxID,
326		)
327		assert.NoError(t, err)
328	}
329	err := l2DB.Reorg(lastValidBatch)
330	assert.NoError(t, err)
331	for _, id := range reorgedTxIDs {
332		tx, err := l2DB.GetTxAPI(id)
333		assert.NoError(t, err)
334		assert.Nil(t, tx.BatchNum)
335		assert.Equal(t, common.PoolL2TxStatePending, tx.State)
336	}
337	for _, id := range nonReorgedTxIDs {
338		fetchedTx, err := l2DB.GetTxAPI(id)
339		assert.NoError(t, err)
340		assert.Equal(t, lastValidBatch, *fetchedTx.BatchNum)
341	}
342}
343
344func TestPurge(t *testing.T) {
345	/*
346		WARNING: this should be fixed once transaktio is ready
347		// Generate txs
348		nInserts := l2DB.maxTxs + 20
349		test.CleanL2DB(l2DB.DB())
350		txs := test.GenPoolTxs(int(nInserts), tokens)
351		deletedIDs := []common.TxID{}
352		keepedIDs := []common.TxID{}
353		const toDeleteBatchNum common.BatchNum = 30
354		safeBatchNum := toDeleteBatchNum + l2DB.safetyPeriod + 1
355		// Add txs to the DB
356		for i := 0; i < int(l2DB.maxTxs); i++ {
357			var batchNum common.BatchNum
358			if i%2 == 0 { // keep tx
359				batchNum = safeBatchNum
360				keepedIDs = append(keepedIDs, txs[i].TxID)
361			} else { // delete after safety period
362				batchNum = toDeleteBatchNum
363				if i%3 == 0 {
364					txs[i].State = common.PoolL2TxStateForged
365				} else {
366					txs[i].State = common.PoolL2TxStateInvalid
367				}
368				deletedIDs = append(deletedIDs, txs[i].TxID)
369			}
370			err := l2DB.AddTxTest(txs[i])
371			assert.NoError(t, err)
372			// Set batchNum
373			_, err = l2DB.db.Exec(
374				"UPDATE tx_pool SET batch_num = $1 WHERE tx_id = $2;",
375				batchNum, txs[i].TxID,
376			)
377			assert.NoError(t, err)
378		}
379		for i := int(l2DB.maxTxs); i < len(txs); i++ {
380			// Delete after TTL
381			deletedIDs = append(deletedIDs, txs[i].TxID)
382			err := l2DB.AddTxTest(txs[i])
383			assert.NoError(t, err)
384			// Set timestamp
385			deleteTimestamp := time.Unix(time.Now().UTC().Unix()-int64(l2DB.ttl.Seconds()+float64(4*time.Second)), 0)
386			_, err = l2DB.db.Exec(
387				"UPDATE tx_pool SET timestamp = $1 WHERE tx_id = $2;",
388				deleteTimestamp, txs[i].TxID,
389			)
390			assert.NoError(t, err)
391		}
392		// Purge txs
393		err := l2DB.Purge(safeBatchNum)
394		assert.NoError(t, err)
395		// Check results
396		for _, id := range deletedIDs {
397			tx, err := l2DB.GetTx(id)
398			if err == nil {
399				log.Debug(tx)
400			}
401			assert.Error(t, err)
402		}
403		for _, id := range keepedIDs {
404			_, err := l2DB.GetTx(id)
405			assert.NoError(t, err)
406		}
407	*/
408}
409
410func TestAuth(t *testing.T) {
411	test.CleanL2DB(l2DB.DB())
412	const nAuths = 5
413	// Generate authorizations
414	auths := test.GenAuths(nAuths)
415	for i := 0; i < len(auths); i++ {
416		// Add to the DB
417		err := l2DB.AddAccountCreationAuth(auths[i])
418		assert.NoError(t, err)
419		// Fetch from DB
420		auth, err := l2DB.GetAccountCreationAuth(auths[i].EthAddr)
421		assert.NoError(t, err)
422		// Check fetched vs generated
423		assert.Equal(t, auths[i].EthAddr, auth.EthAddr)
424		assert.Equal(t, auths[i].BJJ, auth.BJJ)
425		assert.Equal(t, auths[i].Signature, auth.Signature)
426		assert.Equal(t, auths[i].Timestamp.Unix(), auths[i].Timestamp.Unix())
427	}
428}