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.

484 lines
12 KiB

Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
Allow serving API only via new cli command - Add new command to the cli/node: `serveapi` that alows serving the API just by connecting to the PostgreSQL database. The mode flag should me passed in order to select whether we are connecting to a synchronizer database or a coordinator database. If `coord` is chosen as mode, the coordinator endpoints can be activated in order to allow inserting l2txs and authorizations into the L2DB. Summary of the implementation details - New SQL table with 3 columns (plus `item_id` pk). The table only contains a single row with `item_id` = 1. Columns: - state: historydb.StateAPI in JSON. This is the struct that is served via the `/state` API endpoint. The node will periodically update this struct and store it int he DB. The api server will query it from the DB to serve it. - config: historydb.NodeConfig in JSON. This struct contains node configuration parameters that the API needs to be aware of. It's updated once every time the node starts. - constants: historydb.Constants in JSON. This struct contains all the hermez network constants gathered via the ethereum client by the node. It's written once every time the node starts. - The HistoryDB contains methods to get and update each one of these columns individually. - The HistoryDB contains all methods that query the DB and prepare objects that will appear in the StateAPI endpoint. - The configuration used in for the `serveapi` cli/node command is defined in `config.APIServer`, and is a subset of `node.Config` in order to allow reusing the same configuration file of the node if desired. - A new object is introduced in the api: `StateAPIUpdater`, which contains all the necessary information to update the StateAPI in the DB periodically by the node. - Moved the types `SCConsts`, `SCVariables` and `SCVariablesPtr` from `syncrhonizer` to `common` for convenience.
3 years ago
  1. package main
  2. import (
  3. "encoding/hex"
  4. "fmt"
  5. "os"
  6. "os/signal"
  7. "path"
  8. "strings"
  9. ethKeystore "github.com/ethereum/go-ethereum/accounts/keystore"
  10. "github.com/ethereum/go-ethereum/crypto"
  11. "github.com/hermeznetwork/hermez-node/common"
  12. "github.com/hermeznetwork/hermez-node/config"
  13. dbUtils "github.com/hermeznetwork/hermez-node/db"
  14. "github.com/hermeznetwork/hermez-node/db/historydb"
  15. "github.com/hermeznetwork/hermez-node/db/kvdb"
  16. "github.com/hermeznetwork/hermez-node/db/l2db"
  17. "github.com/hermeznetwork/hermez-node/log"
  18. "github.com/hermeznetwork/hermez-node/node"
  19. "github.com/hermeznetwork/tracerr"
  20. "github.com/iden3/go-iden3-crypto/babyjub"
  21. "github.com/jmoiron/sqlx"
  22. "github.com/urfave/cli/v2"
  23. )
  24. const (
  25. flagCfg = "cfg"
  26. flagMode = "mode"
  27. flagSK = "privatekey"
  28. flagYes = "yes"
  29. flagBlock = "block"
  30. modeSync = "sync"
  31. modeCoord = "coord"
  32. )
  33. func cmdGenBJJ(c *cli.Context) error {
  34. sk := babyjub.NewRandPrivKey()
  35. skBuf := [32]byte(sk)
  36. pk := sk.Public()
  37. fmt.Printf("BJJ = \"0x%s\"\n", pk.String())
  38. fmt.Printf("BJJPrivateKey = \"0x%s\"\n", hex.EncodeToString(skBuf[:]))
  39. return nil
  40. }
  41. func cmdImportKey(c *cli.Context) error {
  42. _cfg, err := parseCli(c)
  43. if err != nil {
  44. return tracerr.Wrap(fmt.Errorf("error parsing flags and config: %w", err))
  45. }
  46. if _cfg.mode != node.ModeCoordinator {
  47. return tracerr.Wrap(fmt.Errorf("importkey must use mode coordinator"))
  48. }
  49. cfg := _cfg.node
  50. scryptN := ethKeystore.StandardScryptN
  51. scryptP := ethKeystore.StandardScryptP
  52. if cfg.Coordinator.Debug.LightScrypt {
  53. scryptN = ethKeystore.LightScryptN
  54. scryptP = ethKeystore.LightScryptP
  55. }
  56. keyStore := ethKeystore.NewKeyStore(cfg.Coordinator.EthClient.Keystore.Path,
  57. scryptN, scryptP)
  58. hexKey := c.String(flagSK)
  59. hexKey = strings.TrimPrefix(hexKey, "0x")
  60. sk, err := crypto.HexToECDSA(hexKey)
  61. if err != nil {
  62. return tracerr.Wrap(err)
  63. }
  64. acc, err := keyStore.ImportECDSA(sk, cfg.Coordinator.EthClient.Keystore.Password)
  65. if err != nil {
  66. return tracerr.Wrap(err)
  67. }
  68. log.Infow("Imported private key", "addr", acc.Address.Hex())
  69. return nil
  70. }
  71. func resetStateDBs(cfg *Config, batchNum common.BatchNum) error {
  72. log.Infof("Reset Synchronizer StateDB to batchNum %v...", batchNum)
  73. // Manually make a checkpoint from batchNum to current to force current
  74. // to be a valid checkpoint. This is useful because in case of a
  75. // crash, current can be corrupted and the first thing that
  76. // `kvdb.NewKVDB` does is read the current checkpoint, which wouldn't
  77. // succeed in case of corruption.
  78. dbPath := cfg.node.StateDB.Path
  79. source := path.Join(dbPath, fmt.Sprintf("%s%d", kvdb.PathBatchNum, batchNum))
  80. current := path.Join(dbPath, kvdb.PathCurrent)
  81. last := path.Join(dbPath, kvdb.PathLast)
  82. if err := os.RemoveAll(last); err != nil {
  83. return tracerr.Wrap(fmt.Errorf("os.RemoveAll: %w", err))
  84. }
  85. if batchNum == 0 {
  86. if err := os.RemoveAll(current); err != nil {
  87. return tracerr.Wrap(fmt.Errorf("os.RemoveAll: %w", err))
  88. }
  89. } else {
  90. if err := kvdb.PebbleMakeCheckpoint(source, current); err != nil {
  91. return tracerr.Wrap(fmt.Errorf("kvdb.PebbleMakeCheckpoint: %w", err))
  92. }
  93. }
  94. db, err := kvdb.NewKVDB(kvdb.Config{
  95. Path: dbPath,
  96. NoGapsCheck: true,
  97. NoLast: true,
  98. })
  99. if err != nil {
  100. return tracerr.Wrap(fmt.Errorf("kvdb.NewKVDB: %w", err))
  101. }
  102. if err := db.Reset(batchNum); err != nil {
  103. return tracerr.Wrap(fmt.Errorf("db.Reset: %w", err))
  104. }
  105. if cfg.mode == node.ModeCoordinator {
  106. log.Infof("Wipe Coordinator StateDBs...")
  107. // We wipe the Coordinator StateDBs entirely (by deleting
  108. // current and resetting to batchNum 0) because the Coordinator
  109. // StateDBs are always reset from Synchronizer when the
  110. // coordinator pipeline starts.
  111. dbPath := cfg.node.Coordinator.TxSelector.Path
  112. current := path.Join(dbPath, kvdb.PathCurrent)
  113. if err := os.RemoveAll(current); err != nil {
  114. return tracerr.Wrap(fmt.Errorf("os.RemoveAll: %w", err))
  115. }
  116. db, err := kvdb.NewKVDB(kvdb.Config{
  117. Path: dbPath,
  118. NoGapsCheck: true,
  119. NoLast: true,
  120. })
  121. if err != nil {
  122. return tracerr.Wrap(fmt.Errorf("kvdb.NewKVDB: %w", err))
  123. }
  124. if err := db.Reset(0); err != nil {
  125. return tracerr.Wrap(fmt.Errorf("db.Reset: %w", err))
  126. }
  127. dbPath = cfg.node.Coordinator.BatchBuilder.Path
  128. current = path.Join(dbPath, kvdb.PathCurrent)
  129. if err := os.RemoveAll(current); err != nil {
  130. return tracerr.Wrap(fmt.Errorf("os.RemoveAll: %w", err))
  131. }
  132. db, err = kvdb.NewKVDB(kvdb.Config{
  133. Path: dbPath,
  134. NoGapsCheck: true,
  135. NoLast: true,
  136. })
  137. if err != nil {
  138. return tracerr.Wrap(fmt.Errorf("statedb.NewKVDB: %w", err))
  139. }
  140. if err := db.Reset(0); err != nil {
  141. return tracerr.Wrap(fmt.Errorf("db.Reset: %w", err))
  142. }
  143. }
  144. return nil
  145. }
  146. func cmdWipeSQL(c *cli.Context) error {
  147. _cfg, err := parseCli(c)
  148. if err != nil {
  149. return tracerr.Wrap(fmt.Errorf("error parsing flags and config: %w", err))
  150. }
  151. cfg := _cfg.node
  152. yes := c.Bool(flagYes)
  153. if !yes {
  154. fmt.Print("*WARNING* Are you sure you want to delete " +
  155. "the SQL DB and StateDBs? [y/N]: ")
  156. var input string
  157. if _, err := fmt.Scanln(&input); err != nil {
  158. return tracerr.Wrap(err)
  159. }
  160. input = strings.ToLower(input)
  161. if !(input == "y" || input == "yes") {
  162. return nil
  163. }
  164. }
  165. db, err := dbUtils.ConnectSQLDB(
  166. cfg.PostgreSQL.PortWrite,
  167. cfg.PostgreSQL.HostWrite,
  168. cfg.PostgreSQL.UserWrite,
  169. cfg.PostgreSQL.PasswordWrite,
  170. cfg.PostgreSQL.NameWrite,
  171. )
  172. if err != nil {
  173. return tracerr.Wrap(err)
  174. }
  175. log.Info("Wiping SQL DB...")
  176. if err := dbUtils.MigrationsDown(db.DB); err != nil {
  177. return tracerr.Wrap(fmt.Errorf("dbUtils.MigrationsDown: %w", err))
  178. }
  179. log.Info("Wiping StateDBs...")
  180. if err := resetStateDBs(_cfg, 0); err != nil {
  181. return tracerr.Wrap(fmt.Errorf("resetStateDBs: %w", err))
  182. }
  183. return nil
  184. }
  185. func waitSigInt() {
  186. stopCh := make(chan interface{})
  187. // catch ^C to send the stop signal
  188. ossig := make(chan os.Signal, 1)
  189. signal.Notify(ossig, os.Interrupt)
  190. const forceStopCount = 3
  191. go func() {
  192. n := 0
  193. for sig := range ossig {
  194. if sig == os.Interrupt {
  195. log.Info("Received Interrupt Signal")
  196. stopCh <- nil
  197. n++
  198. if n == forceStopCount {
  199. log.Fatalf("Received %v Interrupt Signals", forceStopCount)
  200. }
  201. }
  202. }
  203. }()
  204. <-stopCh
  205. }
  206. func cmdRun(c *cli.Context) error {
  207. cfg, err := parseCli(c)
  208. if err != nil {
  209. return tracerr.Wrap(fmt.Errorf("error parsing flags and config: %w", err))
  210. }
  211. node, err := node.NewNode(cfg.mode, cfg.node)
  212. if err != nil {
  213. return tracerr.Wrap(fmt.Errorf("error starting node: %w", err))
  214. }
  215. node.Start()
  216. waitSigInt()
  217. node.Stop()
  218. return nil
  219. }
  220. func cmdServeAPI(c *cli.Context) error {
  221. cfg, err := parseCliAPIServer(c)
  222. if err != nil {
  223. return tracerr.Wrap(fmt.Errorf("error parsing flags and config: %w", err))
  224. }
  225. srv, err := node.NewAPIServer(cfg.mode, cfg.server)
  226. if err != nil {
  227. return tracerr.Wrap(fmt.Errorf("error starting api server: %w", err))
  228. }
  229. srv.Start()
  230. waitSigInt()
  231. srv.Stop()
  232. return nil
  233. }
  234. func cmdDiscard(c *cli.Context) error {
  235. _cfg, err := parseCli(c)
  236. if err != nil {
  237. return tracerr.Wrap(fmt.Errorf("error parsing flags and config: %w", err))
  238. }
  239. cfg := _cfg.node
  240. blockNum := c.Int64(flagBlock)
  241. log.Infof("Discarding all blocks up to block %v...", blockNum)
  242. dbWrite, err := dbUtils.InitSQLDB(
  243. cfg.PostgreSQL.PortWrite,
  244. cfg.PostgreSQL.HostWrite,
  245. cfg.PostgreSQL.UserWrite,
  246. cfg.PostgreSQL.PasswordWrite,
  247. cfg.PostgreSQL.NameWrite,
  248. )
  249. if err != nil {
  250. return tracerr.Wrap(fmt.Errorf("dbUtils.InitSQLDB: %w", err))
  251. }
  252. var dbRead *sqlx.DB
  253. if cfg.PostgreSQL.HostRead == "" {
  254. dbRead = dbWrite
  255. } else if cfg.PostgreSQL.HostRead == cfg.PostgreSQL.HostWrite {
  256. return tracerr.Wrap(fmt.Errorf(
  257. "PostgreSQL.HostRead and PostgreSQL.HostWrite must be different",
  258. ))
  259. } else {
  260. dbRead, err = dbUtils.InitSQLDB(
  261. cfg.PostgreSQL.PortRead,
  262. cfg.PostgreSQL.HostRead,
  263. cfg.PostgreSQL.UserRead,
  264. cfg.PostgreSQL.PasswordRead,
  265. cfg.PostgreSQL.NameRead,
  266. )
  267. if err != nil {
  268. return tracerr.Wrap(fmt.Errorf("dbUtils.InitSQLDB: %w", err))
  269. }
  270. }
  271. historyDB := historydb.NewHistoryDB(dbRead, dbWrite, nil)
  272. if err := historyDB.Reorg(blockNum); err != nil {
  273. return tracerr.Wrap(fmt.Errorf("historyDB.Reorg: %w", err))
  274. }
  275. batchNum, err := historyDB.GetLastBatchNum()
  276. if err != nil {
  277. return tracerr.Wrap(fmt.Errorf("historyDB.GetLastBatchNum: %w", err))
  278. }
  279. l2DB := l2db.NewL2DB(
  280. dbRead, dbWrite,
  281. cfg.Coordinator.L2DB.SafetyPeriod,
  282. cfg.Coordinator.L2DB.MaxTxs,
  283. cfg.Coordinator.L2DB.MinFeeUSD,
  284. cfg.Coordinator.L2DB.TTL.Duration,
  285. nil,
  286. )
  287. if err := l2DB.Reorg(batchNum); err != nil {
  288. return tracerr.Wrap(fmt.Errorf("l2DB.Reorg: %w", err))
  289. }
  290. log.Info("Resetting StateDBs...")
  291. if err := resetStateDBs(_cfg, batchNum); err != nil {
  292. return tracerr.Wrap(fmt.Errorf("resetStateDBs: %w", err))
  293. }
  294. return nil
  295. }
  296. // Config is the configuration of the hermez node execution
  297. type Config struct {
  298. mode node.Mode
  299. node *config.Node
  300. }
  301. func parseCli(c *cli.Context) (*Config, error) {
  302. cfg, err := getConfig(c)
  303. if err != nil {
  304. if err := cli.ShowAppHelp(c); err != nil {
  305. panic(err)
  306. }
  307. return nil, tracerr.Wrap(err)
  308. }
  309. return cfg, nil
  310. }
  311. func getConfig(c *cli.Context) (*Config, error) {
  312. var cfg Config
  313. mode := c.String(flagMode)
  314. nodeCfgPath := c.String(flagCfg)
  315. var err error
  316. switch mode {
  317. case modeSync:
  318. cfg.mode = node.ModeSynchronizer
  319. cfg.node, err = config.LoadNode(nodeCfgPath, false)
  320. if err != nil {
  321. return nil, tracerr.Wrap(err)
  322. }
  323. case modeCoord:
  324. cfg.mode = node.ModeCoordinator
  325. cfg.node, err = config.LoadNode(nodeCfgPath, true)
  326. if err != nil {
  327. return nil, tracerr.Wrap(err)
  328. }
  329. default:
  330. return nil, tracerr.Wrap(fmt.Errorf("invalid mode \"%v\"", mode))
  331. }
  332. return &cfg, nil
  333. }
  334. // ConfigAPIServer is the configuration of the api server execution
  335. type ConfigAPIServer struct {
  336. mode node.Mode
  337. server *config.APIServer
  338. }
  339. func parseCliAPIServer(c *cli.Context) (*ConfigAPIServer, error) {
  340. cfg, err := getConfigAPIServer(c)
  341. if err != nil {
  342. if err := cli.ShowAppHelp(c); err != nil {
  343. panic(err)
  344. }
  345. return nil, tracerr.Wrap(err)
  346. }
  347. return cfg, nil
  348. }
  349. func getConfigAPIServer(c *cli.Context) (*ConfigAPIServer, error) {
  350. var cfg ConfigAPIServer
  351. mode := c.String(flagMode)
  352. nodeCfgPath := c.String(flagCfg)
  353. var err error
  354. switch mode {
  355. case modeSync:
  356. cfg.mode = node.ModeSynchronizer
  357. cfg.server, err = config.LoadAPIServer(nodeCfgPath, false)
  358. if err != nil {
  359. return nil, tracerr.Wrap(err)
  360. }
  361. case modeCoord:
  362. cfg.mode = node.ModeCoordinator
  363. cfg.server, err = config.LoadAPIServer(nodeCfgPath, true)
  364. if err != nil {
  365. return nil, tracerr.Wrap(err)
  366. }
  367. default:
  368. return nil, tracerr.Wrap(fmt.Errorf("invalid mode \"%v\"", mode))
  369. }
  370. return &cfg, nil
  371. }
  372. func main() {
  373. app := cli.NewApp()
  374. app.Name = "hermez-node"
  375. app.Version = "0.1.0-alpha"
  376. app.Flags = []cli.Flag{
  377. &cli.StringFlag{
  378. Name: flagMode,
  379. Usage: fmt.Sprintf("Set node `MODE` (can be \"%v\" or \"%v\")", modeSync, modeCoord),
  380. Required: true,
  381. },
  382. &cli.StringFlag{
  383. Name: flagCfg,
  384. Usage: "Node configuration `FILE`",
  385. Required: true,
  386. },
  387. }
  388. app.Commands = []*cli.Command{
  389. {
  390. Name: "importkey",
  391. Aliases: []string{},
  392. Usage: "Import ethereum private key",
  393. Action: cmdImportKey,
  394. Flags: []cli.Flag{
  395. &cli.StringFlag{
  396. Name: flagSK,
  397. Usage: "ethereum `PRIVATE_KEY` in hex",
  398. Required: true,
  399. }},
  400. },
  401. {
  402. Name: "genbjj",
  403. Aliases: []string{},
  404. Usage: "Generate a new BabyJubJub key",
  405. Action: cmdGenBJJ,
  406. },
  407. {
  408. Name: "wipesql",
  409. Aliases: []string{},
  410. Usage: "Wipe the SQL DB (HistoryDB and L2DB) and the StateDBs, " +
  411. "leaving the DB in a clean state",
  412. Action: cmdWipeSQL,
  413. Flags: []cli.Flag{
  414. &cli.BoolFlag{
  415. Name: flagYes,
  416. Usage: "automatic yes to the prompt",
  417. Required: false,
  418. }},
  419. },
  420. {
  421. Name: "run",
  422. Aliases: []string{},
  423. Usage: "Run the hermez-node in the indicated mode",
  424. Action: cmdRun,
  425. },
  426. {
  427. Name: "serveapi",
  428. Aliases: []string{},
  429. Usage: "Serve the API only",
  430. Action: cmdServeAPI,
  431. },
  432. {
  433. Name: "discard",
  434. Aliases: []string{},
  435. Usage: "Discard blocks up to a specified block number",
  436. Action: cmdDiscard,
  437. Flags: []cli.Flag{
  438. &cli.Int64Flag{
  439. Name: flagBlock,
  440. Usage: "last block number to keep",
  441. Required: false,
  442. }},
  443. },
  444. }
  445. err := app.Run(os.Args)
  446. if err != nil {
  447. fmt.Printf("\nError: %v\n", tracerr.Sprint(err))
  448. os.Exit(1)
  449. }
  450. }