arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/db/l2db/l2db_test.go
db/l2db/l2db_test.goRaw
  1package l2db
  2
  3import (
  4	"fmt"
  5	"math"
  6	"os"
  7	"testing"
  8	"time"
  9
 10	"github.com/hermeznetwork/hermez-node/common"
 11	"github.com/hermeznetwork/hermez-node/log"
 12	"github.com/hermeznetwork/hermez-node/test"
 13	"github.com/stretchr/testify/assert"
 14)
 15
 16var l2DB *L2DB
 17
 18func TestMain(m *testing.M) {
 19	// init DB
 20	var err error
 21	pass := os.Getenv("POSTGRES_PASS")
 22	l2DB, err = NewL2DB(5432, "localhost", "hermez", pass, "l2", 10, 100, 24*time.Hour)
 23	if err != nil {
 24		log.Error("L2DB migration failed: " + err.Error())
 25		panic(err)
 26	} else {
 27		log.Debug("L2DB migration succed")
 28	}
 29	// Run tests
 30	result := m.Run()
 31	// Close DB
 32	if err := l2DB.Close(); err != nil {
 33		fmt.Println("Error closing the history DB:", err)
 34	}
 35	os.Exit(result)
 36}
 37
 38func TestAddTx(t *testing.T) {
 39	const nInserts = 20
 40	test.CleanL2DB(l2DB.DB())
 41	txs := test.GenPoolTxs(nInserts)
 42	for _, tx := range txs {
 43		err := l2DB.AddTx(tx)
 44		assert.NoError(t, err)
 45		fetchedTx, err := l2DB.GetTx(tx.TxID)
 46		assert.NoError(t, err)
 47		assert.Equal(t, tx.Timestamp.Unix(), fetchedTx.Timestamp.Unix())
 48		tx.Timestamp = fetchedTx.Timestamp
 49		assert.Equal(t, tx.AbsoluteFeeUpdate.Unix(), fetchedTx.AbsoluteFeeUpdate.Unix())
 50		tx.Timestamp = fetchedTx.Timestamp
 51		tx.AbsoluteFeeUpdate = fetchedTx.AbsoluteFeeUpdate
 52		assert.Equal(t, tx, fetchedTx)
 53	}
 54}
 55
 56func BenchmarkAddTx(b *testing.B) {
 57	const nInserts = 20
 58	test.CleanL2DB(l2DB.DB())
 59	txs := test.GenPoolTxs(nInserts)
 60	now := time.Now()
 61	for _, tx := range txs {
 62		_ = l2DB.AddTx(tx)
 63	}
 64	elapsedTime := time.Since(now)
 65	fmt.Println("Time to insert 2048 txs:", elapsedTime)
 66}
 67
 68func TestGetPending(t *testing.T) {
 69	const nInserts = 20
 70	test.CleanL2DB(l2DB.DB())
 71	txs := test.GenPoolTxs(nInserts)
 72	var pendingTxs []*common.PoolL2Tx
 73	for _, tx := range txs {
 74		err := l2DB.AddTx(tx)
 75		assert.NoError(t, err)
 76		if tx.State == common.PoolL2TxStatePending {
 77			pendingTxs = append(pendingTxs, tx)
 78		}
 79	}
 80	fetchedTxs, err := l2DB.GetPendingTxs()
 81	assert.NoError(t, err)
 82	assert.Equal(t, len(pendingTxs), len(fetchedTxs))
 83	for i, fetchedTx := range fetchedTxs {
 84		assert.Equal(t, pendingTxs[i].Timestamp.Unix(), fetchedTx.Timestamp.Unix())
 85		pendingTxs[i].Timestamp = fetchedTx.Timestamp
 86		assert.Equal(t, pendingTxs[i].AbsoluteFeeUpdate.Unix(), fetchedTx.AbsoluteFeeUpdate.Unix())
 87		pendingTxs[i].AbsoluteFeeUpdate = fetchedTx.AbsoluteFeeUpdate
 88		assert.Equal(t, pendingTxs[i], fetchedTx)
 89	}
 90}
 91
 92func TestStartForging(t *testing.T) {
 93	// Generate txs
 94	const nInserts = 60
 95	const fakeBatchNum common.BatchNum = 33
 96	test.CleanL2DB(l2DB.DB())
 97	txs := test.GenPoolTxs(nInserts)
 98	var startForgingTxIDs []common.TxID
 99	randomizer := 0
100	// Add txs to DB
101	for _, tx := range txs {
102		err := l2DB.AddTx(tx)
103		assert.NoError(t, err)
104		if tx.State == common.PoolL2TxStatePending && randomizer%2 == 0 {
105			randomizer++
106			startForgingTxIDs = append(startForgingTxIDs, tx.TxID)
107		}
108	}
109	// Start forging txs
110	err := l2DB.StartForging(startForgingTxIDs, fakeBatchNum)
111	assert.NoError(t, err)
112	// Fetch txs and check that they've been updated correctly
113	for _, id := range startForgingTxIDs {
114		fetchedTx, err := l2DB.GetTx(id)
115		assert.NoError(t, err)
116		assert.Equal(t, common.PoolL2TxStateForging, fetchedTx.State)
117		assert.Equal(t, fakeBatchNum, fetchedTx.BatchNum)
118	}
119}
120
121func TestDoneForging(t *testing.T) {
122	// Generate txs
123	const nInserts = 60
124	const fakeBatchNum common.BatchNum = 33
125	test.CleanL2DB(l2DB.DB())
126	txs := test.GenPoolTxs(nInserts)
127	var doneForgingTxIDs []common.TxID
128	randomizer := 0
129	// Add txs to DB
130	for _, tx := range txs {
131		err := l2DB.AddTx(tx)
132		assert.NoError(t, err)
133		if tx.State == common.PoolL2TxStateForging && randomizer%2 == 0 {
134			randomizer++
135			doneForgingTxIDs = append(doneForgingTxIDs, tx.TxID)
136		}
137	}
138	// Start forging txs
139	err := l2DB.DoneForging(doneForgingTxIDs, fakeBatchNum)
140	assert.NoError(t, err)
141	// Fetch txs and check that they've been updated correctly
142	for _, id := range doneForgingTxIDs {
143		fetchedTx, err := l2DB.GetTx(id)
144		assert.NoError(t, err)
145		assert.Equal(t, common.PoolL2TxStateForged, fetchedTx.State)
146		assert.Equal(t, fakeBatchNum, fetchedTx.BatchNum)
147	}
148}
149
150func TestInvalidate(t *testing.T) {
151	// Generate txs
152	const nInserts = 60
153	const fakeBatchNum common.BatchNum = 33
154	test.CleanL2DB(l2DB.DB())
155	txs := test.GenPoolTxs(nInserts)
156	var invalidTxIDs []common.TxID
157	randomizer := 0
158	// Add txs to DB
159	for _, tx := range txs {
160		err := l2DB.AddTx(tx)
161		assert.NoError(t, err)
162		if tx.State != common.PoolL2TxStateInvalid && randomizer%2 == 0 {
163			randomizer++
164			invalidTxIDs = append(invalidTxIDs, tx.TxID)
165		}
166	}
167	// Start forging txs
168	err := l2DB.InvalidateTxs(invalidTxIDs, fakeBatchNum)
169	assert.NoError(t, err)
170	// Fetch txs and check that they've been updated correctly
171	for _, id := range invalidTxIDs {
172		fetchedTx, err := l2DB.GetTx(id)
173		assert.NoError(t, err)
174		assert.Equal(t, common.PoolL2TxStateInvalid, fetchedTx.State)
175		assert.Equal(t, fakeBatchNum, fetchedTx.BatchNum)
176	}
177}
178
179func TestCheckNonces(t *testing.T) {
180	// Generate txs
181	const nInserts = 60
182	const fakeBatchNum common.BatchNum = 33
183	test.CleanL2DB(l2DB.DB())
184	txs := test.GenPoolTxs(nInserts)
185	var invalidTxIDs []common.TxID
186	// Generate accounts
187	const nAccoutns = 2
188	const currentNonce = 2
189	accs := []common.Account{}
190	for i := 0; i < nAccoutns; i++ {
191		accs = append(accs, common.Account{
192			Idx:   common.Idx(i),
193			Nonce: currentNonce,
194		})
195	}
196	// Add txs to DB
197	for i := 0; i < len(txs); i++ {
198		if txs[i].State != common.PoolL2TxStateInvalid {
199			if i%2 == 0 { // Ensure transaction will be marked as invalid due to old nonce
200				txs[i].Nonce = accs[i%len(accs)].Nonce
201				txs[i].FromIdx = accs[i%len(accs)].Idx
202				invalidTxIDs = append(invalidTxIDs, txs[i].TxID)
203			} else { // Ensure transaction will NOT be marked as invalid due to old nonce
204				txs[i].Nonce = currentNonce + 1
205			}
206		}
207		err := l2DB.AddTx(txs[i])
208		assert.NoError(t, err)
209	}
210	// Start forging txs
211	err := l2DB.InvalidateTxs(invalidTxIDs, fakeBatchNum)
212	assert.NoError(t, err)
213	// Fetch txs and check that they've been updated correctly
214	for _, id := range invalidTxIDs {
215		fetchedTx, err := l2DB.GetTx(id)
216		assert.NoError(t, err)
217		assert.Equal(t, common.PoolL2TxStateInvalid, fetchedTx.State)
218		assert.Equal(t, fakeBatchNum, fetchedTx.BatchNum)
219	}
220}
221
222func TestUpdateTxValue(t *testing.T) {
223	// Generate txs
224	const nInserts = 255 // Force all possible fee selector values
225	test.CleanL2DB(l2DB.DB())
226	txs := test.GenPoolTxs(nInserts)
227	// Generate tokens
228	const nTokens = 2
229	tokens := []common.Token{}
230	for i := 0; i < nTokens; i++ {
231		tokens = append(tokens, common.Token{
232			TokenID: common.TokenID(i),
233			USD:     float64(i) * 1.3,
234		})
235	}
236	// Add txs to DB
237	for i := 0; i < len(txs); i++ {
238		// Set Token
239		token := tokens[i%len(tokens)]
240		txs[i].TokenID = token.TokenID
241		// Insert to DB
242		err := l2DB.AddTx(txs[i])
243		assert.NoError(t, err)
244		// Set USD values (for comparing results when fetching from DB)
245		txs[i].USD = txs[i].AmountFloat * token.USD
246		if txs[i].Fee == 0 {
247			txs[i].AbsoluteFee = 0
248		} else if txs[i].Fee <= 32 {
249			txs[i].AbsoluteFee = txs[i].USD * math.Pow(10, -24+(float64(txs[i].Fee)/2))
250		} else if txs[i].Fee <= 223 {
251			txs[i].AbsoluteFee = txs[i].USD * math.Pow(10, -8+(0.041666666666667*(float64(txs[i].Fee)-32)))
252		} else {
253			txs[i].AbsoluteFee = txs[i].USD * math.Pow(10, float64(txs[i].Fee)-224)
254		}
255	}
256	// Update token value
257	err := l2DB.UpdateTxValue(tokens)
258	assert.NoError(t, err)
259	// Fetch txs and check that they've been updated correctly
260	for _, tx := range txs {
261		fetchedTx, err := l2DB.GetTx(tx.TxID)
262		assert.NoError(t, err)
263		if fetchedTx.USD > tx.USD {
264			assert.Less(t, 0.999, tx.USD/fetchedTx.USD)
265		} else if fetchedTx.USD < tx.USD {
266			assert.Less(t, 0.999, fetchedTx.USD/tx.USD)
267		}
268		if fetchedTx.AbsoluteFee > tx.AbsoluteFee {
269			assert.Less(t, 0.999, tx.AbsoluteFee/fetchedTx.AbsoluteFee)
270		} else if fetchedTx.AbsoluteFee < tx.AbsoluteFee {
271			assert.Less(t, 0.999, fetchedTx.AbsoluteFee/tx.AbsoluteFee)
272		}
273		// Time is set in the DB, so it cannot be compared exactly
274		assert.Greater(t, float64(15*time.Second), time.Since(fetchedTx.AbsoluteFeeUpdate).Seconds())
275	}
276}
277
278func TestReorg(t *testing.T) {
279	// Generate txs
280	const nInserts = 20
281	const lastValidBatch common.BatchNum = 20
282	const reorgBatch common.BatchNum = lastValidBatch + 1
283	test.CleanL2DB(l2DB.DB())
284	txs := test.GenPoolTxs(nInserts)
285	// Add txs to the DB
286	reorgedTxIDs := []common.TxID{}
287	nonReorgedTxIDs := []common.TxID{}
288	for i := 0; i < len(txs); i++ {
289		if txs[i].State == common.PoolL2TxStateForged || txs[i].State == common.PoolL2TxStateInvalid {
290			txs[i].BatchNum = reorgBatch
291			reorgedTxIDs = append(reorgedTxIDs, txs[i].TxID)
292		} else {
293			txs[i].BatchNum = lastValidBatch
294			nonReorgedTxIDs = append(nonReorgedTxIDs, txs[i].TxID)
295		}
296		err := l2DB.AddTx(txs[i])
297		assert.NoError(t, err)
298	}
299	err := l2DB.Reorg(lastValidBatch)
300	assert.NoError(t, err)
301	var nullBatchNum common.BatchNum
302	for _, id := range reorgedTxIDs {
303		tx, err := l2DB.GetTx(id)
304		assert.NoError(t, err)
305		assert.Equal(t, nullBatchNum, tx.BatchNum)
306		assert.Equal(t, common.PoolL2TxStatePending, tx.State)
307	}
308	for _, id := range nonReorgedTxIDs {
309		tx, err := l2DB.GetTx(id)
310		assert.NoError(t, err)
311		assert.Equal(t, lastValidBatch, tx.BatchNum)
312	}
313}
314
315func TestPurge(t *testing.T) {
316	// Generate txs
317	nInserts := l2DB.maxTxs + 20
318	test.CleanL2DB(l2DB.DB())
319	txs := test.GenPoolTxs(int(nInserts))
320	deletedIDs := []common.TxID{}
321	keepedIDs := []common.TxID{}
322	const toDeleteBatchNum common.BatchNum = 30
323	safeBatchNum := toDeleteBatchNum + l2DB.safetyPeriod + 1
324	// Add txs to the DB
325	for i := 0; i < int(l2DB.maxTxs); i++ {
326		if i%1 == 0 { // keep tx
327			txs[i].BatchNum = safeBatchNum
328			keepedIDs = append(keepedIDs, txs[i].TxID)
329		} else if i%2 == 0 { // delete after safety period
330			txs[i].BatchNum = toDeleteBatchNum
331			if i%3 == 0 {
332				txs[i].State = common.PoolL2TxStateForged
333			} else {
334				txs[i].State = common.PoolL2TxStateInvalid
335			}
336			deletedIDs = append(deletedIDs, txs[i].TxID)
337		}
338		err := l2DB.AddTx(txs[i])
339		assert.NoError(t, err)
340	}
341	for i := int(l2DB.maxTxs); i < len(txs); i++ {
342		// Delete after TTL
343		txs[i].Timestamp = time.Unix(time.Now().UTC().Unix()-int64(l2DB.ttl.Seconds()+float64(4*time.Second)), 0)
344		deletedIDs = append(deletedIDs, txs[i].TxID)
345		err := l2DB.AddTx(txs[i])
346		assert.NoError(t, err)
347	}
348	// Purge txs
349	err := l2DB.Purge(safeBatchNum - 1)
350	assert.NoError(t, err)
351	// Check results
352	for _, id := range deletedIDs {
353		tx, err := l2DB.GetTx(id)
354		if err == nil {
355			log.Debug(tx)
356		}
357		assert.Error(t, err)
358	}
359	for _, id := range keepedIDs {
360		_, err := l2DB.GetTx(id)
361		assert.NoError(t, err)
362	}
363}
364
365func TestAuth(t *testing.T) {
366	test.CleanL2DB(l2DB.DB())
367	const nAuths = 5
368	// Generate authorizations
369	auths := test.GenAuths(nAuths)
370	for i := 0; i < len(auths); i++ {
371		// Add to the DB
372		err := l2DB.AddAccountCreationAuth(auths[i])
373		assert.NoError(t, err)
374		// Fetch from DB
375		auth, err := l2DB.GetAccountCreationAuth(auths[i].EthAddr)
376		assert.NoError(t, err)
377		// Check fetched vs generated
378		assert.Equal(t, auths[i].EthAddr, auth.EthAddr)
379		assert.Equal(t, auths[i].BJJ, auth.BJJ)
380		assert.Equal(t, auths[i].Signature, auth.Signature)
381		assert.Equal(t, auths[i].Timestamp.Unix(), auths[i].Timestamp.Unix())
382	}
383}