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.

176 lines
4.7 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/iden3/go-iden3-crypto/babyjub"
  12. )
  13. func postPoolTx(c *gin.Context) {
  14. // Parse body
  15. var receivedTx receivedPoolTx
  16. if err := c.ShouldBindJSON(&receivedTx); err != nil {
  17. retBadReq(err, c)
  18. return
  19. }
  20. // Transform from received to insert format and validate
  21. writeTx := receivedTx.toPoolL2TxWrite()
  22. if err := verifyPoolL2TxWrite(writeTx); err != nil {
  23. retBadReq(err, c)
  24. return
  25. }
  26. // Insert to DB
  27. if err := l2.AddTx(writeTx); err != nil {
  28. retSQLErr(err, c)
  29. return
  30. }
  31. // Return TxID
  32. c.JSON(http.StatusOK, writeTx.TxID.String())
  33. }
  34. func getPoolTx(c *gin.Context) {
  35. // Get TxID
  36. txID, err := parseParamTxID(c)
  37. if err != nil {
  38. retBadReq(err, c)
  39. return
  40. }
  41. // Fetch tx from l2DB
  42. tx, err := l2.GetTxAPI(txID)
  43. if err != nil {
  44. retSQLErr(err, c)
  45. return
  46. }
  47. // Build succesfull response
  48. c.JSON(http.StatusOK, tx)
  49. }
  50. type receivedPoolTx struct {
  51. TxID common.TxID `json:"id" binding:"required"`
  52. Type common.TxType `json:"type" binding:"required"`
  53. TokenID common.TokenID `json:"tokenId"`
  54. FromIdx apitypes.StrHezIdx `json:"fromAccountIndex" binding:"required"`
  55. ToIdx *apitypes.StrHezIdx `json:"toAccountIndex"`
  56. ToEthAddr *apitypes.StrHezEthAddr `json:"toHezEthereumAddress"`
  57. ToBJJ *apitypes.StrHezBJJ `json:"toBjj"`
  58. Amount apitypes.StrBigInt `json:"amount" binding:"required"`
  59. Fee common.FeeSelector `json:"fee"`
  60. Nonce common.Nonce `json:"nonce"`
  61. Signature babyjub.SignatureComp `json:"signature" binding:"required"`
  62. RqFromIdx *apitypes.StrHezIdx `json:"requestFromAccountIndex"`
  63. RqToIdx *apitypes.StrHezIdx `json:"requestToAccountIndex"`
  64. RqToEthAddr *apitypes.StrHezEthAddr `json:"requestToHezEthereumAddress"`
  65. RqToBJJ *apitypes.StrHezBJJ `json:"requestToBjj"`
  66. RqTokenID *common.TokenID `json:"requestTokenId"`
  67. RqAmount *apitypes.StrBigInt `json:"requestAmount"`
  68. RqFee *common.FeeSelector `json:"requestFee"`
  69. RqNonce *common.Nonce `json:"requestNonce"`
  70. }
  71. func (tx *receivedPoolTx) toPoolL2TxWrite() *l2db.PoolL2TxWrite {
  72. f := new(big.Float).SetInt((*big.Int)(&tx.Amount))
  73. amountF, _ := f.Float64()
  74. return &l2db.PoolL2TxWrite{
  75. TxID: tx.TxID,
  76. FromIdx: common.Idx(tx.FromIdx),
  77. ToIdx: (*common.Idx)(tx.ToIdx),
  78. ToEthAddr: (*ethCommon.Address)(tx.ToEthAddr),
  79. ToBJJ: (*babyjub.PublicKey)(tx.ToBJJ),
  80. TokenID: tx.TokenID,
  81. Amount: (*big.Int)(&tx.Amount),
  82. AmountFloat: amountF,
  83. Fee: tx.Fee,
  84. Nonce: tx.Nonce,
  85. State: common.PoolL2TxStatePending,
  86. Signature: tx.Signature,
  87. RqFromIdx: (*common.Idx)(tx.RqFromIdx),
  88. RqToIdx: (*common.Idx)(tx.RqToIdx),
  89. RqToEthAddr: (*ethCommon.Address)(tx.RqToEthAddr),
  90. RqToBJJ: (*babyjub.PublicKey)(tx.RqToBJJ),
  91. RqTokenID: tx.RqTokenID,
  92. RqAmount: (*big.Int)(tx.RqAmount),
  93. RqFee: tx.RqFee,
  94. RqNonce: tx.RqNonce,
  95. Type: tx.Type,
  96. }
  97. }
  98. func verifyPoolL2TxWrite(txw *l2db.PoolL2TxWrite) error {
  99. poolTx := common.PoolL2Tx{
  100. TxID: txw.TxID,
  101. FromIdx: txw.FromIdx,
  102. ToBJJ: txw.ToBJJ,
  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. RqToBJJ: txw.RqToBJJ,
  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. // RqFromIdx
  124. if txw.RqFromIdx != nil {
  125. poolTx.RqFromIdx = *txw.RqFromIdx
  126. }
  127. // RqToIdx
  128. if txw.RqToIdx != nil {
  129. poolTx.RqToIdx = *txw.RqToIdx
  130. }
  131. // RqToEthAddr
  132. if txw.RqToEthAddr == nil {
  133. poolTx.RqToEthAddr = common.EmptyAddr
  134. } else {
  135. poolTx.RqToEthAddr = *txw.RqToEthAddr
  136. }
  137. // RqTokenID
  138. if txw.RqTokenID != nil {
  139. poolTx.RqTokenID = *txw.RqTokenID
  140. }
  141. // RqFee
  142. if txw.RqFee != nil {
  143. poolTx.RqFee = *txw.RqFee
  144. }
  145. // RqNonce
  146. if txw.RqNonce != nil {
  147. poolTx.RqNonce = *txw.RqNonce
  148. }
  149. // Check type and id
  150. _, err := common.NewPoolL2Tx(&poolTx)
  151. if err != nil {
  152. return err
  153. }
  154. // Get public key
  155. account, err := s.GetAccount(poolTx.FromIdx)
  156. if err != nil {
  157. return err
  158. }
  159. // Validate feeAmount
  160. _, err = common.CalcFeeAmount(poolTx.Amount, poolTx.Fee)
  161. if err != nil {
  162. return err
  163. }
  164. // Check signature
  165. if !poolTx.VerifySignature(account.PublicKey) {
  166. return errors.New("wrong signature")
  167. }
  168. return nil
  169. }