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.

460 lines
12 KiB

Redo coordinator structure, connect API to node - API: - Modify the constructor so that hardcoded rollup constants don't need to be passed (introduce a `Config` and use `configAPI` internally) - Common: - Update rollup constants with proper *big.Int when required - Add BidCoordinator and Slot structs used by the HistoryDB and Synchronizer. - Add helper methods to AuctionConstants - AuctionVariables: Add column `DefaultSlotSetBidSlotNum` (in the SQL table: `default_slot_set_bid_slot_num`), which indicates at which slotNum does the `DefaultSlotSetBid` specified starts applying. - Config: - Move coordinator exclusive configuration from the node config to the coordinator config - Coordinator: - Reorganize the code towards having the goroutines started and stopped from the coordinator itself instead of the node. - Remove all stop and stopped channels, and use context.Context and sync.WaitGroup instead. - Remove BatchInfo setters and assing variables directly - In ServerProof and ServerProofPool use context instead stop channel. - Use message passing to notify the coordinator about sync updates and reorgs - Introduce the Pipeline, which can be started and stopped by the Coordinator - Introduce the TxManager, which manages ethereum transactions (the TxManager is also in charge of making the forge call to the rollup smart contract). The TxManager keeps ethereum transactions and: 1. Waits for the transaction to be accepted 2. Waits for the transaction to be confirmed for N blocks - In forge logic, first prepare a batch and then wait for an available server proof to have all work ready once the proof server is ready. - Remove the `isForgeSequence` method which was querying the smart contract, and instead use notifications sent by the Synchronizer to figure out if it's forging time. - Update test (which is a minimal test to manually see if the coordinator starts) - HistoryDB: - Add method to get the number of batches in a slot (used to detect when a slot has passed the bid winner forging deadline) - Add method to get the best bid and associated coordinator of a slot (used to detect the forgerAddress that can forge the slot) - General: - Rename some instances of `currentBlock` to `lastBlock` to be more clear. - Node: - Connect the API to the node and call the methods to update cached state when the sync advances blocks. - Call methods to update Coordinator state when the sync advances blocks and finds reorgs. - Synchronizer: - Add Auction field in the Stats, which contain the current slot with info about highest bidder and other related info required to know who can forge in the current block. - Better organization of cached state: - On Sync, update the internal cached state - On Init or Reorg, load the state from HistoryDB into the internal cached state.
3 years ago
Redo coordinator structure, connect API to node - API: - Modify the constructor so that hardcoded rollup constants don't need to be passed (introduce a `Config` and use `configAPI` internally) - Common: - Update rollup constants with proper *big.Int when required - Add BidCoordinator and Slot structs used by the HistoryDB and Synchronizer. - Add helper methods to AuctionConstants - AuctionVariables: Add column `DefaultSlotSetBidSlotNum` (in the SQL table: `default_slot_set_bid_slot_num`), which indicates at which slotNum does the `DefaultSlotSetBid` specified starts applying. - Config: - Move coordinator exclusive configuration from the node config to the coordinator config - Coordinator: - Reorganize the code towards having the goroutines started and stopped from the coordinator itself instead of the node. - Remove all stop and stopped channels, and use context.Context and sync.WaitGroup instead. - Remove BatchInfo setters and assing variables directly - In ServerProof and ServerProofPool use context instead stop channel. - Use message passing to notify the coordinator about sync updates and reorgs - Introduce the Pipeline, which can be started and stopped by the Coordinator - Introduce the TxManager, which manages ethereum transactions (the TxManager is also in charge of making the forge call to the rollup smart contract). The TxManager keeps ethereum transactions and: 1. Waits for the transaction to be accepted 2. Waits for the transaction to be confirmed for N blocks - In forge logic, first prepare a batch and then wait for an available server proof to have all work ready once the proof server is ready. - Remove the `isForgeSequence` method which was querying the smart contract, and instead use notifications sent by the Synchronizer to figure out if it's forging time. - Update test (which is a minimal test to manually see if the coordinator starts) - HistoryDB: - Add method to get the number of batches in a slot (used to detect when a slot has passed the bid winner forging deadline) - Add method to get the best bid and associated coordinator of a slot (used to detect the forgerAddress that can forge the slot) - General: - Rename some instances of `currentBlock` to `lastBlock` to be more clear. - Node: - Connect the API to the node and call the methods to update cached state when the sync advances blocks. - Call methods to update Coordinator state when the sync advances blocks and finds reorgs. - Synchronizer: - Add Auction field in the Stats, which contain the current slot with info about highest bidder and other related info required to know who can forge in the current block. - Better organization of cached state: - On Sync, update the internal cached state - On Init or Reorg, load the state from HistoryDB into the internal cached state.
3 years ago
Redo coordinator structure, connect API to node - API: - Modify the constructor so that hardcoded rollup constants don't need to be passed (introduce a `Config` and use `configAPI` internally) - Common: - Update rollup constants with proper *big.Int when required - Add BidCoordinator and Slot structs used by the HistoryDB and Synchronizer. - Add helper methods to AuctionConstants - AuctionVariables: Add column `DefaultSlotSetBidSlotNum` (in the SQL table: `default_slot_set_bid_slot_num`), which indicates at which slotNum does the `DefaultSlotSetBid` specified starts applying. - Config: - Move coordinator exclusive configuration from the node config to the coordinator config - Coordinator: - Reorganize the code towards having the goroutines started and stopped from the coordinator itself instead of the node. - Remove all stop and stopped channels, and use context.Context and sync.WaitGroup instead. - Remove BatchInfo setters and assing variables directly - In ServerProof and ServerProofPool use context instead stop channel. - Use message passing to notify the coordinator about sync updates and reorgs - Introduce the Pipeline, which can be started and stopped by the Coordinator - Introduce the TxManager, which manages ethereum transactions (the TxManager is also in charge of making the forge call to the rollup smart contract). The TxManager keeps ethereum transactions and: 1. Waits for the transaction to be accepted 2. Waits for the transaction to be confirmed for N blocks - In forge logic, first prepare a batch and then wait for an available server proof to have all work ready once the proof server is ready. - Remove the `isForgeSequence` method which was querying the smart contract, and instead use notifications sent by the Synchronizer to figure out if it's forging time. - Update test (which is a minimal test to manually see if the coordinator starts) - HistoryDB: - Add method to get the number of batches in a slot (used to detect when a slot has passed the bid winner forging deadline) - Add method to get the best bid and associated coordinator of a slot (used to detect the forgerAddress that can forge the slot) - General: - Rename some instances of `currentBlock` to `lastBlock` to be more clear. - Node: - Connect the API to the node and call the methods to update cached state when the sync advances blocks. - Call methods to update Coordinator state when the sync advances blocks and finds reorgs. - Synchronizer: - Add Auction field in the Stats, which contain the current slot with info about highest bidder and other related info required to know who can forge in the current block. - Better organization of cached state: - On Sync, update the internal cached state - On Init or Reorg, load the state from HistoryDB into the internal cached state.
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
Redo coordinator structure, connect API to node - API: - Modify the constructor so that hardcoded rollup constants don't need to be passed (introduce a `Config` and use `configAPI` internally) - Common: - Update rollup constants with proper *big.Int when required - Add BidCoordinator and Slot structs used by the HistoryDB and Synchronizer. - Add helper methods to AuctionConstants - AuctionVariables: Add column `DefaultSlotSetBidSlotNum` (in the SQL table: `default_slot_set_bid_slot_num`), which indicates at which slotNum does the `DefaultSlotSetBid` specified starts applying. - Config: - Move coordinator exclusive configuration from the node config to the coordinator config - Coordinator: - Reorganize the code towards having the goroutines started and stopped from the coordinator itself instead of the node. - Remove all stop and stopped channels, and use context.Context and sync.WaitGroup instead. - Remove BatchInfo setters and assing variables directly - In ServerProof and ServerProofPool use context instead stop channel. - Use message passing to notify the coordinator about sync updates and reorgs - Introduce the Pipeline, which can be started and stopped by the Coordinator - Introduce the TxManager, which manages ethereum transactions (the TxManager is also in charge of making the forge call to the rollup smart contract). The TxManager keeps ethereum transactions and: 1. Waits for the transaction to be accepted 2. Waits for the transaction to be confirmed for N blocks - In forge logic, first prepare a batch and then wait for an available server proof to have all work ready once the proof server is ready. - Remove the `isForgeSequence` method which was querying the smart contract, and instead use notifications sent by the Synchronizer to figure out if it's forging time. - Update test (which is a minimal test to manually see if the coordinator starts) - HistoryDB: - Add method to get the number of batches in a slot (used to detect when a slot has passed the bid winner forging deadline) - Add method to get the best bid and associated coordinator of a slot (used to detect the forgerAddress that can forge the slot) - General: - Rename some instances of `currentBlock` to `lastBlock` to be more clear. - Node: - Connect the API to the node and call the methods to update cached state when the sync advances blocks. - Call methods to update Coordinator state when the sync advances blocks and finds reorgs. - Synchronizer: - Add Auction field in the Stats, which contain the current slot with info about highest bidder and other related info required to know who can forge in the current block. - Better organization of cached state: - On Sync, update the internal cached state - On Init or Reorg, load the state from HistoryDB into the internal cached state.
3 years ago
Redo coordinator structure, connect API to node - API: - Modify the constructor so that hardcoded rollup constants don't need to be passed (introduce a `Config` and use `configAPI` internally) - Common: - Update rollup constants with proper *big.Int when required - Add BidCoordinator and Slot structs used by the HistoryDB and Synchronizer. - Add helper methods to AuctionConstants - AuctionVariables: Add column `DefaultSlotSetBidSlotNum` (in the SQL table: `default_slot_set_bid_slot_num`), which indicates at which slotNum does the `DefaultSlotSetBid` specified starts applying. - Config: - Move coordinator exclusive configuration from the node config to the coordinator config - Coordinator: - Reorganize the code towards having the goroutines started and stopped from the coordinator itself instead of the node. - Remove all stop and stopped channels, and use context.Context and sync.WaitGroup instead. - Remove BatchInfo setters and assing variables directly - In ServerProof and ServerProofPool use context instead stop channel. - Use message passing to notify the coordinator about sync updates and reorgs - Introduce the Pipeline, which can be started and stopped by the Coordinator - Introduce the TxManager, which manages ethereum transactions (the TxManager is also in charge of making the forge call to the rollup smart contract). The TxManager keeps ethereum transactions and: 1. Waits for the transaction to be accepted 2. Waits for the transaction to be confirmed for N blocks - In forge logic, first prepare a batch and then wait for an available server proof to have all work ready once the proof server is ready. - Remove the `isForgeSequence` method which was querying the smart contract, and instead use notifications sent by the Synchronizer to figure out if it's forging time. - Update test (which is a minimal test to manually see if the coordinator starts) - HistoryDB: - Add method to get the number of batches in a slot (used to detect when a slot has passed the bid winner forging deadline) - Add method to get the best bid and associated coordinator of a slot (used to detect the forgerAddress that can forge the slot) - General: - Rename some instances of `currentBlock` to `lastBlock` to be more clear. - Node: - Connect the API to the node and call the methods to update cached state when the sync advances blocks. - Call methods to update Coordinator state when the sync advances blocks and finds reorgs. - Synchronizer: - Add Auction field in the Stats, which contain the current slot with info about highest bidder and other related info required to know who can forge in the current block. - Better organization of cached state: - On Sync, update the internal cached state - On Init or Reorg, load the state from HistoryDB into the internal cached state.
3 years ago
  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/hermeznetwork/hermez-node/db/historydb"
  11. "github.com/hermeznetwork/tracerr"
  12. "github.com/iden3/go-iden3-crypto/babyjub"
  13. )
  14. const exitIdx = "hez:EXIT:1"
  15. // Query parsers
  16. type querier interface {
  17. Query(string) string
  18. }
  19. func parsePagination(c querier) (fromItem *uint, order string, limit *uint, err error) {
  20. // FromItem
  21. fromItem, err = parseQueryUint("fromItem", nil, 0, maxUint32, c)
  22. if err != nil {
  23. return nil, "", nil, tracerr.Wrap(err)
  24. }
  25. // Order
  26. order = dfltOrder
  27. const orderName = "order"
  28. orderStr := c.Query(orderName)
  29. if orderStr != "" && !(orderStr == historydb.OrderAsc || historydb.OrderDesc == orderStr) {
  30. return nil, "", nil, tracerr.Wrap(errors.New(
  31. "order must have the value " + historydb.OrderAsc + " or " + historydb.OrderDesc,
  32. ))
  33. }
  34. if orderStr == historydb.OrderAsc {
  35. order = historydb.OrderAsc
  36. } else if orderStr == historydb.OrderDesc {
  37. order = historydb.OrderDesc
  38. }
  39. // Limit
  40. limit = new(uint)
  41. *limit = dfltLimit
  42. limit, err = parseQueryUint("limit", limit, 1, maxLimit, c)
  43. if err != nil {
  44. return nil, "", nil, tracerr.Wrap(err)
  45. }
  46. return fromItem, order, limit, nil
  47. }
  48. // nolint reason: res may be not overwriten
  49. func parseQueryUint(name string, dflt *uint, min, max uint, c querier) (*uint, error) { //nolint:SA4009
  50. str := c.Query(name)
  51. return stringToUint(str, name, dflt, min, max)
  52. }
  53. // nolint reason: res may be not overwriten
  54. func parseQueryInt64(name string, dflt *int64, min, max int64, c querier) (*int64, error) { //nolint:SA4009
  55. str := c.Query(name)
  56. return stringToInt64(str, name, dflt, min, max)
  57. }
  58. // nolint reason: res may be not overwriten
  59. func parseQueryBool(name string, dflt *bool, c querier) (*bool, error) { //nolint:SA4009
  60. str := c.Query(name)
  61. if str == "" {
  62. return dflt, nil
  63. }
  64. if str == "true" {
  65. res := new(bool)
  66. *res = true
  67. return res, nil
  68. }
  69. if str == "false" {
  70. res := new(bool)
  71. *res = false
  72. return res, nil
  73. }
  74. return nil, tracerr.Wrap(fmt.Errorf("Invalid %s. Must be eithe true or false", name))
  75. }
  76. func parseQueryHezEthAddr(c querier) (*ethCommon.Address, error) {
  77. const name = "hermezEthereumAddress"
  78. addrStr := c.Query(name)
  79. return hezStringToEthAddr(addrStr, name)
  80. }
  81. func parseQueryBJJ(c querier) (*babyjub.PublicKey, error) {
  82. const name = "BJJ"
  83. bjjStr := c.Query(name)
  84. if bjjStr == "" {
  85. return nil, nil
  86. }
  87. return hezStringToBJJ(bjjStr, name)
  88. }
  89. func parseQueryTxType(c querier) (*common.TxType, error) {
  90. const name = "type"
  91. typeStr := c.Query(name)
  92. if typeStr == "" {
  93. return nil, nil
  94. }
  95. switch common.TxType(typeStr) {
  96. case common.TxTypeExit:
  97. ret := common.TxTypeExit
  98. return &ret, nil
  99. case common.TxTypeTransfer:
  100. ret := common.TxTypeTransfer
  101. return &ret, nil
  102. case common.TxTypeDeposit:
  103. ret := common.TxTypeDeposit
  104. return &ret, nil
  105. case common.TxTypeCreateAccountDeposit:
  106. ret := common.TxTypeCreateAccountDeposit
  107. return &ret, nil
  108. case common.TxTypeCreateAccountDepositTransfer:
  109. ret := common.TxTypeCreateAccountDepositTransfer
  110. return &ret, nil
  111. case common.TxTypeDepositTransfer:
  112. ret := common.TxTypeDepositTransfer
  113. return &ret, nil
  114. case common.TxTypeForceTransfer:
  115. ret := common.TxTypeForceTransfer
  116. return &ret, nil
  117. case common.TxTypeForceExit:
  118. ret := common.TxTypeForceExit
  119. return &ret, nil
  120. case common.TxTypeTransferToEthAddr:
  121. ret := common.TxTypeTransferToEthAddr
  122. return &ret, nil
  123. case common.TxTypeTransferToBJJ:
  124. ret := common.TxTypeTransferToBJJ
  125. return &ret, nil
  126. }
  127. return nil, tracerr.Wrap(fmt.Errorf(
  128. "invalid %s, %s is not a valid option. Check the valid options in the docmentation",
  129. name, typeStr,
  130. ))
  131. }
  132. func parseIdx(c querier) (*common.Idx, error) {
  133. const name = "accountIndex"
  134. idxStr := c.Query(name)
  135. return stringToIdx(idxStr, name)
  136. }
  137. func parseExitFilters(c querier) (*common.TokenID, *ethCommon.Address, *babyjub.PublicKey, *common.Idx, error) {
  138. // TokenID
  139. tid, err := parseQueryUint("tokenId", nil, 0, maxUint32, c)
  140. if err != nil {
  141. return nil, nil, nil, nil, tracerr.Wrap(err)
  142. }
  143. var tokenID *common.TokenID
  144. if tid != nil {
  145. tokenID = new(common.TokenID)
  146. *tokenID = common.TokenID(*tid)
  147. }
  148. // Hez Eth addr
  149. addr, err := parseQueryHezEthAddr(c)
  150. if err != nil {
  151. return nil, nil, nil, nil, tracerr.Wrap(err)
  152. }
  153. // BJJ
  154. bjj, err := parseQueryBJJ(c)
  155. if err != nil {
  156. return nil, nil, nil, nil, tracerr.Wrap(err)
  157. }
  158. if addr != nil && bjj != nil {
  159. return nil, nil, nil, nil, tracerr.Wrap(errors.New("bjj and hermezEthereumAddress params are incompatible"))
  160. }
  161. // Idx
  162. idx, err := parseIdx(c)
  163. if err != nil {
  164. return nil, nil, nil, nil, tracerr.Wrap(err)
  165. }
  166. if idx != nil && (addr != nil || bjj != nil || tokenID != nil) {
  167. return nil, nil, nil, nil, tracerr.Wrap(errors.New("accountIndex is incompatible with BJJ, hermezEthereumAddress and tokenId"))
  168. }
  169. return tokenID, addr, bjj, idx, nil
  170. }
  171. func parseTokenFilters(c querier) ([]common.TokenID, []string, string, error) {
  172. idsStr := c.Query("ids")
  173. symbolsStr := c.Query("symbols")
  174. nameStr := c.Query("name")
  175. var tokensIDs []common.TokenID
  176. if idsStr != "" {
  177. ids := strings.Split(idsStr, ",")
  178. for _, id := range ids {
  179. idUint, err := strconv.Atoi(id)
  180. if err != nil {
  181. return nil, nil, "", tracerr.Wrap(err)
  182. }
  183. tokenID := common.TokenID(idUint)
  184. tokensIDs = append(tokensIDs, tokenID)
  185. }
  186. }
  187. var symbols []string
  188. if symbolsStr != "" {
  189. symbols = strings.Split(symbolsStr, ",")
  190. }
  191. return tokensIDs, symbols, nameStr, nil
  192. }
  193. func parseBidFilters(c querier) (*int64, *ethCommon.Address, error) {
  194. slotNum, err := parseQueryInt64("slotNum", nil, 0, maxInt64, c)
  195. if err != nil {
  196. return nil, nil, tracerr.Wrap(err)
  197. }
  198. bidderAddr, err := parseQueryEthAddr("bidderAddr", c)
  199. if err != nil {
  200. return nil, nil, tracerr.Wrap(err)
  201. }
  202. return slotNum, bidderAddr, nil
  203. }
  204. func parseSlotFilters(c querier) (*int64, *int64, *ethCommon.Address, *bool, error) {
  205. minSlotNum, err := parseQueryInt64("minSlotNum", nil, 0, maxInt64, c)
  206. if err != nil {
  207. return nil, nil, nil, nil, tracerr.Wrap(err)
  208. }
  209. maxSlotNum, err := parseQueryInt64("maxSlotNum", nil, 0, maxInt64, c)
  210. if err != nil {
  211. return nil, nil, nil, nil, tracerr.Wrap(err)
  212. }
  213. wonByEthereumAddress, err := parseQueryEthAddr("wonByEthereumAddress", c)
  214. if err != nil {
  215. return nil, nil, nil, nil, tracerr.Wrap(err)
  216. }
  217. finishedAuction, err := parseQueryBool("finishedAuction", nil, c)
  218. if err != nil {
  219. return nil, nil, nil, nil, tracerr.Wrap(err)
  220. }
  221. return minSlotNum, maxSlotNum, wonByEthereumAddress, finishedAuction, nil
  222. }
  223. func parseAccountFilters(c querier) ([]common.TokenID, *ethCommon.Address, *babyjub.PublicKey, error) {
  224. // TokenID
  225. idsStr := c.Query("tokenIds")
  226. var tokenIDs []common.TokenID
  227. if idsStr != "" {
  228. ids := strings.Split(idsStr, ",")
  229. for _, id := range ids {
  230. idUint, err := strconv.Atoi(id)
  231. if err != nil {
  232. return nil, nil, nil, tracerr.Wrap(err)
  233. }
  234. tokenID := common.TokenID(idUint)
  235. tokenIDs = append(tokenIDs, tokenID)
  236. }
  237. }
  238. // Hez Eth addr
  239. addr, err := parseQueryHezEthAddr(c)
  240. if err != nil {
  241. return nil, nil, nil, tracerr.Wrap(err)
  242. }
  243. // BJJ
  244. bjj, err := parseQueryBJJ(c)
  245. if err != nil {
  246. return nil, nil, nil, tracerr.Wrap(err)
  247. }
  248. if addr != nil && bjj != nil {
  249. return nil, nil, nil, tracerr.Wrap(errors.New("bjj and hermezEthereumAddress params are incompatible"))
  250. }
  251. return tokenIDs, addr, bjj, nil
  252. }
  253. // Param parsers
  254. type paramer interface {
  255. Param(string) string
  256. }
  257. func parseParamTxID(c paramer) (common.TxID, error) {
  258. const name = "id"
  259. txIDStr := c.Param(name)
  260. if txIDStr == "" {
  261. return common.TxID{}, tracerr.Wrap(fmt.Errorf("%s is required", name))
  262. }
  263. txID, err := common.NewTxIDFromString(txIDStr)
  264. if err != nil {
  265. return common.TxID{}, tracerr.Wrap(fmt.Errorf("invalid %s", name))
  266. }
  267. return txID, nil
  268. }
  269. func parseParamIdx(c paramer) (*common.Idx, error) {
  270. const name = "accountIndex"
  271. idxStr := c.Param(name)
  272. return stringToIdx(idxStr, name)
  273. }
  274. // nolint reason: res may be not overwriten
  275. func parseParamUint(name string, dflt *uint, min, max uint, c paramer) (*uint, error) { //nolint:SA4009
  276. str := c.Param(name)
  277. return stringToUint(str, name, dflt, min, max)
  278. }
  279. // nolint reason: res may be not overwriten
  280. func parseParamInt64(name string, dflt *int64, min, max int64, c paramer) (*int64, error) { //nolint:SA4009
  281. str := c.Param(name)
  282. return stringToInt64(str, name, dflt, min, max)
  283. }
  284. func stringToIdx(idxStr, name string) (*common.Idx, error) {
  285. if idxStr == "" {
  286. return nil, nil
  287. }
  288. splitted := strings.Split(idxStr, ":")
  289. const expectedLen = 3
  290. if len(splitted) != expectedLen || splitted[0] != "hez" {
  291. return nil, tracerr.Wrap(fmt.Errorf(
  292. "invalid %s, must follow this: hez:<tokenSymbol>:index", name))
  293. }
  294. // TODO: check that the tokenSymbol match the token related to the account index
  295. idxInt, err := strconv.Atoi(splitted[2])
  296. idx := common.Idx(idxInt)
  297. return &idx, tracerr.Wrap(err)
  298. }
  299. func stringToUint(uintStr, name string, dflt *uint, min, max uint) (*uint, error) {
  300. if uintStr != "" {
  301. resInt, err := strconv.Atoi(uintStr)
  302. if err != nil || resInt < 0 || resInt < int(min) || resInt > int(max) {
  303. return nil, tracerr.Wrap(fmt.Errorf(
  304. "Invalid %s. Must be an integer within the range [%d, %d]",
  305. name, min, max))
  306. }
  307. res := uint(resInt)
  308. return &res, nil
  309. }
  310. return dflt, nil
  311. }
  312. func stringToInt64(uintStr, name string, dflt *int64, min, max int64) (*int64, error) {
  313. if uintStr != "" {
  314. resInt, err := strconv.Atoi(uintStr)
  315. if err != nil || resInt < 0 || resInt < int(min) || resInt > int(max) {
  316. return nil, tracerr.Wrap(fmt.Errorf(
  317. "Invalid %s. Must be an integer within the range [%d, %d]",
  318. name, min, max))
  319. }
  320. res := int64(resInt)
  321. return &res, nil
  322. }
  323. return dflt, nil
  324. }
  325. func hezStringToEthAddr(addrStr, name string) (*ethCommon.Address, error) {
  326. if addrStr == "" {
  327. return nil, nil
  328. }
  329. splitted := strings.Split(addrStr, "hez:")
  330. if len(splitted) != 2 || len(splitted[1]) != 42 {
  331. return nil, tracerr.Wrap(fmt.Errorf(
  332. "Invalid %s, must follow this regex: ^hez:0x[a-fA-F0-9]{40}$", name))
  333. }
  334. var addr ethCommon.Address
  335. err := addr.UnmarshalText([]byte(splitted[1]))
  336. return &addr, tracerr.Wrap(err)
  337. }
  338. func hezStringToBJJ(bjjStr, name string) (*babyjub.PublicKey, error) {
  339. const decodedLen = 33
  340. splitted := strings.Split(bjjStr, "hez:")
  341. if len(splitted) != 2 || len(splitted[1]) != 44 {
  342. return nil, tracerr.Wrap(fmt.Errorf(
  343. "Invalid %s, must follow this regex: ^hez:[A-Za-z0-9+/=]{44}$",
  344. name))
  345. }
  346. decoded, err := base64.RawURLEncoding.DecodeString(splitted[1])
  347. if err != nil {
  348. return nil, tracerr.Wrap(fmt.Errorf(
  349. "Invalid %s, error decoding base64 string: %s",
  350. name, err.Error()))
  351. }
  352. if len(decoded) != decodedLen {
  353. return nil, tracerr.Wrap(fmt.Errorf(
  354. "invalid %s, error decoding base64 string: unexpected byte array length",
  355. name))
  356. }
  357. bjjBytes := [decodedLen - 1]byte{}
  358. copy(bjjBytes[:decodedLen-1], decoded[:decodedLen-1])
  359. sum := bjjBytes[0]
  360. for i := 1; i < len(bjjBytes); i++ {
  361. sum += bjjBytes[i]
  362. }
  363. if decoded[decodedLen-1] != sum {
  364. return nil, tracerr.Wrap(fmt.Errorf("invalid %s, checksum failed",
  365. name))
  366. }
  367. bjjComp := babyjub.PublicKeyComp(bjjBytes)
  368. bjj, err := bjjComp.Decompress()
  369. if err != nil {
  370. return nil, tracerr.Wrap(fmt.Errorf(
  371. "invalid %s, error decompressing public key: %s",
  372. name, err.Error()))
  373. }
  374. return bjj, nil
  375. }
  376. func parseQueryEthAddr(name string, c querier) (*ethCommon.Address, error) {
  377. addrStr := c.Query(name)
  378. if addrStr == "" {
  379. return nil, nil
  380. }
  381. return parseEthAddr(addrStr)
  382. }
  383. func parseParamEthAddr(name string, c paramer) (*ethCommon.Address, error) {
  384. addrStr := c.Param(name)
  385. if addrStr == "" {
  386. return nil, nil
  387. }
  388. return parseEthAddr(addrStr)
  389. }
  390. func parseEthAddr(ethAddrStr string) (*ethCommon.Address, error) {
  391. var addr ethCommon.Address
  392. err := addr.UnmarshalText([]byte(ethAddrStr))
  393. return &addr, tracerr.Wrap(err)
  394. }
  395. func parseParamHezEthAddr(c paramer) (*ethCommon.Address, error) {
  396. const name = "hermezEthereumAddress"
  397. addrStr := c.Param(name)
  398. return hezStringToEthAddr(addrStr, name)
  399. }
  400. type errorMsg struct {
  401. Message string
  402. }
  403. func bjjToString(bjj *babyjub.PublicKey) string {
  404. pkComp := [32]byte(bjj.Compress())
  405. sum := pkComp[0]
  406. for i := 1; i < len(pkComp); i++ {
  407. sum += pkComp[i]
  408. }
  409. bjjSum := append(pkComp[:], sum)
  410. return "hez:" + base64.RawURLEncoding.EncodeToString(bjjSum)
  411. }
  412. func ethAddrToHez(addr ethCommon.Address) string {
  413. return "hez:" + addr.String()
  414. }
  415. func idxToHez(idx common.Idx, tokenSymbol string) string {
  416. if idx == 1 {
  417. return exitIdx
  418. }
  419. return "hez:" + tokenSymbol + ":" + strconv.Itoa(int(idx))
  420. }