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.

204 lines
5.1 KiB

  1. package api
  2. import (
  3. "encoding/base64"
  4. "errors"
  5. "fmt"
  6. "strconv"
  7. "strings"
  8. ethCommon "github.com/ethereum/go-ethereum/common"
  9. "github.com/hermeznetwork/hermez-node/common"
  10. "github.com/iden3/go-iden3-crypto/babyjub"
  11. )
  12. type querier interface {
  13. Query(string) string
  14. }
  15. func parsePagination(c querier) (*uint, *bool, *uint, error) {
  16. // Offset
  17. offset := new(uint)
  18. *offset = 0
  19. offset, err := parseQueryUint("offset", offset, 0, maxUint32, c)
  20. if err != nil {
  21. return nil, nil, nil, err
  22. }
  23. // Last
  24. last := new(bool)
  25. *last = dfltLast
  26. last, err = parseQueryBool("last", last, c)
  27. if err != nil {
  28. return nil, nil, nil, err
  29. }
  30. if *last && (offset != nil && *offset > 0) {
  31. return nil, nil, nil, errors.New(
  32. "last and offset are incompatible, provide only one of them",
  33. )
  34. }
  35. // Limit
  36. limit := new(uint)
  37. *limit = dfltLimit
  38. limit, err = parseQueryUint("limit", limit, 1, maxLimit, c)
  39. if err != nil {
  40. return nil, nil, nil, err
  41. }
  42. return offset, last, limit, nil
  43. }
  44. func parseQueryUint(name string, dflt *uint, min, max uint, c querier) (*uint, error) { //nolint:SA4009 res may be not overwriten
  45. str := c.Query(name)
  46. if str != "" {
  47. resInt, err := strconv.Atoi(str)
  48. if err != nil || resInt < 0 || resInt < int(min) || resInt > int(max) {
  49. return nil, fmt.Errorf(
  50. "Inavlid %s. Must be an integer within the range [%d, %d]",
  51. name, min, max)
  52. }
  53. res := uint(resInt)
  54. return &res, nil
  55. }
  56. return dflt, nil
  57. }
  58. func parseQueryBool(name string, dflt *bool, c querier) (*bool, error) { //nolint:SA4009 res may be not overwriten
  59. str := c.Query(name)
  60. if str == "" {
  61. return dflt, nil
  62. }
  63. if str == "true" {
  64. res := new(bool)
  65. *res = true
  66. return res, nil
  67. }
  68. if str == "false" {
  69. res := new(bool)
  70. *res = false
  71. return res, nil
  72. }
  73. return nil, fmt.Errorf("Inavlid %s. Must be eithe true or false", name)
  74. }
  75. func parseQueryHezEthAddr(c querier) (*ethCommon.Address, error) {
  76. const name = "hermezEthereumAddress"
  77. addrStr := c.Query(name)
  78. if addrStr == "" {
  79. return nil, nil
  80. }
  81. splitted := strings.Split(addrStr, "hez:")
  82. if len(splitted) != 2 || len(splitted[1]) != 42 {
  83. return nil, fmt.Errorf(
  84. "Invalid %s, must follow this regex: ^hez:0x[a-fA-F0-9]{40}$", name)
  85. }
  86. var addr ethCommon.Address
  87. err := addr.UnmarshalText([]byte(splitted[1]))
  88. return &addr, err
  89. }
  90. func parseQueryBJJ(c querier) (*babyjub.PublicKey, error) {
  91. const name = "BJJ"
  92. const decodedLen = 33
  93. bjjStr := c.Query(name)
  94. if bjjStr == "" {
  95. return nil, nil
  96. }
  97. splitted := strings.Split(bjjStr, "hez:")
  98. if len(splitted) != 2 || len(splitted[1]) != 44 {
  99. return nil, fmt.Errorf(
  100. "Invalid %s, must follow this regex: ^hez:[A-Za-z0-9+/=]{44}$",
  101. name)
  102. }
  103. decoded, err := base64.RawURLEncoding.DecodeString(splitted[1])
  104. if err != nil {
  105. return nil, fmt.Errorf(
  106. "Invalid %s, error decoding base64 string: %s",
  107. name, err.Error())
  108. }
  109. if len(decoded) != decodedLen {
  110. return nil, fmt.Errorf(
  111. "invalid %s, error decoding base64 string: unexpected byte array length",
  112. name)
  113. }
  114. bjjBytes := [decodedLen - 1]byte{}
  115. copy(bjjBytes[:decodedLen-1], decoded[:decodedLen-1])
  116. sum := bjjBytes[0]
  117. for i := 1; i < len(bjjBytes); i++ {
  118. sum += bjjBytes[i]
  119. }
  120. if decoded[decodedLen-1] != sum {
  121. return nil, fmt.Errorf("invalid %s, checksum failed",
  122. name)
  123. }
  124. bjjComp := babyjub.PublicKeyComp(bjjBytes)
  125. bjj, err := bjjComp.Decompress()
  126. if err != nil {
  127. return nil, fmt.Errorf(
  128. "invalid %s, error decompressing public key: %s",
  129. name, err.Error())
  130. }
  131. return bjj, nil
  132. }
  133. func parseQueryTxType(c querier) (*common.TxType, error) {
  134. const name = "type"
  135. typeStr := c.Query(name)
  136. if typeStr == "" {
  137. return nil, nil
  138. }
  139. switch common.TxType(typeStr) {
  140. case common.TxTypeExit:
  141. ret := common.TxTypeExit
  142. return &ret, nil
  143. case common.TxTypeWithdrawn:
  144. ret := common.TxTypeWithdrawn
  145. return &ret, nil
  146. case common.TxTypeTransfer:
  147. ret := common.TxTypeTransfer
  148. return &ret, nil
  149. case common.TxTypeDeposit:
  150. ret := common.TxTypeDeposit
  151. return &ret, nil
  152. case common.TxTypeCreateAccountDeposit:
  153. ret := common.TxTypeCreateAccountDeposit
  154. return &ret, nil
  155. case common.TxTypeCreateAccountDepositTransfer:
  156. ret := common.TxTypeCreateAccountDepositTransfer
  157. return &ret, nil
  158. case common.TxTypeDepositTransfer:
  159. ret := common.TxTypeDepositTransfer
  160. return &ret, nil
  161. case common.TxTypeForceTransfer:
  162. ret := common.TxTypeForceTransfer
  163. return &ret, nil
  164. case common.TxTypeForceExit:
  165. ret := common.TxTypeForceExit
  166. return &ret, nil
  167. case common.TxTypeTransferToEthAddr:
  168. ret := common.TxTypeTransferToEthAddr
  169. return &ret, nil
  170. case common.TxTypeTransferToBJJ:
  171. ret := common.TxTypeTransferToBJJ
  172. return &ret, nil
  173. }
  174. return nil, fmt.Errorf(
  175. "invalid %s, %s is not a valid option. Check the valid options in the docmentation",
  176. name, typeStr,
  177. )
  178. }
  179. func parseIdx(c querier) (*uint, error) {
  180. const name = "accountIndex"
  181. addrStr := c.Query(name)
  182. if addrStr == "" {
  183. return nil, nil
  184. }
  185. splitted := strings.Split(addrStr, ":")
  186. const expectedLen = 3
  187. if len(splitted) != expectedLen {
  188. return nil, fmt.Errorf(
  189. "invalid %s, must follow this: hez:<tokenSymbol>:index", name)
  190. }
  191. idxInt, err := strconv.Atoi(splitted[2])
  192. idx := uint(idxInt)
  193. return &idx, err
  194. }