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.

124 lines
2.9 KiB

  1. package debugapi
  2. import (
  3. "context"
  4. "net/http"
  5. "time"
  6. "github.com/gin-contrib/cors"
  7. "github.com/gin-gonic/gin"
  8. "github.com/hermeznetwork/hermez-node/common"
  9. "github.com/hermeznetwork/hermez-node/db/statedb"
  10. "github.com/hermeznetwork/hermez-node/log"
  11. )
  12. func handleNoRoute(c *gin.Context) {
  13. c.JSON(http.StatusNotFound, gin.H{
  14. "error": "404 page not found",
  15. })
  16. }
  17. type errorMsg struct {
  18. Message string
  19. }
  20. func badReq(err error, c *gin.Context) {
  21. log.Errorw("Bad request", "err", err)
  22. c.JSON(http.StatusBadRequest, errorMsg{
  23. Message: err.Error(),
  24. })
  25. }
  26. // DebugAPI is an http API with debugging endpoints
  27. type DebugAPI struct {
  28. addr string
  29. stateDB *statedb.StateDB // synchronizer statedb
  30. }
  31. // NewDebugAPI creates a new DebugAPI
  32. func NewDebugAPI(addr string, stateDB *statedb.StateDB) *DebugAPI {
  33. return &DebugAPI{
  34. stateDB: stateDB,
  35. addr: addr,
  36. }
  37. }
  38. func (a *DebugAPI) handleAccount(c *gin.Context) {
  39. uri := struct {
  40. Idx uint32
  41. }{}
  42. if err := c.ShouldBindUri(&uri); err != nil {
  43. badReq(err, c)
  44. return
  45. }
  46. account, err := a.stateDB.GetAccount(common.Idx(uri.Idx))
  47. if err != nil {
  48. badReq(err, c)
  49. return
  50. }
  51. c.JSON(http.StatusOK, account)
  52. }
  53. func (a *DebugAPI) handleAccounts(c *gin.Context) {
  54. accounts, err := a.stateDB.GetAccounts()
  55. if err != nil {
  56. badReq(err, c)
  57. return
  58. }
  59. c.JSON(http.StatusOK, accounts)
  60. }
  61. func (a *DebugAPI) handleCurrentBatch(c *gin.Context) {
  62. batchNum, err := a.stateDB.GetCurrentBatch()
  63. if err != nil {
  64. badReq(err, c)
  65. return
  66. }
  67. c.JSON(http.StatusOK, batchNum)
  68. }
  69. func (a *DebugAPI) handleMTRoot(c *gin.Context) {
  70. root := a.stateDB.MTGetRoot()
  71. c.JSON(http.StatusOK, root)
  72. }
  73. // Run starts the http server of the DebugAPI. To stop it, pass a context with
  74. // cancelation (see `debugapi_test.go` for an example).
  75. func (a *DebugAPI) Run(ctx context.Context) error {
  76. api := gin.Default()
  77. api.NoRoute(handleNoRoute)
  78. api.Use(cors.Default())
  79. debugAPI := api.Group("/debug")
  80. debugAPI.GET("sdb/batchnum", a.handleCurrentBatch)
  81. debugAPI.GET("sdb/mtroot", a.handleMTRoot)
  82. // Accounts returned by these endpoints will always have BatchNum = 0,
  83. // because the stateDB doesn't store the BatchNum in which an account
  84. // is created.
  85. debugAPI.GET("sdb/accounts", a.handleAccounts)
  86. debugAPI.GET("sdb/accounts/:Idx", a.handleAccount)
  87. debugAPIServer := &http.Server{
  88. Addr: a.addr,
  89. Handler: api,
  90. // Use some hardcoded numberes that are suitable for testing
  91. ReadTimeout: 30 * time.Second, //nolint:gomnd
  92. WriteTimeout: 30 * time.Second, //nolint:gomnd
  93. MaxHeaderBytes: 1 << 20, //nolint:gomnd
  94. }
  95. go func() {
  96. log.Infof("DebugAPI is ready at %v", a.addr)
  97. if err := debugAPIServer.ListenAndServe(); err != nil &&
  98. err != http.ErrServerClosed {
  99. log.Fatalf("Listen: %s\n", err)
  100. }
  101. }()
  102. <-ctx.Done()
  103. log.Info("Stopping DebugAPI...")
  104. if err := debugAPIServer.Shutdown(context.Background()); err != nil {
  105. return err
  106. }
  107. log.Info("DebugAPI done")
  108. return nil
  109. }