hermez-node/db/l2db/l2db_test.go
db/l2db/l2db_test.goRaw
1package l2db
2
3import (
4 "database/sql"
5 "fmt"
6 "os"
7 "testing"
8 "time"
9
10 ethCommon "github.com/ethereum/go-ethereum/common"
11 "github.com/hermeznetwork/hermez-node/common"
12 dbUtils "github.com/hermeznetwork/hermez-node/db"
13 "github.com/hermeznetwork/hermez-node/db/historydb"
14 "github.com/hermeznetwork/hermez-node/log"
15 "github.com/hermeznetwork/hermez-node/test"
16 "github.com/hermeznetwork/hermez-node/test/til"
17 "github.com/hermeznetwork/tracerr"
18 "github.com/iden3/go-iden3-crypto/babyjub"
19 "github.com/stretchr/testify/assert"
20 "github.com/stretchr/testify/require"
21)
22
23var decimals = uint64(3)
24var tokenValue = 1.0 // The price update gives a value of 1.0 USD to the token
25var l2DB *L2DB
26var l2DBWithACC *L2DB
27var historyDB *historydb.HistoryDB
28var tc *til.Context
29var tokens map[common.TokenID]historydb.TokenWithUSD
30
31var accs map[common.Idx]common.Account
32
33func TestMain(m *testing.M) {
34 // init DB
35 pass := os.Getenv("POSTGRES_PASS")
36 db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
37 if err != nil {
38 panic(err)
39 }
40 l2DB = NewL2DB(db, db, 10, 1000, 0.0, 24*time.Hour, nil)
41 apiConnCon := dbUtils.NewAPIConnectionController(1, time.Second)
42 l2DBWithACC = NewL2DB(db, db, 10, 1000, 0.0, 24*time.Hour, apiConnCon)
43 test.WipeDB(l2DB.DB())
44 historyDB = historydb.NewHistoryDB(db, db, nil)
45 // Run tests
46 result := m.Run()
47 // Close DB
48 if err := db.Close(); err != nil {
49 log.Error("Error closing the history DB:", err)
50 }
51 os.Exit(result)
52}
53
54func prepareHistoryDB(historyDB *historydb.HistoryDB) error {
55 // Reset DB
56 test.WipeDB(l2DB.DB())
57 // Generate pool txs using til
58 setBlockchain := `
59 Type: Blockchain
60
61 AddToken(1)
62 AddToken(2)
63 CreateAccountDeposit(1) A: 20000
64 CreateAccountDeposit(2) A: 20000
65 CreateAccountDeposit(1) B: 10000
66 CreateAccountDeposit(2) B: 10000
67 > batchL1
68 > batchL1
69 > block
70 > block
71 `
72
73 tc = til.NewContext(uint16(0), common.RollupConstMaxL1UserTx)
74 tilCfgExtra := til.ConfigExtra{
75 BootCoordAddr: ethCommon.HexToAddress("0xE39fEc6224708f0772D2A74fd3f9055A90E0A9f2"),
76 CoordUser: "A",
77 }
78 blocks, err := tc.GenerateBlocks(setBlockchain)
79 if err != nil {
80 return tracerr.Wrap(err)
81 }
82
83 err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
84 if err != nil {
85 return tracerr.Wrap(err)
86 }
87 for i := range blocks {
88 block := &blocks[i]
89 for j := range block.Rollup.AddedTokens {
90 token := &block.Rollup.AddedTokens[j]
91 token.Name = fmt.Sprintf("Token %d", token.TokenID)
92 token.Symbol = fmt.Sprintf("TK%d", token.TokenID)
93 token.Decimals = decimals
94 }
95 }
96
97 tokens = make(map[common.TokenID]historydb.TokenWithUSD)
98 // tokensValue = make(map[common.TokenID]float64)
99 accs = make(map[common.Idx]common.Account)
100 now := time.Now().UTC()
101 // Add all blocks except for the last one
102 for i := range blocks[:len(blocks)-1] {
103 if err := historyDB.AddBlockSCData(&blocks[i]); err != nil {
104 return tracerr.Wrap(err)
105 }
106 for _, batch := range blocks[i].Rollup.Batches {
107 for _, account := range batch.CreatedAccounts {
108 accs[account.Idx] = account
109 }
110 }
111 for _, token := range blocks[i].Rollup.AddedTokens {
112 readToken := historydb.TokenWithUSD{
113 TokenID: token.TokenID,
114 EthBlockNum: token.EthBlockNum,
115 EthAddr: token.EthAddr,
116 Name: token.Name,
117 Symbol: token.Symbol,
118 Decimals: token.Decimals,
119 USD: &tokenValue,
120 USDUpdate: &now,
121 }
122 tokens[token.TokenID] = readToken
123 // Set value to the tokens
124 err := historyDB.UpdateTokenValue(readToken.EthAddr, *readToken.USD)
125 if err != nil {
126 return tracerr.Wrap(err)
127 }
128 }
129 }
130 return nil
131}
132
133func generatePoolL2Txs() ([]common.PoolL2Tx, error) {
134 // Fee = 126 corresponds to ~10%
135 setPool := `
136 Type: PoolL2
137 PoolTransfer(1) A-B: 6000 (126)
138 PoolTransfer(2) A-B: 3000 (126)
139 PoolTransfer(1) B-A: 5000 (126)
140 PoolTransfer(2) B-A: 10000 (126)
141 PoolTransfer(1) A-B: 7000 (126)
142 PoolTransfer(2) A-B: 2000 (126)
143 PoolTransfer(1) B-A: 8000 (126)
144 PoolTransfer(2) B-A: 1000 (126)
145 PoolTransfer(1) A-B: 3000 (126)
146 PoolTransferToEthAddr(2) B-A: 5000 (126)
147 PoolTransferToBJJ(2) B-A: 5000 (126)
148
149 PoolExit(1) A: 5000 (126)
150 PoolExit(2) B: 3000 (126)
151 `
152 poolL2Txs, err := tc.GeneratePoolL2Txs(setPool)
153 if err != nil {
154 return nil, tracerr.Wrap(err)
155 }
156 return poolL2Txs, nil
157}
158
159func TestAddTxTest(t *testing.T) {
160 err := prepareHistoryDB(historyDB)
161 if err != nil {
162 log.Error("Error prepare historyDB", err)
163 }
164 poolL2Txs, err := generatePoolL2Txs()
165 require.NoError(t, err)
166 for i := range poolL2Txs {
167 err := l2DB.AddTxTest(&poolL2Txs[i])
168 require.NoError(t, err)
169 fetchedTx, err := l2DB.GetTx(poolL2Txs[i].TxID)
170 require.NoError(t, err)
171 assertTx(t, &poolL2Txs[i], fetchedTx)
172 nameZone, offset := fetchedTx.Timestamp.Zone()
173 assert.Equal(t, "UTC", nameZone)
174 assert.Equal(t, 0, offset)
175 }
176}
177
178func TestAddTxAPI(t *testing.T) {
179 err := prepareHistoryDB(historyDB)
180 if err != nil {
181 log.Error("Error prepare historyDB", err)
182 }
183
184 oldMaxTxs := l2DBWithACC.maxTxs
185 // set max number of pending txs that can be kept in the pool to 5
186 l2DBWithACC.maxTxs = 5
187
188 poolL2Txs, err := generatePoolL2Txs()
189 txs := make([]*PoolL2TxWrite, len(poolL2Txs))
190 for i := range poolL2Txs {
191 txs[i] = NewPoolL2TxWriteFromPoolL2Tx(&poolL2Txs[i])
192 }
193 require.NoError(t, err)
194 require.GreaterOrEqual(t, len(poolL2Txs), 8)
195 for i := range txs[:5] {
196 err := l2DBWithACC.AddTxAPI(txs[i])
197 require.NoError(t, err)
198 fetchedTx, err := l2DB.GetTx(poolL2Txs[i].TxID)
199 require.NoError(t, err)
200 assertTx(t, &poolL2Txs[i], fetchedTx)
201 nameZone, offset := fetchedTx.Timestamp.Zone()
202 assert.Equal(t, "UTC", nameZone)
203 assert.Equal(t, 0, offset)
204 }
205 err = l2DBWithACC.AddTxAPI(txs[5])
206 assert.Equal(t, errPoolFull, tracerr.Unwrap(err))
207 // reset maxTxs to original value
208 l2DBWithACC.maxTxs = oldMaxTxs
209
210 // set minFeeUSD to a high value than the tx feeUSD to test the error
211 // of inserting a tx with lower than min fee
212 oldMinFeeUSD := l2DBWithACC.minFeeUSD
213 tx := txs[5]
214 feeAmount, err := common.CalcFeeAmount(tx.Amount, tx.Fee)
215 require.NoError(t, err)
216 feeAmountUSD := common.TokensToUSD(feeAmount, decimals, tokenValue)
217 // set minFeeUSD higher than the tx fee to trigger the error
218 l2DBWithACC.minFeeUSD = feeAmountUSD + 1
219 err = l2DBWithACC.AddTxAPI(tx)
220 require.Error(t, err)
221 assert.Regexp(t, "tx.feeUSD (.*) < minFeeUSD (.*)", err.Error())
222 // reset minFeeUSD to original value
223 l2DBWithACC.minFeeUSD = oldMinFeeUSD
224}
225
226func TestUpdateTxsInfo(t *testing.T) {
227 err := prepareHistoryDB(historyDB)
228 if err != nil {
229 log.Error("Error prepare historyDB", err)
230 }
231 poolL2Txs, err := generatePoolL2Txs()
232 require.NoError(t, err)
233 for i := range poolL2Txs {
234 err := l2DB.AddTxTest(&poolL2Txs[i])
235 require.NoError(t, err)
236
237 // once added, change the Info parameter
238 poolL2Txs[i].Info = "test"
239 }
240 // update the txs
241 err = l2DB.UpdateTxsInfo(poolL2Txs)
242 require.NoError(t, err)
243
244 for i := range poolL2Txs {
245 fetchedTx, err := l2DB.GetTx(poolL2Txs[i].TxID)
246 require.NoError(t, err)
247 assert.Equal(t, "test", fetchedTx.Info)
248 }
249}
250
251func assertTx(t *testing.T, expected, actual *common.PoolL2Tx) {
252 // Check that timestamp has been set within the last 3 seconds
253 assert.Less(t, time.Now().UTC().Unix()-3, actual.Timestamp.Unix())
254 assert.GreaterOrEqual(t, time.Now().UTC().Unix(), actual.Timestamp.Unix())
255 expected.Timestamp = actual.Timestamp
256 // Check absolute fee
257 // find token
258 token := tokens[expected.TokenID]
259 // If the token has value in USD setted
260 if token.USDUpdate != nil {
261 assert.Less(t, token.USDUpdate.Unix()-3, actual.AbsoluteFeeUpdate.Unix())
262 expected.AbsoluteFeeUpdate = actual.AbsoluteFeeUpdate
263 // Set expected fee
264 amountUSD := common.TokensToUSD(expected.Amount, token.Decimals, *token.USD)
265 expected.AbsoluteFee = amountUSD * expected.Fee.Percentage()
266 test.AssertUSD(t, &expected.AbsoluteFee, &actual.AbsoluteFee)
267 }
268 assert.Equal(t, expected, actual)
269}
270
271// NO UPDATE: benchmarks will be done after impl is finished
272// func BenchmarkAddTxTest(b *testing.B) {
273// const nInserts = 20
274// test.WipeDB(l2DB.DB())
275// txs := test.GenPoolTxs(nInserts, tokens)
276// now := time.Now()
277// for _, tx := range txs {
278// _ = l2DB.AddTxTest(tx)
279// }
280// elapsedTime := time.Since(now)
281// log.Info("Time to insert 2048 txs:", elapsedTime)
282// }
283
284func TestGetPending(t *testing.T) {
285 err := prepareHistoryDB(historyDB)
286 if err != nil {
287 log.Error("Error prepare historyDB", err)
288 }
289 poolL2Txs, err := generatePoolL2Txs()
290 require.NoError(t, err)
291 var pendingTxs []*common.PoolL2Tx
292 for i := range poolL2Txs {
293 err := l2DB.AddTxTest(&poolL2Txs[i])
294 require.NoError(t, err)
295 pendingTxs = append(pendingTxs, &poolL2Txs[i])
296 }
297 fetchedTxs, err := l2DB.GetPendingTxs()
298 require.NoError(t, err)
299 assert.Equal(t, len(pendingTxs), len(fetchedTxs))
300 for i := range fetchedTxs {
301 assertTx(t, pendingTxs[i], &fetchedTxs[i])
302 }
303 // Check AbsoluteFee amount
304 for i := range fetchedTxs {
305 tx := &fetchedTxs[i]
306 feeAmount, err := common.CalcFeeAmount(tx.Amount, tx.Fee)
307 require.NoError(t, err)
308 feeAmountUSD := common.TokensToUSD(feeAmount,
309 tokens[tx.TokenID].Decimals, *tokens[tx.TokenID].USD)
310 assert.InEpsilon(t, feeAmountUSD, tx.AbsoluteFee, 0.01)
311 }
312}
313
314func TestStartForging(t *testing.T) {
315 // Generate txs
316 var fakeBatchNum common.BatchNum = 33
317 err := prepareHistoryDB(historyDB)
318 if err != nil {
319 log.Error("Error prepare historyDB", err)
320 }
321 poolL2Txs, err := generatePoolL2Txs()
322 require.NoError(t, err)
323 var startForgingTxIDs []common.TxID
324 randomizer := 0
325 // Add txs to DB
326 for i := range poolL2Txs {
327 err := l2DB.AddTxTest(&poolL2Txs[i])
328 require.NoError(t, err)
329 if poolL2Txs[i].State == common.PoolL2TxStatePending && randomizer%2 == 0 {
330 startForgingTxIDs = append(startForgingTxIDs, poolL2Txs[i].TxID)
331 }
332 randomizer++
333 }
334 // Start forging txs
335 err = l2DB.StartForging(startForgingTxIDs, fakeBatchNum)
336 require.NoError(t, err)
337 // Fetch txs and check that they've been updated correctly
338 for _, id := range startForgingTxIDs {
339 fetchedTx, err := l2DBWithACC.GetTxAPI(id)
340 require.NoError(t, err)
341 assert.Equal(t, common.PoolL2TxStateForging, fetchedTx.State)
342 assert.Equal(t, &fakeBatchNum, fetchedTx.BatchNum)
343 }
344}
345
346func TestDoneForging(t *testing.T) {
347 // Generate txs
348 var fakeBatchNum common.BatchNum = 33
349 err := prepareHistoryDB(historyDB)
350 if err != nil {
351 log.Error("Error prepare historyDB", err)
352 }
353 poolL2Txs, err := generatePoolL2Txs()
354 require.NoError(t, err)
355 var startForgingTxIDs []common.TxID
356 randomizer := 0
357 // Add txs to DB
358 for i := range poolL2Txs {
359 err := l2DB.AddTxTest(&poolL2Txs[i])
360 require.NoError(t, err)
361 if poolL2Txs[i].State == common.PoolL2TxStatePending && randomizer%2 == 0 {
362 startForgingTxIDs = append(startForgingTxIDs, poolL2Txs[i].TxID)
363 }
364 randomizer++
365 }
366 // Start forging txs
367 err = l2DB.StartForging(startForgingTxIDs, fakeBatchNum)
368 require.NoError(t, err)
369
370 var doneForgingTxIDs []common.TxID
371 randomizer = 0
372 for _, txID := range startForgingTxIDs {
373 if randomizer%2 == 0 {
374 doneForgingTxIDs = append(doneForgingTxIDs, txID)
375 }
376 randomizer++
377 }
378 // Done forging txs
379 err = l2DB.DoneForging(doneForgingTxIDs, fakeBatchNum)
380 require.NoError(t, err)
381
382 // Fetch txs and check that they've been updated correctly
383 for _, id := range doneForgingTxIDs {
384 fetchedTx, err := l2DBWithACC.GetTxAPI(id)
385 require.NoError(t, err)
386 assert.Equal(t, common.PoolL2TxStateForged, fetchedTx.State)
387 assert.Equal(t, &fakeBatchNum, fetchedTx.BatchNum)
388 }
389}
390
391func TestInvalidate(t *testing.T) {
392 // Generate txs
393 var fakeBatchNum common.BatchNum = 33
394 err := prepareHistoryDB(historyDB)
395 if err != nil {
396 log.Error("Error prepare historyDB", err)
397 }
398 poolL2Txs, err := generatePoolL2Txs()
399 require.NoError(t, err)
400 var invalidTxIDs []common.TxID
401 randomizer := 0
402 // Add txs to DB
403 for i := range poolL2Txs {
404 err := l2DB.AddTxTest(&poolL2Txs[i])
405 require.NoError(t, err)
406 if poolL2Txs[i].State != common.PoolL2TxStateInvalid && randomizer%2 == 0 {
407 randomizer++
408 invalidTxIDs = append(invalidTxIDs, poolL2Txs[i].TxID)
409 }
410 }
411 // Invalidate txs
412 err = l2DB.InvalidateTxs(invalidTxIDs, fakeBatchNum)
413 require.NoError(t, err)
414 // Fetch txs and check that they've been updated correctly
415 for _, id := range invalidTxIDs {
416 fetchedTx, err := l2DBWithACC.GetTxAPI(id)
417 require.NoError(t, err)
418 assert.Equal(t, common.PoolL2TxStateInvalid, fetchedTx.State)
419 assert.Equal(t, &fakeBatchNum, fetchedTx.BatchNum)
420 }
421}
422
423func TestInvalidateOldNonces(t *testing.T) {
424 // Generate txs
425 var fakeBatchNum common.BatchNum = 33
426 err := prepareHistoryDB(historyDB)
427 if err != nil {
428 log.Error("Error prepare historyDB", err)
429 }
430 poolL2Txs, err := generatePoolL2Txs()
431 require.NoError(t, err)
432 // Update Accounts currentNonce
433 var updateAccounts []common.IdxNonce
434 var currentNonce = common.Nonce(1)
435 for i := range accs {
436 updateAccounts = append(updateAccounts, common.IdxNonce{
437 Idx: accs[i].Idx,
438 Nonce: common.Nonce(currentNonce),
439 })
440 }
441 // Add txs to DB
442 var invalidTxIDs []common.TxID
443 for i := range poolL2Txs {
444 if poolL2Txs[i].Nonce < currentNonce {
445 invalidTxIDs = append(invalidTxIDs, poolL2Txs[i].TxID)
446 }
447 err := l2DB.AddTxTest(&poolL2Txs[i])
448 require.NoError(t, err)
449 }
450 // sanity check
451 require.Greater(t, len(invalidTxIDs), 0)
452
453 err = l2DB.InvalidateOldNonces(updateAccounts, fakeBatchNum)
454 require.NoError(t, err)
455 // Fetch txs and check that they've been updated correctly
456 for _, id := range invalidTxIDs {
457 fetchedTx, err := l2DBWithACC.GetTxAPI(id)
458 require.NoError(t, err)
459 assert.Equal(t, common.PoolL2TxStateInvalid, fetchedTx.State)
460 assert.Equal(t, &fakeBatchNum, fetchedTx.BatchNum)
461 }
462}
463
464// TestReorg: first part of the test with reorg
465// With invalidated transactions BEFORE reorgBatch
466// And forged transactions in reorgBatch
467func TestReorg(t *testing.T) {
468 // Generate txs
469 const lastValidBatch common.BatchNum = 20
470 const reorgBatch common.BatchNum = lastValidBatch + 1
471 err := prepareHistoryDB(historyDB)
472 if err != nil {
473 log.Error("Error prepare historyDB", err)
474 }
475 poolL2Txs, err := generatePoolL2Txs()
476 require.NoError(t, err)
477
478 reorgedTxIDs := []common.TxID{}
479 nonReorgedTxIDs := []common.TxID{}
480 var startForgingTxIDs []common.TxID
481 var invalidTxIDs []common.TxID
482 var allTxRandomize []common.TxID
483 randomizer := 0
484 // Add txs to DB
485 for i := range poolL2Txs {
486 err := l2DB.AddTxTest(&poolL2Txs[i])
487 require.NoError(t, err)
488 if poolL2Txs[i].State == common.PoolL2TxStatePending && randomizer%2 == 0 {
489 startForgingTxIDs = append(startForgingTxIDs, poolL2Txs[i].TxID)
490 allTxRandomize = append(allTxRandomize, poolL2Txs[i].TxID)
491 } else if poolL2Txs[i].State == common.PoolL2TxStatePending && randomizer%3 == 0 {
492 invalidTxIDs = append(invalidTxIDs, poolL2Txs[i].TxID)
493 allTxRandomize = append(allTxRandomize, poolL2Txs[i].TxID)
494 }
495 randomizer++
496 }
497 // Start forging txs
498 err = l2DB.StartForging(startForgingTxIDs, lastValidBatch)
499 require.NoError(t, err)
500
501 var doneForgingTxIDs []common.TxID
502 randomizer = 0
503 for _, txID := range allTxRandomize {
504 invalidTx := false
505 for i := range invalidTxIDs {
506 if invalidTxIDs[i] == txID {
507 invalidTx = true
508 nonReorgedTxIDs = append(nonReorgedTxIDs, txID)
509 }
510 }
511 if !invalidTx {
512 if randomizer%2 == 0 {
513 doneForgingTxIDs = append(doneForgingTxIDs, txID)
514 reorgedTxIDs = append(reorgedTxIDs, txID)
515 } else {
516 nonReorgedTxIDs = append(nonReorgedTxIDs, txID)
517 }
518 randomizer++
519 }
520 }
521
522 // Invalidate txs BEFORE reorgBatch --> nonReorg
523 err = l2DB.InvalidateTxs(invalidTxIDs, lastValidBatch)
524 require.NoError(t, err)
525 // Done forging txs in reorgBatch --> Reorg
526 err = l2DB.DoneForging(doneForgingTxIDs, reorgBatch)
527 require.NoError(t, err)
528
529 err = l2DB.Reorg(lastValidBatch)
530 require.NoError(t, err)
531 for _, id := range reorgedTxIDs {
532 tx, err := l2DBWithACC.GetTxAPI(id)
533 require.NoError(t, err)
534 assert.Nil(t, tx.BatchNum)
535 assert.Equal(t, common.PoolL2TxStatePending, tx.State)
536 }
537 for _, id := range nonReorgedTxIDs {
538 fetchedTx, err := l2DBWithACC.GetTxAPI(id)
539 require.NoError(t, err)
540 assert.Equal(t, lastValidBatch, *fetchedTx.BatchNum)
541 }
542}
543
544// TestReorg: second part of test with reorg
545// With invalidated transactions in reorgBatch
546// And forged transactions BEFORE reorgBatch
547func TestReorg2(t *testing.T) {
548 // Generate txs
549 const lastValidBatch common.BatchNum = 20
550 const reorgBatch common.BatchNum = lastValidBatch + 1
551 err := prepareHistoryDB(historyDB)
552 if err != nil {
553 log.Error("Error prepare historyDB", err)
554 }
555 poolL2Txs, err := generatePoolL2Txs()
556 require.NoError(t, err)
557
558 reorgedTxIDs := []common.TxID{}
559 nonReorgedTxIDs := []common.TxID{}
560 var startForgingTxIDs []common.TxID
561 var invalidTxIDs []common.TxID
562 var allTxRandomize []common.TxID
563 randomizer := 0
564 // Add txs to DB
565 for i := range poolL2Txs {
566 err := l2DB.AddTxTest(&poolL2Txs[i])
567 require.NoError(t, err)
568 if poolL2Txs[i].State == common.PoolL2TxStatePending && randomizer%2 == 0 {
569 startForgingTxIDs = append(startForgingTxIDs, poolL2Txs[i].TxID)
570 allTxRandomize = append(allTxRandomize, poolL2Txs[i].TxID)
571 } else if poolL2Txs[i].State == common.PoolL2TxStatePending && randomizer%3 == 0 {
572 invalidTxIDs = append(invalidTxIDs, poolL2Txs[i].TxID)
573 allTxRandomize = append(allTxRandomize, poolL2Txs[i].TxID)
574 }
575 randomizer++
576 }
577 // Start forging txs
578 err = l2DB.StartForging(startForgingTxIDs, lastValidBatch)
579 require.NoError(t, err)
580
581 var doneForgingTxIDs []common.TxID
582 randomizer = 0
583 for _, txID := range allTxRandomize {
584 invalidTx := false
585 for i := range invalidTxIDs {
586 if invalidTxIDs[i] == txID {
587 invalidTx = true
588 reorgedTxIDs = append(reorgedTxIDs, txID)
589 }
590 }
591 if !invalidTx {
592 if randomizer%2 == 0 {
593 doneForgingTxIDs = append(doneForgingTxIDs, txID)
594 }
595 nonReorgedTxIDs = append(nonReorgedTxIDs, txID)
596 randomizer++
597 }
598 }
599 // Done forging txs BEFORE reorgBatch --> nonReorg
600 err = l2DB.DoneForging(doneForgingTxIDs, lastValidBatch)
601 require.NoError(t, err)
602 // Invalidate txs in reorgBatch --> Reorg
603 err = l2DB.InvalidateTxs(invalidTxIDs, reorgBatch)
604 require.NoError(t, err)
605
606 err = l2DB.Reorg(lastValidBatch)
607 require.NoError(t, err)
608 for _, id := range reorgedTxIDs {
609 tx, err := l2DBWithACC.GetTxAPI(id)
610 require.NoError(t, err)
611 assert.Nil(t, tx.BatchNum)
612 assert.Equal(t, common.PoolL2TxStatePending, tx.State)
613 }
614 for _, id := range nonReorgedTxIDs {
615 fetchedTx, err := l2DBWithACC.GetTxAPI(id)
616 require.NoError(t, err)
617 assert.Equal(t, lastValidBatch, *fetchedTx.BatchNum)
618 }
619}
620
621func TestPurge(t *testing.T) {
622 // Generate txs
623 err := prepareHistoryDB(historyDB)
624 if err != nil {
625 log.Error("Error prepare historyDB", err)
626 }
627 // generatePoolL2Txs
628 generateTx := int(l2DB.maxTxs/8 + 1)
629 var poolL2Tx []common.PoolL2Tx
630 for i := 0; i < generateTx; i++ {
631 poolL2TxAux, err := generatePoolL2Txs()
632 require.NoError(t, err)
633 poolL2Tx = append(poolL2Tx, poolL2TxAux...)
634 }
635
636 afterTTLIDs := []common.TxID{}
637 keepedIDs := []common.TxID{}
638 var deletedIDs []common.TxID
639 var invalidTxIDs []common.TxID
640 var doneForgingTxIDs []common.TxID
641 const toDeleteBatchNum common.BatchNum = 30
642 safeBatchNum := toDeleteBatchNum + l2DB.safetyPeriod + 1
643 // Add txs to the DB
644 for i := 0; i < len(poolL2Tx); i++ {
645 tx := poolL2Tx[i]
646 if i%2 == 0 { // keep tx
647 keepedIDs = append(keepedIDs, tx.TxID)
648 } else { // delete after safety period
649 if i%3 == 0 {
650 doneForgingTxIDs = append(doneForgingTxIDs, tx.TxID)
651 } else if i%5 == 0 {
652 invalidTxIDs = append(invalidTxIDs, tx.TxID)
653 } else {
654 afterTTLIDs = append(afterTTLIDs, tx.TxID)
655 }
656 deletedIDs = append(deletedIDs, poolL2Tx[i].TxID)
657 }
658 err := l2DB.AddTxTest(&tx)
659 require.NoError(t, err)
660 }
661 // Set batchNum keeped txs
662 for i := range keepedIDs {
663 _, err = l2DB.dbWrite.Exec(
664 "UPDATE tx_pool SET batch_num = $1 WHERE tx_id = $2;",
665 safeBatchNum, keepedIDs[i],
666 )
667 require.NoError(t, err)
668 }
669 // Start forging txs and set batchNum
670 err = l2DB.StartForging(doneForgingTxIDs, toDeleteBatchNum)
671 require.NoError(t, err)
672 // Done forging txs and set batchNum
673 err = l2DB.DoneForging(doneForgingTxIDs, toDeleteBatchNum)
674 require.NoError(t, err)
675 // Invalidate txs and set batchNum
676 err = l2DB.InvalidateTxs(invalidTxIDs, toDeleteBatchNum)
677 require.NoError(t, err)
678 // Update timestamp of afterTTL txs
679 deleteTimestamp := time.Unix(time.Now().UTC().Unix()-int64(l2DB.ttl.Seconds()+float64(4*time.Second)), 0)
680 for _, id := range afterTTLIDs {
681 // Set timestamp
682 _, err = l2DB.dbWrite.Exec(
683 "UPDATE tx_pool SET timestamp = $1, state = $2 WHERE tx_id = $3;",
684 deleteTimestamp, common.PoolL2TxStatePending, id,
685 )
686 require.NoError(t, err)
687 }
688
689 // Purge txs
690 err = l2DB.Purge(safeBatchNum)
691 require.NoError(t, err)
692 // Check results
693 for _, id := range deletedIDs {
694 _, err := l2DB.GetTx(id)
695 assert.Error(t, err)
696 }
697 for _, id := range keepedIDs {
698 _, err := l2DB.GetTx(id)
699 require.NoError(t, err)
700 }
701}
702
703func TestAuth(t *testing.T) {
704 test.WipeDB(l2DB.DB())
705 const nAuths = 5
706 chainID := uint16(0)
707 hermezContractAddr := ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
708 // Generate authorizations
709 auths := test.GenAuths(nAuths, chainID, hermezContractAddr)
710 for i := 0; i < len(auths); i++ {
711 // Add to the DB
712 err := l2DB.AddAccountCreationAuth(auths[i])
713 require.NoError(t, err)
714 // Fetch from DB
715 auth, err := l2DB.GetAccountCreationAuth(auths[i].EthAddr)
716 require.NoError(t, err)
717 // Check fetched vs generated
718 assert.Equal(t, auths[i].EthAddr, auth.EthAddr)
719 assert.Equal(t, auths[i].BJJ, auth.BJJ)
720 assert.Equal(t, auths[i].Signature, auth.Signature)
721 assert.Equal(t, auths[i].Timestamp.Unix(), auths[i].Timestamp.Unix())
722 nameZone, offset := auths[i].Timestamp.Zone()
723 assert.Equal(t, "UTC", nameZone)
724 assert.Equal(t, 0, offset)
725 }
726}
727
728func TestAddGet(t *testing.T) {
729 err := prepareHistoryDB(historyDB)
730 if err != nil {
731 log.Error("Error prepare historyDB", err)
732 }
733 poolL2Txs, err := generatePoolL2Txs()
734 require.NoError(t, err)
735
736 // We will work with only 3 txs
737 require.GreaterOrEqual(t, len(poolL2Txs), 3)
738 txs := poolL2Txs[:3]
739 // NOTE: By changing the tx fields, the signature will no longer be
740 // valid, but we are not checking the signautre here so it's OK.
741 // 0. Has ToIdx >= 256 && ToEthAddr == 0 && ToBJJ == 0
742 require.GreaterOrEqual(t, int(txs[0].ToIdx), 256)
743 txs[0].ToEthAddr = ethCommon.Address{}
744 txs[0].ToBJJ = babyjub.PublicKeyComp{}
745 // 1. Has ToIdx >= 256 && ToEthAddr != 0 && ToBJJ != 0
746 require.GreaterOrEqual(t, int(txs[1].ToIdx), 256)
747 require.NotEqual(t, txs[1].ToEthAddr, ethCommon.Address{})
748 require.NotEqual(t, txs[1].ToBJJ, babyjub.PublicKeyComp{})
749 // 2. Has ToIdx == 0 && ToEthAddr != 0 && ToBJJ != 0
750 txs[2].ToIdx = 0
751 require.NotEqual(t, txs[2].ToEthAddr, ethCommon.Address{})
752 require.NotEqual(t, txs[2].ToBJJ, babyjub.PublicKeyComp{})
753
754 for i := 0; i < len(txs); i++ {
755 require.NoError(t, txs[i].SetID())
756 require.NoError(t, l2DB.AddTxTest(&txs[i]))
757 }
758 // Verify that the inserts haven't altered any field (specially
759 // ToEthAddr and ToBJJ)
760 for i := 0; i < len(txs); i++ {
761 dbTx, err := l2DB.GetTx(txs[i].TxID)
762 require.NoError(t, err)
763 // Ignore Timestamp, AbsoluteFee, AbsoluteFeeUpdate
764 txs[i].Timestamp = dbTx.Timestamp
765 txs[i].AbsoluteFee = dbTx.AbsoluteFee
766 txs[i].AbsoluteFeeUpdate = dbTx.AbsoluteFeeUpdate
767 assert.Equal(t, txs[i], *dbTx)
768 }
769}
770
771func TestPurgeByExternalDelete(t *testing.T) {
772 err := prepareHistoryDB(historyDB)
773 if err != nil {
774 log.Error("Error prepare historyDB", err)
775 }
776 txs, err := generatePoolL2Txs()
777 require.NoError(t, err)
778
779 // We will work with 8 txs
780 require.GreaterOrEqual(t, len(txs), 8)
781 txs = txs[:8]
782 for i := range txs {
783 require.NoError(t, l2DB.AddTxTest(&txs[i]))
784 }
785
786 // We will recreate this scenario:
787 // tx index, status , external_delete
788 // 0 , pending, false
789 // 1 , pending, false
790 // 2 , pending, true // will be deleted
791 // 3 , pending, true // will be deleted
792 // 4 , fging , false
793 // 5 , fging , false
794 // 6 , fging , true
795 // 7 , fging , true
796
797 require.NoError(t, l2DB.StartForging(
798 []common.TxID{txs[4].TxID, txs[5].TxID, txs[6].TxID, txs[7].TxID},
799 1))
800 _, err = l2DB.dbWrite.Exec(
801 `UPDATE tx_pool SET external_delete = true WHERE
802 tx_id IN ($1, $2, $3, $4)
803 ;`,
804 txs[2].TxID, txs[3].TxID, txs[6].TxID, txs[7].TxID,
805 )
806 require.NoError(t, err)
807 require.NoError(t, l2DB.PurgeByExternalDelete())
808
809 // Query txs that are have been not deleted
810 for _, i := range []int{0, 1, 4, 5, 6, 7} {
811 txID := txs[i].TxID
812 _, err := l2DB.GetTx(txID)
813 require.NoError(t, err)
814 }
815
816 // Query txs that have been deleted
817 for _, i := range []int{2, 3} {
818 txID := txs[i].TxID
819 _, err := l2DB.GetTx(txID)
820 require.Equal(t, sql.ErrNoRows, tracerr.Unwrap(err))
821 }
822}