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.

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