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 := range fetchedTxs {
115		assertTx(t, pendingTxs[i], &fetchedTxs[i])
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		txs[i].BatchNum = new(common.BatchNum)
261		if txs[i].State == common.PoolL2TxStateForged || txs[i].State == common.PoolL2TxStateInvalid {
262			*txs[i].BatchNum = reorgBatch
263			reorgedTxIDs = append(reorgedTxIDs, txs[i].TxID)
264		} else {
265			*txs[i].BatchNum = lastValidBatch
266			nonReorgedTxIDs = append(nonReorgedTxIDs, txs[i].TxID)
267		}
268		err := l2DB.AddTxTest(txs[i])
269		assert.NoError(t, err)
270	}
271	err := l2DB.Reorg(lastValidBatch)
272	assert.NoError(t, err)
273	for _, id := range reorgedTxIDs {
274		tx, err := l2DB.GetTx(id)
275		assert.NoError(t, err)
276		assert.Nil(t, 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		txs[i].BatchNum = new(common.BatchNum)
298		if i%1 == 0 { // keep tx
299			*txs[i].BatchNum = safeBatchNum
300			keepedIDs = append(keepedIDs, txs[i].TxID)
301		} else if i%2 == 0 { // delete after safety period
302			*txs[i].BatchNum = toDeleteBatchNum
303			if i%3 == 0 {
304				txs[i].State = common.PoolL2TxStateForged
305			} else {
306				txs[i].State = common.PoolL2TxStateInvalid
307			}
308			deletedIDs = append(deletedIDs, txs[i].TxID)
309		}
310		err := l2DB.AddTxTest(txs[i])
311		assert.NoError(t, err)
312	}
313	for i := int(l2DB.maxTxs); i < len(txs); i++ {
314		// Delete after TTL
315		txs[i].Timestamp = time.Unix(time.Now().UTC().Unix()-int64(l2DB.ttl.Seconds()+float64(4*time.Second)), 0)
316		deletedIDs = append(deletedIDs, txs[i].TxID)
317		err := l2DB.AddTxTest(txs[i])
318		assert.NoError(t, err)
319	}
320	// Purge txs
321	err := l2DB.Purge(safeBatchNum - 1)
322	assert.NoError(t, err)
323	// Check results
324	for _, id := range deletedIDs {
325		tx, err := l2DB.GetTx(id)
326		if err == nil {
327			log.Debug(tx)
328		}
329		assert.Error(t, err)
330	}
331	for _, id := range keepedIDs {
332		_, err := l2DB.GetTx(id)
333		assert.NoError(t, err)
334	}
335}
336
337func TestAuth(t *testing.T) {
338	test.CleanL2DB(l2DB.DB())
339	const nAuths = 5
340	// Generate authorizations
341	auths := test.GenAuths(nAuths)
342	for i := 0; i < len(auths); i++ {
343		// Add to the DB
344		err := l2DB.AddAccountCreationAuth(auths[i])
345		assert.NoError(t, err)
346		// Fetch from DB
347		auth, err := l2DB.GetAccountCreationAuth(&auths[i].EthAddr)
348		assert.NoError(t, err)
349		// Check fetched vs generated
350		assert.Equal(t, auths[i].EthAddr, auth.EthAddr)
351		assert.Equal(t, auths[i].BJJ, auth.BJJ)
352		assert.Equal(t, auths[i].Signature, auth.Signature)
353		assert.Equal(t, auths[i].Timestamp.Unix(), auths[i].Timestamp.Unix())
354	}
355}