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.

325 lines
8.8 KiB

Update coordinator, call all api update functions - Common: - Rename Block.EthBlockNum to Block.Num to avoid unneeded repetition - API: - Add UpdateNetworkInfoBlock to update just block information, to be used when the node is not yet synchronized - Node: - Call API.UpdateMetrics and UpdateRecommendedFee in a loop, with configurable time intervals - Synchronizer: - When mapping events by TxHash, use an array to support the possibility of multiple calls of the same function happening in the same transaction (for example, a smart contract in a single transaction could call withdraw with delay twice, which would generate 2 withdraw events, and 2 deposit events). - In Stats, keep entire LastBlock instead of just the blockNum - In Stats, add lastL1BatchBlock - Test Stats and SCVars - Coordinator: - Enable writing the BatchInfo in every step of the pipeline to disk (with JSON text files) for debugging purposes. - Move the Pipeline functionality from the Coordinator to its own struct (Pipeline) - Implement shouldL1lL2Batch - In TxManager, implement logic to perform several attempts when doing ethereum node RPC calls before considering the error. (Both for calls to forgeBatch and transaction receipt) - In TxManager, reorganize the flow and note the specific points in which actions are made when err != nil - HistoryDB: - Implement GetLastL1BatchBlockNum: returns the blockNum of the latest forged l1Batch, to help the coordinator decide when to forge an L1Batch. - EthereumClient and test.Client: - Update EthBlockByNumber to return the last block when the passed number is -1.
4 years ago
Update coordinator, call all api update functions - Common: - Rename Block.EthBlockNum to Block.Num to avoid unneeded repetition - API: - Add UpdateNetworkInfoBlock to update just block information, to be used when the node is not yet synchronized - Node: - Call API.UpdateMetrics and UpdateRecommendedFee in a loop, with configurable time intervals - Synchronizer: - When mapping events by TxHash, use an array to support the possibility of multiple calls of the same function happening in the same transaction (for example, a smart contract in a single transaction could call withdraw with delay twice, which would generate 2 withdraw events, and 2 deposit events). - In Stats, keep entire LastBlock instead of just the blockNum - In Stats, add lastL1BatchBlock - Test Stats and SCVars - Coordinator: - Enable writing the BatchInfo in every step of the pipeline to disk (with JSON text files) for debugging purposes. - Move the Pipeline functionality from the Coordinator to its own struct (Pipeline) - Implement shouldL1lL2Batch - In TxManager, implement logic to perform several attempts when doing ethereum node RPC calls before considering the error. (Both for calls to forgeBatch and transaction receipt) - In TxManager, reorganize the flow and note the specific points in which actions are made when err != nil - HistoryDB: - Implement GetLastL1BatchBlockNum: returns the blockNum of the latest forged l1Batch, to help the coordinator decide when to forge an L1Batch. - EthereumClient and test.Client: - Update EthBlockByNumber to return the last block when the passed number is -1.
4 years ago
Update coordinator, call all api update functions - Common: - Rename Block.EthBlockNum to Block.Num to avoid unneeded repetition - API: - Add UpdateNetworkInfoBlock to update just block information, to be used when the node is not yet synchronized - Node: - Call API.UpdateMetrics and UpdateRecommendedFee in a loop, with configurable time intervals - Synchronizer: - When mapping events by TxHash, use an array to support the possibility of multiple calls of the same function happening in the same transaction (for example, a smart contract in a single transaction could call withdraw with delay twice, which would generate 2 withdraw events, and 2 deposit events). - In Stats, keep entire LastBlock instead of just the blockNum - In Stats, add lastL1BatchBlock - Test Stats and SCVars - Coordinator: - Enable writing the BatchInfo in every step of the pipeline to disk (with JSON text files) for debugging purposes. - Move the Pipeline functionality from the Coordinator to its own struct (Pipeline) - Implement shouldL1lL2Batch - In TxManager, implement logic to perform several attempts when doing ethereum node RPC calls before considering the error. (Both for calls to forgeBatch and transaction receipt) - In TxManager, reorganize the flow and note the specific points in which actions are made when err != nil - HistoryDB: - Implement GetLastL1BatchBlockNum: returns the blockNum of the latest forged l1Batch, to help the coordinator decide when to forge an L1Batch. - EthereumClient and test.Client: - Update EthBlockByNumber to return the last block when the passed number is -1.
4 years ago
Update coordinator, call all api update functions - Common: - Rename Block.EthBlockNum to Block.Num to avoid unneeded repetition - API: - Add UpdateNetworkInfoBlock to update just block information, to be used when the node is not yet synchronized - Node: - Call API.UpdateMetrics and UpdateRecommendedFee in a loop, with configurable time intervals - Synchronizer: - When mapping events by TxHash, use an array to support the possibility of multiple calls of the same function happening in the same transaction (for example, a smart contract in a single transaction could call withdraw with delay twice, which would generate 2 withdraw events, and 2 deposit events). - In Stats, keep entire LastBlock instead of just the blockNum - In Stats, add lastL1BatchBlock - Test Stats and SCVars - Coordinator: - Enable writing the BatchInfo in every step of the pipeline to disk (with JSON text files) for debugging purposes. - Move the Pipeline functionality from the Coordinator to its own struct (Pipeline) - Implement shouldL1lL2Batch - In TxManager, implement logic to perform several attempts when doing ethereum node RPC calls before considering the error. (Both for calls to forgeBatch and transaction receipt) - In TxManager, reorganize the flow and note the specific points in which actions are made when err != nil - HistoryDB: - Implement GetLastL1BatchBlockNum: returns the blockNum of the latest forged l1Batch, to help the coordinator decide when to forge an L1Batch. - EthereumClient and test.Client: - Update EthBlockByNumber to return the last block when the passed number is -1.
4 years ago
Update coordinator, call all api update functions - Common: - Rename Block.EthBlockNum to Block.Num to avoid unneeded repetition - API: - Add UpdateNetworkInfoBlock to update just block information, to be used when the node is not yet synchronized - Node: - Call API.UpdateMetrics and UpdateRecommendedFee in a loop, with configurable time intervals - Synchronizer: - When mapping events by TxHash, use an array to support the possibility of multiple calls of the same function happening in the same transaction (for example, a smart contract in a single transaction could call withdraw with delay twice, which would generate 2 withdraw events, and 2 deposit events). - In Stats, keep entire LastBlock instead of just the blockNum - In Stats, add lastL1BatchBlock - Test Stats and SCVars - Coordinator: - Enable writing the BatchInfo in every step of the pipeline to disk (with JSON text files) for debugging purposes. - Move the Pipeline functionality from the Coordinator to its own struct (Pipeline) - Implement shouldL1lL2Batch - In TxManager, implement logic to perform several attempts when doing ethereum node RPC calls before considering the error. (Both for calls to forgeBatch and transaction receipt) - In TxManager, reorganize the flow and note the specific points in which actions are made when err != nil - HistoryDB: - Implement GetLastL1BatchBlockNum: returns the blockNum of the latest forged l1Batch, to help the coordinator decide when to forge an L1Batch. - EthereumClient and test.Client: - Update EthBlockByNumber to return the last block when the passed number is -1.
4 years ago
  1. package api
  2. import (
  3. "database/sql"
  4. "errors"
  5. "net/http"
  6. "github.com/gin-gonic/gin"
  7. "github.com/hermeznetwork/hermez-node/common"
  8. "github.com/hermeznetwork/hermez-node/db/historydb"
  9. "github.com/hermeznetwork/tracerr"
  10. )
  11. // SlotAPI is a repesentation of a slot information
  12. type SlotAPI struct {
  13. ItemID uint64 `json:"itemId"`
  14. SlotNum int64 `json:"slotNum"`
  15. FirstBlock int64 `json:"firstBlock"`
  16. LastBlock int64 `json:"lastBlock"`
  17. OpenAuction bool `json:"openAuction"`
  18. WinnerBid *historydb.BidAPI `json:"bestBid"`
  19. }
  20. func (a *API) getFirstLastBlock(slotNum int64) (int64, int64) {
  21. genesisBlock := a.cg.AuctionConstants.GenesisBlockNum
  22. blocksPerSlot := int64(a.cg.AuctionConstants.BlocksPerSlot)
  23. firstBlock := slotNum*blocksPerSlot + genesisBlock
  24. lastBlock := (slotNum+1)*blocksPerSlot + genesisBlock - 1
  25. return firstBlock, lastBlock
  26. }
  27. func (a *API) getCurrentSlot(currentBlock int64) int64 {
  28. genesisBlock := a.cg.AuctionConstants.GenesisBlockNum
  29. blocksPerSlot := int64(a.cg.AuctionConstants.BlocksPerSlot)
  30. currentSlot := (currentBlock - genesisBlock) / blocksPerSlot
  31. return currentSlot
  32. }
  33. func (a *API) isOpenAuction(currentBlock, slotNum int64, auctionVars common.AuctionVariables) bool {
  34. currentSlot := a.getCurrentSlot(currentBlock)
  35. closedAuctionSlots := currentSlot + int64(auctionVars.ClosedAuctionSlots)
  36. openAuctionSlots := int64(auctionVars.OpenAuctionSlots)
  37. if slotNum > closedAuctionSlots && slotNum <= (closedAuctionSlots+openAuctionSlots) {
  38. return true
  39. }
  40. return false
  41. }
  42. func (a *API) newSlotAPI(slotNum, currentBlockNum int64, bid *historydb.BidAPI, auctionVars *common.AuctionVariables) SlotAPI {
  43. firstBlock, lastBlock := a.getFirstLastBlock(slotNum)
  44. openAuction := a.isOpenAuction(currentBlockNum, slotNum, *auctionVars)
  45. slot := SlotAPI{
  46. ItemID: uint64(slotNum),
  47. SlotNum: slotNum,
  48. FirstBlock: firstBlock,
  49. LastBlock: lastBlock,
  50. OpenAuction: openAuction,
  51. WinnerBid: bid,
  52. }
  53. return slot
  54. }
  55. func (a *API) newSlotsAPIFromWinnerBids(fromItem *uint, order string, bids []historydb.BidAPI, currentBlockNum int64, auctionVars *common.AuctionVariables) (slots []SlotAPI) {
  56. for i := range bids {
  57. slotNum := bids[i].SlotNum
  58. slot := a.newSlotAPI(slotNum, currentBlockNum, &bids[i], auctionVars)
  59. if order == historydb.OrderAsc {
  60. if slot.ItemID >= uint64(*fromItem) {
  61. slots = append(slots, slot)
  62. }
  63. } else {
  64. if slot.ItemID <= uint64(*fromItem) {
  65. slots = append(slots, slot)
  66. }
  67. }
  68. }
  69. return slots
  70. }
  71. func (a *API) addEmptySlot(slots []SlotAPI, slotNum int64, currentBlockNum int64, auctionVars *common.AuctionVariables, fromItem *uint, order string) ([]SlotAPI, error) {
  72. emptySlot := a.newSlotAPI(slotNum, currentBlockNum, nil, auctionVars)
  73. if order == historydb.OrderAsc {
  74. if emptySlot.ItemID >= uint64(*fromItem) {
  75. slots = append(slots, emptySlot)
  76. }
  77. } else {
  78. if emptySlot.ItemID <= uint64(*fromItem) {
  79. slots = append([]SlotAPI{emptySlot}, slots...)
  80. }
  81. }
  82. return slots, nil
  83. }
  84. func (a *API) getSlot(c *gin.Context) {
  85. slotNumUint, err := parseParamUint("slotNum", nil, 0, maxUint32, c)
  86. if err != nil {
  87. retBadReq(err, c)
  88. return
  89. }
  90. currentBlock, err := a.h.GetLastBlock()
  91. if err != nil {
  92. retBadReq(err, c)
  93. return
  94. }
  95. auctionVars, err := a.h.GetAuctionVars()
  96. if err != nil {
  97. retBadReq(err, c)
  98. return
  99. }
  100. slotNum := int64(*slotNumUint)
  101. bid, err := a.h.GetBestBidAPI(&slotNum)
  102. if err != nil && tracerr.Unwrap(err) != sql.ErrNoRows {
  103. retSQLErr(err, c)
  104. return
  105. }
  106. var slot SlotAPI
  107. if tracerr.Unwrap(err) == sql.ErrNoRows {
  108. slot = a.newSlotAPI(slotNum, currentBlock.Num, nil, auctionVars)
  109. } else {
  110. slot = a.newSlotAPI(bid.SlotNum, currentBlock.Num, &bid, auctionVars)
  111. }
  112. // JSON response
  113. c.JSON(http.StatusOK, slot)
  114. }
  115. func getLimits(
  116. minSlotNum, maxSlotNum int64, fromItem, limit *uint, order string,
  117. ) (minLimit, maxLimit int64, pendingItems uint64) {
  118. if order == historydb.OrderAsc {
  119. if fromItem != nil && int64(*fromItem) > minSlotNum {
  120. minLimit = int64(*fromItem)
  121. } else {
  122. minLimit = minSlotNum
  123. }
  124. if limit != nil && (minLimit+int64(*limit-1)) < maxSlotNum {
  125. maxLimit = minLimit + int64(*limit-1)
  126. } else {
  127. maxLimit = maxSlotNum
  128. }
  129. pendingItems = uint64(maxSlotNum - maxLimit)
  130. } else {
  131. if fromItem != nil && int64(*fromItem) < maxSlotNum {
  132. maxLimit = int64(*fromItem)
  133. } else {
  134. maxLimit = maxSlotNum
  135. }
  136. if limit != nil && (maxLimit-int64(*limit-1)) < minSlotNum {
  137. minLimit = minSlotNum
  138. } else {
  139. minLimit = maxLimit - int64(*limit-1)
  140. }
  141. pendingItems = uint64(-(minSlotNum - minLimit))
  142. }
  143. return minLimit, maxLimit, pendingItems
  144. }
  145. func getLimitsWithAddr(minSlotNum, maxSlotNum *int64, fromItem, limit *uint, order string) (int64, int64) {
  146. var minLim, maxLim int64
  147. if fromItem != nil {
  148. if order == historydb.OrderAsc {
  149. maxLim = *maxSlotNum
  150. if int64(*fromItem) > *minSlotNum {
  151. minLim = int64(*fromItem)
  152. } else {
  153. minLim = *minSlotNum
  154. }
  155. } else {
  156. minLim = *minSlotNum
  157. if int64(*fromItem) < *maxSlotNum {
  158. maxLim = int64(*fromItem)
  159. } else {
  160. maxLim = *maxSlotNum
  161. }
  162. }
  163. }
  164. return minLim, maxLim
  165. }
  166. func (a *API) getSlots(c *gin.Context) {
  167. var slots []SlotAPI
  168. minSlotNumDflt := int64(0)
  169. // Get filters
  170. minSlotNum, maxSlotNum, wonByEthereumAddress, finishedAuction, err := parseSlotFilters(c)
  171. if err != nil {
  172. retBadReq(err, c)
  173. return
  174. }
  175. // Pagination
  176. fromItem, order, limit, err := parsePagination(c)
  177. if err != nil {
  178. retBadReq(err, c)
  179. return
  180. }
  181. currentBlock, err := a.h.GetLastBlock()
  182. if err != nil {
  183. retBadReq(err, c)
  184. return
  185. }
  186. auctionVars, err := a.h.GetAuctionVars()
  187. if err != nil {
  188. retBadReq(err, c)
  189. return
  190. }
  191. // Check filters
  192. if maxSlotNum == nil && finishedAuction == nil {
  193. retBadReq(errors.New("It is necessary to add maxSlotNum filter"), c)
  194. return
  195. } else if finishedAuction != nil {
  196. if maxSlotNum == nil && !*finishedAuction {
  197. retBadReq(errors.New("It is necessary to add maxSlotNum filter"), c)
  198. return
  199. } else if *finishedAuction {
  200. currentBlock, err := a.h.GetLastBlock()
  201. if err != nil {
  202. retBadReq(err, c)
  203. return
  204. }
  205. currentSlot := a.getCurrentSlot(currentBlock.Num)
  206. auctionVars, err := a.h.GetAuctionVars()
  207. if err != nil {
  208. retBadReq(err, c)
  209. return
  210. }
  211. closedAuctionSlots := currentSlot + int64(auctionVars.ClosedAuctionSlots)
  212. if maxSlotNum == nil {
  213. maxSlotNum = &closedAuctionSlots
  214. } else if closedAuctionSlots < *maxSlotNum {
  215. maxSlotNum = &closedAuctionSlots
  216. }
  217. }
  218. } else if maxSlotNum != nil && minSlotNum != nil {
  219. if *minSlotNum > *maxSlotNum {
  220. retBadReq(errors.New("It is necessary to add valid filter (minSlotNum <= maxSlotNum)"), c)
  221. return
  222. }
  223. }
  224. if minSlotNum == nil {
  225. minSlotNum = &minSlotNumDflt
  226. }
  227. // Get bids and pagination according to filters
  228. var slotMinLim, slotMaxLim int64
  229. var bids []historydb.BidAPI
  230. var pendingItems uint64
  231. if wonByEthereumAddress == nil {
  232. slotMinLim, slotMaxLim, pendingItems = getLimits(*minSlotNum, *maxSlotNum, fromItem, limit, order)
  233. // Get best bids in range maxSlotNum - minSlotNum
  234. bids, _, err = a.h.GetBestBidsAPI(&slotMinLim, &slotMaxLim, wonByEthereumAddress, nil, order)
  235. if err != nil && tracerr.Unwrap(err) != sql.ErrNoRows {
  236. retSQLErr(err, c)
  237. return
  238. }
  239. } else {
  240. slotMinLim, slotMaxLim = getLimitsWithAddr(minSlotNum, maxSlotNum, fromItem, limit, order)
  241. bids, pendingItems, err = a.h.GetBestBidsAPI(&slotMinLim, &slotMaxLim, wonByEthereumAddress, limit, order)
  242. if err != nil && tracerr.Unwrap(err) != sql.ErrNoRows {
  243. retSQLErr(err, c)
  244. return
  245. }
  246. }
  247. // Build the slot information with previous bids
  248. var slotsBids []SlotAPI
  249. if len(bids) > 0 {
  250. slotsBids = a.newSlotsAPIFromWinnerBids(fromItem, order, bids, currentBlock.Num, auctionVars)
  251. if err != nil {
  252. retBadReq(err, c)
  253. return
  254. }
  255. }
  256. // Build the other slots
  257. if wonByEthereumAddress == nil {
  258. // Build hte information of the slots with bids or not
  259. for i := slotMinLim; i <= slotMaxLim; i++ {
  260. found := false
  261. for j := range slotsBids {
  262. if slotsBids[j].SlotNum == i {
  263. found = true
  264. if order == historydb.OrderAsc {
  265. if slotsBids[j].ItemID >= uint64(*fromItem) {
  266. slots = append(slots, slotsBids[j])
  267. }
  268. } else {
  269. if slotsBids[j].ItemID <= uint64(*fromItem) {
  270. slots = append([]SlotAPI{slotsBids[j]}, slots...)
  271. }
  272. }
  273. break
  274. }
  275. }
  276. if !found {
  277. slots, err = a.addEmptySlot(slots, i, currentBlock.Num, auctionVars, fromItem, order)
  278. if err != nil {
  279. retBadReq(err, c)
  280. return
  281. }
  282. }
  283. }
  284. } else if len(slotsBids) > 0 {
  285. slots = slotsBids
  286. }
  287. if len(slots) == 0 {
  288. retSQLErr(sql.ErrNoRows, c)
  289. return
  290. }
  291. // Build succesfull response
  292. type slotsResponse struct {
  293. Slots []SlotAPI `json:"slots"`
  294. PendingItems uint64 `json:"pendingItems"`
  295. }
  296. c.JSON(http.StatusOK, &slotsResponse{
  297. Slots: slots,
  298. PendingItems: pendingItems,
  299. })
  300. }