You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

881 lines
26 KiB

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