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.

194 lines
5.3 KiB

  1. package api
  2. import (
  3. "errors"
  4. "fmt"
  5. "math/big"
  6. "net/http"
  7. ethCommon "github.com/ethereum/go-ethereum/common"
  8. "github.com/gin-gonic/gin"
  9. "github.com/hermeznetwork/hermez-node/api/apitypes"
  10. "github.com/hermeznetwork/hermez-node/common"
  11. "github.com/hermeznetwork/hermez-node/db/l2db"
  12. "github.com/hermeznetwork/tracerr"
  13. "github.com/iden3/go-iden3-crypto/babyjub"
  14. )
  15. func (a *API) postPoolTx(c *gin.Context) {
  16. // Parse body
  17. var receivedTx receivedPoolTx
  18. if err := c.ShouldBindJSON(&receivedTx); err != nil {
  19. retBadReq(err, c)
  20. return
  21. }
  22. // Transform from received to insert format and validate
  23. writeTx := receivedTx.toPoolL2TxWrite()
  24. if err := a.verifyPoolL2TxWrite(writeTx); err != nil {
  25. retBadReq(err, c)
  26. return
  27. }
  28. writeTx.ClientIP = c.ClientIP()
  29. // Insert to DB
  30. if err := a.l2.AddTxAPI(writeTx); err != nil {
  31. retSQLErr(err, c)
  32. return
  33. }
  34. // Return TxID
  35. c.JSON(http.StatusOK, writeTx.TxID.String())
  36. }
  37. func (a *API) getPoolTx(c *gin.Context) {
  38. // Get TxID
  39. txID, err := parseParamTxID(c)
  40. if err != nil {
  41. retBadReq(err, c)
  42. return
  43. }
  44. // Fetch tx from l2DB
  45. tx, err := a.l2.GetTxAPI(txID)
  46. if err != nil {
  47. retSQLErr(err, c)
  48. return
  49. }
  50. // Build successful response
  51. c.JSON(http.StatusOK, tx)
  52. }
  53. type receivedPoolTx struct {
  54. TxID common.TxID `json:"id" binding:"required"`
  55. Type common.TxType `json:"type" binding:"required"`
  56. TokenID common.TokenID `json:"tokenId"`
  57. FromIdx apitypes.StrHezIdx `json:"fromAccountIndex" binding:"required"`
  58. ToIdx *apitypes.StrHezIdx `json:"toAccountIndex"`
  59. ToEthAddr *apitypes.StrHezEthAddr `json:"toHezEthereumAddress"`
  60. ToBJJ *apitypes.StrHezBJJ `json:"toBjj"`
  61. Amount apitypes.StrBigInt `json:"amount" binding:"required"`
  62. Fee common.FeeSelector `json:"fee"`
  63. Nonce common.Nonce `json:"nonce"`
  64. Signature babyjub.SignatureComp `json:"signature" binding:"required"`
  65. RqFromIdx *apitypes.StrHezIdx `json:"requestFromAccountIndex"`
  66. RqToIdx *apitypes.StrHezIdx `json:"requestToAccountIndex"`
  67. RqToEthAddr *apitypes.StrHezEthAddr `json:"requestToHezEthereumAddress"`
  68. RqToBJJ *apitypes.StrHezBJJ `json:"requestToBjj"`
  69. RqTokenID *common.TokenID `json:"requestTokenId"`
  70. RqAmount *apitypes.StrBigInt `json:"requestAmount"`
  71. RqFee *common.FeeSelector `json:"requestFee"`
  72. RqNonce *common.Nonce `json:"requestNonce"`
  73. }
  74. func (tx *receivedPoolTx) toPoolL2TxWrite() *l2db.PoolL2TxWrite {
  75. f := new(big.Float).SetInt((*big.Int)(&tx.Amount))
  76. amountF, _ := f.Float64()
  77. return &l2db.PoolL2TxWrite{
  78. TxID: tx.TxID,
  79. FromIdx: common.Idx(tx.FromIdx),
  80. ToIdx: (*common.Idx)(tx.ToIdx),
  81. ToEthAddr: (*ethCommon.Address)(tx.ToEthAddr),
  82. ToBJJ: (*babyjub.PublicKeyComp)(tx.ToBJJ),
  83. TokenID: tx.TokenID,
  84. Amount: (*big.Int)(&tx.Amount),
  85. AmountFloat: amountF,
  86. Fee: tx.Fee,
  87. Nonce: tx.Nonce,
  88. State: common.PoolL2TxStatePending,
  89. Signature: tx.Signature,
  90. RqFromIdx: (*common.Idx)(tx.RqFromIdx),
  91. RqToIdx: (*common.Idx)(tx.RqToIdx),
  92. RqToEthAddr: (*ethCommon.Address)(tx.RqToEthAddr),
  93. RqToBJJ: (*babyjub.PublicKeyComp)(tx.RqToBJJ),
  94. RqTokenID: tx.RqTokenID,
  95. RqAmount: (*big.Int)(tx.RqAmount),
  96. RqFee: tx.RqFee,
  97. RqNonce: tx.RqNonce,
  98. Type: tx.Type,
  99. }
  100. }
  101. func (a *API) verifyPoolL2TxWrite(txw *l2db.PoolL2TxWrite) error {
  102. poolTx := common.PoolL2Tx{
  103. TxID: txw.TxID,
  104. FromIdx: txw.FromIdx,
  105. TokenID: txw.TokenID,
  106. Amount: txw.Amount,
  107. Fee: txw.Fee,
  108. Nonce: txw.Nonce,
  109. // State: txw.State,
  110. Signature: txw.Signature,
  111. RqAmount: txw.RqAmount,
  112. Type: txw.Type,
  113. }
  114. // ToIdx
  115. if txw.ToIdx != nil {
  116. poolTx.ToIdx = *txw.ToIdx
  117. }
  118. // ToEthAddr
  119. if txw.ToEthAddr == nil {
  120. poolTx.ToEthAddr = common.EmptyAddr
  121. } else {
  122. poolTx.ToEthAddr = *txw.ToEthAddr
  123. }
  124. // ToBJJ
  125. if txw.ToBJJ == nil {
  126. poolTx.ToBJJ = common.EmptyBJJComp
  127. } else {
  128. poolTx.ToBJJ = *txw.ToBJJ
  129. }
  130. // RqFromIdx
  131. if txw.RqFromIdx != nil {
  132. poolTx.RqFromIdx = *txw.RqFromIdx
  133. }
  134. // RqToIdx
  135. if txw.RqToIdx != nil {
  136. poolTx.RqToIdx = *txw.RqToIdx
  137. }
  138. // RqToEthAddr
  139. if txw.RqToEthAddr == nil {
  140. poolTx.RqToEthAddr = common.EmptyAddr
  141. } else {
  142. poolTx.RqToEthAddr = *txw.RqToEthAddr
  143. }
  144. // RqToBJJ
  145. if txw.RqToBJJ == nil {
  146. poolTx.RqToBJJ = common.EmptyBJJComp
  147. } else {
  148. poolTx.RqToBJJ = *txw.RqToBJJ
  149. }
  150. // RqTokenID
  151. if txw.RqTokenID != nil {
  152. poolTx.RqTokenID = *txw.RqTokenID
  153. }
  154. // RqFee
  155. if txw.RqFee != nil {
  156. poolTx.RqFee = *txw.RqFee
  157. }
  158. // RqNonce
  159. if txw.RqNonce != nil {
  160. poolTx.RqNonce = *txw.RqNonce
  161. }
  162. // Check type and id
  163. _, err := common.NewPoolL2Tx(&poolTx)
  164. if err != nil {
  165. return tracerr.Wrap(err)
  166. }
  167. // Validate feeAmount
  168. _, err = common.CalcFeeAmount(poolTx.Amount, poolTx.Fee)
  169. if err != nil {
  170. return tracerr.Wrap(err)
  171. }
  172. // Get public key
  173. account, err := a.h.GetCommonAccountAPI(poolTx.FromIdx)
  174. if err != nil {
  175. return tracerr.Wrap(fmt.Errorf("Error getting from account: %w", err))
  176. }
  177. // Validate TokenID
  178. if poolTx.TokenID != account.TokenID {
  179. return tracerr.Wrap(fmt.Errorf("tx.TokenID (%v) != account.TokenID (%v)",
  180. poolTx.TokenID, account.TokenID))
  181. }
  182. // Check signature
  183. if !poolTx.VerifySignature(a.chainID, account.BJJ) {
  184. return tracerr.Wrap(errors.New("wrong signature"))
  185. }
  186. return nil
  187. }