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.

188 lines
5.0 KiB

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