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.

507 lines
13 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. var (
  34. // Version represents the program based on the git tag
  35. Version = "v0.1.0"
  36. // Build represents the program based on the git commit
  37. Build = "dev"
  38. // Date represents the date of application was built
  39. Date = ""
  40. )
  41. func cmdVersion(c *cli.Context) error {
  42. fmt.Printf("Version = \"%v\"\n", Version)
  43. fmt.Printf("Build = \"%v\"\n", Build)
  44. fmt.Printf("Date = \"%v\"\n", Date)
  45. return nil
  46. }
  47. func cmdGenBJJ(c *cli.Context) error {
  48. sk := babyjub.NewRandPrivKey()
  49. skBuf := [32]byte(sk)
  50. pk := sk.Public()
  51. fmt.Printf("BJJ = \"0x%s\"\n", pk.String())
  52. fmt.Printf("BJJPrivateKey = \"0x%s\"\n", hex.EncodeToString(skBuf[:]))
  53. return nil
  54. }
  55. func cmdImportKey(c *cli.Context) error {
  56. _cfg, err := parseCli(c)
  57. if err != nil {
  58. return tracerr.Wrap(fmt.Errorf("error parsing flags and config: %w", err))
  59. }
  60. if _cfg.mode != node.ModeCoordinator {
  61. return tracerr.Wrap(fmt.Errorf("importkey must use mode coordinator"))
  62. }
  63. cfg := _cfg.node
  64. scryptN := ethKeystore.StandardScryptN
  65. scryptP := ethKeystore.StandardScryptP
  66. if cfg.Coordinator.Debug.LightScrypt {
  67. scryptN = ethKeystore.LightScryptN
  68. scryptP = ethKeystore.LightScryptP
  69. }
  70. keyStore := ethKeystore.NewKeyStore(cfg.Coordinator.EthClient.Keystore.Path,
  71. scryptN, scryptP)
  72. hexKey := c.String(flagSK)
  73. hexKey = strings.TrimPrefix(hexKey, "0x")
  74. sk, err := crypto.HexToECDSA(hexKey)
  75. if err != nil {
  76. return tracerr.Wrap(err)
  77. }
  78. acc, err := keyStore.ImportECDSA(sk, cfg.Coordinator.EthClient.Keystore.Password)
  79. if err != nil {
  80. return tracerr.Wrap(err)
  81. }
  82. log.Infow("Imported private key", "addr", acc.Address.Hex())
  83. return nil
  84. }
  85. func resetStateDBs(cfg *Config, batchNum common.BatchNum) error {
  86. log.Infof("Reset Synchronizer StateDB to batchNum %v...", batchNum)
  87. // Manually make a checkpoint from batchNum to current to force current
  88. // to be a valid checkpoint. This is useful because in case of a
  89. // crash, current can be corrupted and the first thing that
  90. // `kvdb.NewKVDB` does is read the current checkpoint, which wouldn't
  91. // succeed in case of corruption.
  92. dbPath := cfg.node.StateDB.Path
  93. source := path.Join(dbPath, fmt.Sprintf("%s%d", kvdb.PathBatchNum, batchNum))
  94. current := path.Join(dbPath, kvdb.PathCurrent)
  95. last := path.Join(dbPath, kvdb.PathLast)
  96. if err := os.RemoveAll(last); err != nil {
  97. return tracerr.Wrap(fmt.Errorf("os.RemoveAll: %w", err))
  98. }
  99. if batchNum == 0 {
  100. if err := os.RemoveAll(current); err != nil {
  101. return tracerr.Wrap(fmt.Errorf("os.RemoveAll: %w", err))
  102. }
  103. } else {
  104. if err := kvdb.PebbleMakeCheckpoint(source, current); err != nil {
  105. return tracerr.Wrap(fmt.Errorf("kvdb.PebbleMakeCheckpoint: %w", err))
  106. }
  107. }
  108. db, err := kvdb.NewKVDB(kvdb.Config{
  109. Path: dbPath,
  110. NoGapsCheck: true,
  111. NoLast: true,
  112. })
  113. if err != nil {
  114. return tracerr.Wrap(fmt.Errorf("kvdb.NewKVDB: %w", err))
  115. }
  116. if err := db.Reset(batchNum); err != nil {
  117. return tracerr.Wrap(fmt.Errorf("db.Reset: %w", err))
  118. }
  119. if cfg.mode == node.ModeCoordinator {
  120. log.Infof("Wipe Coordinator StateDBs...")
  121. // We wipe the Coordinator StateDBs entirely (by deleting
  122. // current and resetting to batchNum 0) because the Coordinator
  123. // StateDBs are always reset from Synchronizer when the
  124. // coordinator pipeline starts.
  125. dbPath := cfg.node.Coordinator.TxSelector.Path
  126. current := path.Join(dbPath, kvdb.PathCurrent)
  127. if err := os.RemoveAll(current); err != nil {
  128. return tracerr.Wrap(fmt.Errorf("os.RemoveAll: %w", err))
  129. }
  130. db, err := kvdb.NewKVDB(kvdb.Config{
  131. Path: dbPath,
  132. NoGapsCheck: true,
  133. NoLast: true,
  134. })
  135. if err != nil {
  136. return tracerr.Wrap(fmt.Errorf("kvdb.NewKVDB: %w", err))
  137. }
  138. if err := db.Reset(0); err != nil {
  139. return tracerr.Wrap(fmt.Errorf("db.Reset: %w", err))
  140. }
  141. dbPath = cfg.node.Coordinator.BatchBuilder.Path
  142. current = path.Join(dbPath, kvdb.PathCurrent)
  143. if err := os.RemoveAll(current); err != nil {
  144. return tracerr.Wrap(fmt.Errorf("os.RemoveAll: %w", err))
  145. }
  146. db, err = kvdb.NewKVDB(kvdb.Config{
  147. Path: dbPath,
  148. NoGapsCheck: true,
  149. NoLast: true,
  150. })
  151. if err != nil {
  152. return tracerr.Wrap(fmt.Errorf("statedb.NewKVDB: %w", err))
  153. }
  154. if err := db.Reset(0); err != nil {
  155. return tracerr.Wrap(fmt.Errorf("db.Reset: %w", err))
  156. }
  157. }
  158. return nil
  159. }
  160. func cmdWipeSQL(c *cli.Context) error {
  161. _cfg, err := parseCli(c)
  162. if err != nil {
  163. return tracerr.Wrap(fmt.Errorf("error parsing flags and config: %w", err))
  164. }
  165. cfg := _cfg.node
  166. yes := c.Bool(flagYes)
  167. if !yes {
  168. fmt.Print("*WARNING* Are you sure you want to delete " +
  169. "the SQL DB and StateDBs? [y/N]: ")
  170. var input string
  171. if _, err := fmt.Scanln(&input); err != nil {
  172. return tracerr.Wrap(err)
  173. }
  174. input = strings.ToLower(input)
  175. if !(input == "y" || input == "yes") {
  176. return nil
  177. }
  178. }
  179. db, err := dbUtils.ConnectSQLDB(
  180. cfg.PostgreSQL.PortWrite,
  181. cfg.PostgreSQL.HostWrite,
  182. cfg.PostgreSQL.UserWrite,
  183. cfg.PostgreSQL.PasswordWrite,
  184. cfg.PostgreSQL.NameWrite,
  185. )
  186. if err != nil {
  187. return tracerr.Wrap(err)
  188. }
  189. log.Info("Wiping SQL DB...")
  190. if err := dbUtils.MigrationsDown(db.DB); err != nil {
  191. return tracerr.Wrap(fmt.Errorf("dbUtils.MigrationsDown: %w", err))
  192. }
  193. log.Info("Wiping StateDBs...")
  194. if err := resetStateDBs(_cfg, 0); err != nil {
  195. return tracerr.Wrap(fmt.Errorf("resetStateDBs: %w", err))
  196. }
  197. return nil
  198. }
  199. func waitSigInt() {
  200. stopCh := make(chan interface{})
  201. // catch ^C to send the stop signal
  202. ossig := make(chan os.Signal, 1)
  203. signal.Notify(ossig, os.Interrupt)
  204. const forceStopCount = 3
  205. go func() {
  206. n := 0
  207. for sig := range ossig {
  208. if sig == os.Interrupt {
  209. log.Info("Received Interrupt Signal")
  210. stopCh <- nil
  211. n++
  212. if n == forceStopCount {
  213. log.Fatalf("Received %v Interrupt Signals", forceStopCount)
  214. }
  215. }
  216. }
  217. }()
  218. <-stopCh
  219. }
  220. func cmdRun(c *cli.Context) error {
  221. cfg, err := parseCli(c)
  222. if err != nil {
  223. return tracerr.Wrap(fmt.Errorf("error parsing flags and config: %w", err))
  224. }
  225. node, err := node.NewNode(cfg.mode, cfg.node)
  226. if err != nil {
  227. return tracerr.Wrap(fmt.Errorf("error starting node: %w", err))
  228. }
  229. node.Start()
  230. waitSigInt()
  231. node.Stop()
  232. return nil
  233. }
  234. func cmdServeAPI(c *cli.Context) error {
  235. cfg, err := parseCliAPIServer(c)
  236. if err != nil {
  237. return tracerr.Wrap(fmt.Errorf("error parsing flags and config: %w", err))
  238. }
  239. srv, err := node.NewAPIServer(cfg.mode, cfg.server)
  240. if err != nil {
  241. return tracerr.Wrap(fmt.Errorf("error starting api server: %w", err))
  242. }
  243. srv.Start()
  244. waitSigInt()
  245. srv.Stop()
  246. return nil
  247. }
  248. func cmdDiscard(c *cli.Context) error {
  249. _cfg, err := parseCli(c)
  250. if err != nil {
  251. return tracerr.Wrap(fmt.Errorf("error parsing flags and config: %w", err))
  252. }
  253. cfg := _cfg.node
  254. blockNum := c.Int64(flagBlock)
  255. log.Infof("Discarding all blocks up to block %v...", blockNum)
  256. dbWrite, err := dbUtils.InitSQLDB(
  257. cfg.PostgreSQL.PortWrite,
  258. cfg.PostgreSQL.HostWrite,
  259. cfg.PostgreSQL.UserWrite,
  260. cfg.PostgreSQL.PasswordWrite,
  261. cfg.PostgreSQL.NameWrite,
  262. )
  263. if err != nil {
  264. return tracerr.Wrap(fmt.Errorf("dbUtils.InitSQLDB: %w", err))
  265. }
  266. var dbRead *sqlx.DB
  267. if cfg.PostgreSQL.HostRead == "" {
  268. dbRead = dbWrite
  269. } else if cfg.PostgreSQL.HostRead == cfg.PostgreSQL.HostWrite {
  270. return tracerr.Wrap(fmt.Errorf(
  271. "PostgreSQL.HostRead and PostgreSQL.HostWrite must be different",
  272. ))
  273. } else {
  274. dbRead, err = dbUtils.InitSQLDB(
  275. cfg.PostgreSQL.PortRead,
  276. cfg.PostgreSQL.HostRead,
  277. cfg.PostgreSQL.UserRead,
  278. cfg.PostgreSQL.PasswordRead,
  279. cfg.PostgreSQL.NameRead,
  280. )
  281. if err != nil {
  282. return tracerr.Wrap(fmt.Errorf("dbUtils.InitSQLDB: %w", err))
  283. }
  284. }
  285. historyDB := historydb.NewHistoryDB(dbRead, dbWrite, nil)
  286. if err := historyDB.Reorg(blockNum); err != nil {
  287. return tracerr.Wrap(fmt.Errorf("historyDB.Reorg: %w", err))
  288. }
  289. batchNum, err := historyDB.GetLastBatchNum()
  290. if err != nil {
  291. return tracerr.Wrap(fmt.Errorf("historyDB.GetLastBatchNum: %w", err))
  292. }
  293. l2DB := l2db.NewL2DB(
  294. dbRead, dbWrite,
  295. cfg.Coordinator.L2DB.SafetyPeriod,
  296. cfg.Coordinator.L2DB.MaxTxs,
  297. cfg.Coordinator.L2DB.MinFeeUSD,
  298. cfg.Coordinator.L2DB.TTL.Duration,
  299. nil,
  300. )
  301. if err := l2DB.Reorg(batchNum); err != nil {
  302. return tracerr.Wrap(fmt.Errorf("l2DB.Reorg: %w", err))
  303. }
  304. log.Info("Resetting StateDBs...")
  305. if err := resetStateDBs(_cfg, batchNum); err != nil {
  306. return tracerr.Wrap(fmt.Errorf("resetStateDBs: %w", err))
  307. }
  308. return nil
  309. }
  310. // Config is the configuration of the hermez node execution
  311. type Config struct {
  312. mode node.Mode
  313. node *config.Node
  314. }
  315. func parseCli(c *cli.Context) (*Config, error) {
  316. cfg, err := getConfig(c)
  317. if err != nil {
  318. if err := cli.ShowAppHelp(c); err != nil {
  319. panic(err)
  320. }
  321. return nil, tracerr.Wrap(err)
  322. }
  323. return cfg, nil
  324. }
  325. func getConfig(c *cli.Context) (*Config, error) {
  326. var cfg Config
  327. mode := c.String(flagMode)
  328. nodeCfgPath := c.String(flagCfg)
  329. var err error
  330. switch mode {
  331. case modeSync:
  332. cfg.mode = node.ModeSynchronizer
  333. cfg.node, err = config.LoadNode(nodeCfgPath, false)
  334. if err != nil {
  335. return nil, tracerr.Wrap(err)
  336. }
  337. case modeCoord:
  338. cfg.mode = node.ModeCoordinator
  339. cfg.node, err = config.LoadNode(nodeCfgPath, true)
  340. if err != nil {
  341. return nil, tracerr.Wrap(err)
  342. }
  343. default:
  344. return nil, tracerr.Wrap(fmt.Errorf("invalid mode \"%v\"", mode))
  345. }
  346. return &cfg, nil
  347. }
  348. // ConfigAPIServer is the configuration of the api server execution
  349. type ConfigAPIServer struct {
  350. mode node.Mode
  351. server *config.APIServer
  352. }
  353. func parseCliAPIServer(c *cli.Context) (*ConfigAPIServer, error) {
  354. cfg, err := getConfigAPIServer(c)
  355. if err != nil {
  356. if err := cli.ShowAppHelp(c); err != nil {
  357. panic(err)
  358. }
  359. return nil, tracerr.Wrap(err)
  360. }
  361. return cfg, nil
  362. }
  363. func getConfigAPIServer(c *cli.Context) (*ConfigAPIServer, error) {
  364. var cfg ConfigAPIServer
  365. mode := c.String(flagMode)
  366. nodeCfgPath := c.String(flagCfg)
  367. var err error
  368. switch mode {
  369. case modeSync:
  370. cfg.mode = node.ModeSynchronizer
  371. cfg.server, err = config.LoadAPIServer(nodeCfgPath, false)
  372. if err != nil {
  373. return nil, tracerr.Wrap(err)
  374. }
  375. case modeCoord:
  376. cfg.mode = node.ModeCoordinator
  377. cfg.server, err = config.LoadAPIServer(nodeCfgPath, true)
  378. if err != nil {
  379. return nil, tracerr.Wrap(err)
  380. }
  381. default:
  382. return nil, tracerr.Wrap(fmt.Errorf("invalid mode \"%v\"", mode))
  383. }
  384. return &cfg, nil
  385. }
  386. func main() {
  387. app := cli.NewApp()
  388. app.Name = "hermez-node"
  389. app.Version = Version
  390. flags := []cli.Flag{
  391. &cli.StringFlag{
  392. Name: flagMode,
  393. Usage: fmt.Sprintf("Set node `MODE` (can be \"%v\" or \"%v\")", modeSync, modeCoord),
  394. Required: true,
  395. },
  396. &cli.StringFlag{
  397. Name: flagCfg,
  398. Usage: "Node configuration `FILE`",
  399. Required: true,
  400. },
  401. }
  402. app.Commands = []*cli.Command{
  403. {
  404. Name: "version",
  405. Aliases: []string{},
  406. Usage: "Show the application version and build",
  407. Action: cmdVersion,
  408. },
  409. {
  410. Name: "importkey",
  411. Aliases: []string{},
  412. Usage: "Import ethereum private key",
  413. Action: cmdImportKey,
  414. Flags: append(flags,
  415. &cli.StringFlag{
  416. Name: flagSK,
  417. Usage: "ethereum `PRIVATE_KEY` in hex",
  418. Required: true,
  419. }),
  420. },
  421. {
  422. Name: "genbjj",
  423. Aliases: []string{},
  424. Usage: "Generate a new BabyJubJub key",
  425. Action: cmdGenBJJ,
  426. },
  427. {
  428. Name: "wipesql",
  429. Aliases: []string{},
  430. Usage: "Wipe the SQL DB (HistoryDB and L2DB) and the StateDBs, " +
  431. "leaving the DB in a clean state",
  432. Action: cmdWipeSQL,
  433. Flags: append(flags,
  434. &cli.BoolFlag{
  435. Name: flagYes,
  436. Usage: "automatic yes to the prompt",
  437. Required: false,
  438. }),
  439. },
  440. {
  441. Name: "run",
  442. Aliases: []string{},
  443. Usage: "Run the hermez-node in the indicated mode",
  444. Action: cmdRun,
  445. Flags: flags,
  446. },
  447. {
  448. Name: "serveapi",
  449. Aliases: []string{},
  450. Usage: "Serve the API only",
  451. Action: cmdServeAPI,
  452. },
  453. {
  454. Name: "discard",
  455. Aliases: []string{},
  456. Usage: "Discard blocks up to a specified block number",
  457. Action: cmdDiscard,
  458. Flags: append(flags,
  459. &cli.Int64Flag{
  460. Name: flagBlock,
  461. Usage: "last block number to keep",
  462. Required: false,
  463. }),
  464. },
  465. }
  466. err := app.Run(os.Args)
  467. if err != nil {
  468. fmt.Printf("\nError: %v\n", tracerr.Sprint(err))
  469. os.Exit(1)
  470. }
  471. }