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