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