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