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.

184 lines
5.4 KiB

  1. package l2db
  2. import (
  3. "fmt"
  4. ethCommon "github.com/ethereum/go-ethereum/common"
  5. "github.com/hermeznetwork/hermez-node/common"
  6. "github.com/hermeznetwork/tracerr"
  7. "github.com/russross/meddler"
  8. )
  9. var (
  10. errPoolFull = fmt.Errorf("the pool is at full capacity. More transactions are not accepted currently")
  11. )
  12. // AddAccountCreationAuthAPI inserts an account creation authorization into the DB
  13. func (l2db *L2DB) AddAccountCreationAuthAPI(auth *common.AccountCreationAuth) error {
  14. cancel, err := l2db.apiConnCon.Acquire()
  15. defer cancel()
  16. if err != nil {
  17. return tracerr.Wrap(err)
  18. }
  19. defer l2db.apiConnCon.Release()
  20. return l2db.AddAccountCreationAuth(auth)
  21. }
  22. // GetAccountCreationAuthAPI returns an account creation authorization from the DB
  23. func (l2db *L2DB) GetAccountCreationAuthAPI(addr ethCommon.Address) (*AccountCreationAuthAPI, error) {
  24. cancel, err := l2db.apiConnCon.Acquire()
  25. defer cancel()
  26. if err != nil {
  27. return nil, tracerr.Wrap(err)
  28. }
  29. defer l2db.apiConnCon.Release()
  30. auth := new(AccountCreationAuthAPI)
  31. return auth, tracerr.Wrap(meddler.QueryRow(
  32. l2db.dbRead, auth,
  33. "SELECT * FROM account_creation_auth WHERE eth_addr = $1;",
  34. addr,
  35. ))
  36. }
  37. // AddTxAPI inserts a tx to the pool
  38. func (l2db *L2DB) AddTxAPI(tx *PoolL2TxWrite) error {
  39. cancel, err := l2db.apiConnCon.Acquire()
  40. defer cancel()
  41. if err != nil {
  42. return tracerr.Wrap(err)
  43. }
  44. defer l2db.apiConnCon.Release()
  45. row := l2db.dbRead.QueryRow(`SELECT
  46. ($1::NUMERIC * COALESCE(token.usd, 0) * fee_percentage($2::NUMERIC)) /
  47. (10.0 ^ token.decimals::NUMERIC)
  48. FROM token WHERE token.token_id = $3;`,
  49. tx.AmountFloat, tx.Fee, tx.TokenID)
  50. var feeUSD float64
  51. if err := row.Scan(&feeUSD); err != nil {
  52. return tracerr.Wrap(err)
  53. }
  54. if feeUSD < l2db.minFeeUSD {
  55. return tracerr.Wrap(fmt.Errorf("tx.feeUSD (%v) < minFeeUSD (%v)",
  56. feeUSD, l2db.minFeeUSD))
  57. }
  58. if feeUSD > l2db.maxFeeUSD {
  59. return tracerr.Wrap(fmt.Errorf("tx.feeUSD (%v) > maxFeeUSD (%v)",
  60. feeUSD, l2db.maxFeeUSD))
  61. }
  62. // Prepare insert SQL query argument parameters
  63. namesPart, err := meddler.Default.ColumnsQuoted(tx, false)
  64. if err != nil {
  65. return err
  66. }
  67. valuesPart, err := meddler.Default.PlaceholdersString(tx, false)
  68. if err != nil {
  69. return err
  70. }
  71. values, err := meddler.Default.Values(tx, false)
  72. if err != nil {
  73. return err
  74. }
  75. q := fmt.Sprintf(
  76. `INSERT INTO tx_pool (%s)
  77. SELECT %s
  78. WHERE (SELECT COUNT(*) FROM tx_pool WHERE state = $%v AND NOT external_delete) < $%v;`,
  79. namesPart, valuesPart,
  80. len(values)+1, len(values)+2) //nolint:gomnd
  81. values = append(values, common.PoolL2TxStatePending, l2db.maxTxs)
  82. res, err := l2db.dbWrite.Exec(q, values...)
  83. if err != nil {
  84. return tracerr.Wrap(err)
  85. }
  86. rowsAffected, err := res.RowsAffected()
  87. if err != nil {
  88. return tracerr.Wrap(err)
  89. }
  90. if rowsAffected == 0 {
  91. return tracerr.Wrap(errPoolFull)
  92. }
  93. return nil
  94. }
  95. // selectPoolTxAPI select part of queries to get PoolL2TxRead
  96. const selectPoolTxAPI = `SELECT tx_pool.tx_id, hez_idx(tx_pool.from_idx, token.symbol) AS from_idx, tx_pool.effective_from_eth_addr,
  97. tx_pool.effective_from_bjj, hez_idx(tx_pool.to_idx, token.symbol) AS to_idx, tx_pool.effective_to_eth_addr,
  98. tx_pool.effective_to_bjj, tx_pool.token_id, tx_pool.amount, tx_pool.fee, tx_pool.nonce,
  99. tx_pool.state, tx_pool.info, tx_pool.signature, tx_pool.timestamp, tx_pool.batch_num, hez_idx(tx_pool.rq_from_idx, token.symbol) AS rq_from_idx,
  100. hez_idx(tx_pool.rq_to_idx, token.symbol) AS rq_to_idx, tx_pool.rq_to_eth_addr, tx_pool.rq_to_bjj, tx_pool.rq_token_id, tx_pool.rq_amount,
  101. tx_pool.rq_fee, tx_pool.rq_nonce, tx_pool.tx_type,
  102. token.item_id AS token_item_id, token.eth_block_num, token.eth_addr, token.name, token.symbol, token.decimals, token.usd, token.usd_update
  103. FROM tx_pool INNER JOIN token ON tx_pool.token_id = token.token_id `
  104. // GetTxAPI return the specified Tx in PoolTxAPI format
  105. func (l2db *L2DB) GetTxAPI(txID common.TxID) (*PoolTxAPI, error) {
  106. cancel, err := l2db.apiConnCon.Acquire()
  107. defer cancel()
  108. if err != nil {
  109. return nil, tracerr.Wrap(err)
  110. }
  111. defer l2db.apiConnCon.Release()
  112. tx := new(PoolTxAPI)
  113. return tx, tracerr.Wrap(meddler.QueryRow(
  114. l2db.dbRead, tx,
  115. selectPoolTxAPI+"WHERE tx_id = $1;",
  116. txID,
  117. ))
  118. }
  119. // GetPoolTxs return Txs from the pool
  120. func (l2db *L2DB) GetPoolTxs(fromIdx, toIdx *common.Idx, state *common.PoolL2TxState) ([]*PoolTxAPI, error) {
  121. cancel, err := l2db.apiConnCon.Acquire()
  122. defer cancel()
  123. if err != nil {
  124. return nil, tracerr.Wrap(err)
  125. }
  126. defer l2db.apiConnCon.Release()
  127. // Apply filters
  128. nextIsAnd := false
  129. queryStr := selectPoolTxAPI
  130. var args []interface{}
  131. if state != nil {
  132. queryStr += "WHERE state = ? "
  133. args = append(args, state)
  134. nextIsAnd = true
  135. }
  136. if fromIdx != nil && toIdx != nil {
  137. if nextIsAnd {
  138. queryStr += "AND ("
  139. } else {
  140. queryStr += "WHERE ("
  141. }
  142. queryStr += "tx_pool.from_idx = ? "
  143. queryStr += "OR tx_pool.to_idx = ?) "
  144. args = append(args, fromIdx)
  145. args = append(args, toIdx)
  146. } else if fromIdx != nil {
  147. if nextIsAnd {
  148. queryStr += "AND "
  149. } else {
  150. queryStr += "WHERE "
  151. }
  152. queryStr += "tx_pool.from_idx = ?"
  153. args = append(args, fromIdx)
  154. } else if toIdx != nil {
  155. if nextIsAnd {
  156. queryStr += "AND "
  157. } else {
  158. queryStr += "WHERE "
  159. }
  160. queryStr += "tx_pool.to_idx = ?"
  161. args = append(args, toIdx)
  162. }
  163. queryStr += "AND NOT external_delete;"
  164. query := l2db.dbRead.Rebind(queryStr)
  165. txs := []*PoolTxAPI{}
  166. err = meddler.QueryAll(
  167. l2db.dbRead, &txs,
  168. query,
  169. args...)
  170. return txs, tracerr.Wrap(err)
  171. }