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.

305 lines
7.1 KiB

  1. package main
  2. import (
  3. "encoding/hex"
  4. "fmt"
  5. "os"
  6. "os/signal"
  7. "strings"
  8. ethKeystore "github.com/ethereum/go-ethereum/accounts/keystore"
  9. "github.com/ethereum/go-ethereum/crypto"
  10. "github.com/hermeznetwork/hermez-node/config"
  11. dbUtils "github.com/hermeznetwork/hermez-node/db"
  12. "github.com/hermeznetwork/hermez-node/db/historydb"
  13. "github.com/hermeznetwork/hermez-node/db/l2db"
  14. "github.com/hermeznetwork/hermez-node/log"
  15. "github.com/hermeznetwork/hermez-node/node"
  16. "github.com/hermeznetwork/tracerr"
  17. "github.com/iden3/go-iden3-crypto/babyjub"
  18. "github.com/urfave/cli/v2"
  19. )
  20. const (
  21. flagCfg = "cfg"
  22. flagMode = "mode"
  23. flagSK = "privatekey"
  24. flagYes = "yes"
  25. flagBlock = "block"
  26. modeSync = "sync"
  27. modeCoord = "coord"
  28. )
  29. func cmdGenBJJ(c *cli.Context) error {
  30. sk := babyjub.NewRandPrivKey()
  31. skBuf := [32]byte(sk)
  32. pk := sk.Public()
  33. fmt.Printf("BJJ = \"0x%s\"\n", pk.String())
  34. fmt.Printf("BJJPrivateKey = \"0x%s\"\n", hex.EncodeToString(skBuf[:]))
  35. return nil
  36. }
  37. func cmdImportKey(c *cli.Context) error {
  38. _cfg, err := parseCli(c)
  39. if err != nil {
  40. return tracerr.Wrap(fmt.Errorf("error parsing flags and config: %w", err))
  41. }
  42. if _cfg.mode != node.ModeCoordinator {
  43. return tracerr.Wrap(fmt.Errorf("importkey must use mode coordinator"))
  44. }
  45. cfg := _cfg.node
  46. scryptN := ethKeystore.StandardScryptN
  47. scryptP := ethKeystore.StandardScryptP
  48. if cfg.Coordinator.Debug.LightScrypt {
  49. scryptN = ethKeystore.LightScryptN
  50. scryptP = ethKeystore.LightScryptP
  51. }
  52. keyStore := ethKeystore.NewKeyStore(cfg.Coordinator.EthClient.Keystore.Path,
  53. scryptN, scryptP)
  54. hexKey := c.String(flagSK)
  55. hexKey = strings.TrimPrefix(hexKey, "0x")
  56. sk, err := crypto.HexToECDSA(hexKey)
  57. if err != nil {
  58. return tracerr.Wrap(err)
  59. }
  60. acc, err := keyStore.ImportECDSA(sk, cfg.Coordinator.EthClient.Keystore.Password)
  61. if err != nil {
  62. return tracerr.Wrap(err)
  63. }
  64. log.Infow("Imported private key", "addr", acc.Address.Hex())
  65. return nil
  66. }
  67. func cmdWipeSQL(c *cli.Context) error {
  68. _cfg, err := parseCli(c)
  69. if err != nil {
  70. return tracerr.Wrap(fmt.Errorf("error parsing flags and config: %w", err))
  71. }
  72. cfg := _cfg.node
  73. yes := c.Bool(flagYes)
  74. if !yes {
  75. fmt.Print("*WARNING* Are you sure you want to delete the SQL DB? [y/N]: ")
  76. var input string
  77. if _, err := fmt.Scanln(&input); err != nil {
  78. return tracerr.Wrap(err)
  79. }
  80. input = strings.ToLower(input)
  81. if !(input == "y" || input == "yes") {
  82. return nil
  83. }
  84. }
  85. db, err := dbUtils.ConnectSQLDB(
  86. cfg.PostgreSQL.Port,
  87. cfg.PostgreSQL.Host,
  88. cfg.PostgreSQL.User,
  89. cfg.PostgreSQL.Password,
  90. cfg.PostgreSQL.Name,
  91. )
  92. if err != nil {
  93. return tracerr.Wrap(err)
  94. }
  95. log.Info("Wiping SQL DB...")
  96. if err := dbUtils.MigrationsDown(db.DB); err != nil {
  97. return tracerr.Wrap(err)
  98. }
  99. return nil
  100. }
  101. func cmdRun(c *cli.Context) error {
  102. cfg, err := parseCli(c)
  103. if err != nil {
  104. return tracerr.Wrap(fmt.Errorf("error parsing flags and config: %w", err))
  105. }
  106. node, err := node.NewNode(cfg.mode, cfg.node)
  107. if err != nil {
  108. return tracerr.Wrap(fmt.Errorf("error starting node: %w", err))
  109. }
  110. node.Start()
  111. stopCh := make(chan interface{})
  112. // catch ^C to send the stop signal
  113. ossig := make(chan os.Signal, 1)
  114. signal.Notify(ossig, os.Interrupt)
  115. const forceStopCount = 3
  116. go func() {
  117. n := 0
  118. for sig := range ossig {
  119. if sig == os.Interrupt {
  120. log.Info("Received Interrupt Signal")
  121. stopCh <- nil
  122. n++
  123. if n == forceStopCount {
  124. log.Fatalf("Received %v Interrupt Signals", forceStopCount)
  125. }
  126. }
  127. }
  128. }()
  129. <-stopCh
  130. node.Stop()
  131. return nil
  132. }
  133. func cmdDiscard(c *cli.Context) error {
  134. _cfg, err := parseCli(c)
  135. if err != nil {
  136. return tracerr.Wrap(fmt.Errorf("error parsing flags and config: %w", err))
  137. }
  138. cfg := _cfg.node
  139. blockNum := c.Int64(flagBlock)
  140. log.Infof("Discarding all blocks up to block %v...", blockNum)
  141. db, err := dbUtils.InitSQLDB(
  142. cfg.PostgreSQL.Port,
  143. cfg.PostgreSQL.Host,
  144. cfg.PostgreSQL.User,
  145. cfg.PostgreSQL.Password,
  146. cfg.PostgreSQL.Name,
  147. )
  148. if err != nil {
  149. return tracerr.Wrap(fmt.Errorf("dbUtils.InitSQLDB: %w", err))
  150. }
  151. historyDB := historydb.NewHistoryDB(db, nil)
  152. if err := historyDB.Reorg(blockNum); err != nil {
  153. return tracerr.Wrap(fmt.Errorf("historyDB.Reorg: %w", err))
  154. }
  155. batchNum, err := historyDB.GetLastBatchNum()
  156. if err != nil {
  157. return tracerr.Wrap(fmt.Errorf("historyDB.GetLastBatchNum: %w", err))
  158. }
  159. l2DB := l2db.NewL2DB(
  160. db,
  161. cfg.Coordinator.L2DB.SafetyPeriod,
  162. cfg.Coordinator.L2DB.MaxTxs,
  163. cfg.Coordinator.L2DB.TTL.Duration,
  164. nil,
  165. )
  166. if err := l2DB.Reorg(batchNum); err != nil {
  167. return tracerr.Wrap(fmt.Errorf("l2DB.Reorg: %w", err))
  168. }
  169. return nil
  170. }
  171. // Config is the configuration of the hermez node execution
  172. type Config struct {
  173. mode node.Mode
  174. node *config.Node
  175. }
  176. func parseCli(c *cli.Context) (*Config, error) {
  177. cfg, err := getConfig(c)
  178. if err != nil {
  179. if err := cli.ShowAppHelp(c); err != nil {
  180. panic(err)
  181. }
  182. return nil, tracerr.Wrap(err)
  183. }
  184. return cfg, nil
  185. }
  186. func getConfig(c *cli.Context) (*Config, error) {
  187. var cfg Config
  188. mode := c.String(flagMode)
  189. nodeCfgPath := c.String(flagCfg)
  190. if nodeCfgPath == "" {
  191. return nil, tracerr.Wrap(fmt.Errorf("required flag \"%v\" not set", flagCfg))
  192. }
  193. var err error
  194. switch mode {
  195. case modeSync:
  196. cfg.mode = node.ModeSynchronizer
  197. cfg.node, err = config.LoadNode(nodeCfgPath)
  198. if err != nil {
  199. return nil, tracerr.Wrap(err)
  200. }
  201. case modeCoord:
  202. cfg.mode = node.ModeCoordinator
  203. cfg.node, err = config.LoadCoordinator(nodeCfgPath)
  204. if err != nil {
  205. return nil, tracerr.Wrap(err)
  206. }
  207. default:
  208. return nil, tracerr.Wrap(fmt.Errorf("invalid mode \"%v\"", mode))
  209. }
  210. return &cfg, nil
  211. }
  212. func main() {
  213. app := cli.NewApp()
  214. app.Name = "hermez-node"
  215. app.Version = "0.1.0-alpha"
  216. app.Flags = []cli.Flag{
  217. &cli.StringFlag{
  218. Name: flagMode,
  219. Usage: fmt.Sprintf("Set node `MODE` (can be \"%v\" or \"%v\")", modeSync, modeCoord),
  220. Required: true,
  221. },
  222. &cli.StringFlag{
  223. Name: flagCfg,
  224. Usage: "Node configuration `FILE`",
  225. Required: true,
  226. },
  227. }
  228. app.Commands = []*cli.Command{
  229. {
  230. Name: "importkey",
  231. Aliases: []string{},
  232. Usage: "Import ethereum private key",
  233. Action: cmdImportKey,
  234. Flags: []cli.Flag{
  235. &cli.StringFlag{
  236. Name: flagSK,
  237. Usage: "ethereum `PRIVATE_KEY` in hex",
  238. Required: true,
  239. }},
  240. },
  241. {
  242. Name: "genbjj",
  243. Aliases: []string{},
  244. Usage: "Generate a new BabyJubJub key",
  245. Action: cmdGenBJJ,
  246. },
  247. {
  248. Name: "wipesql",
  249. Aliases: []string{},
  250. Usage: "Wipe the SQL DB (HistoryDB and L2DB), " +
  251. "leaving the DB in a clean state",
  252. Action: cmdWipeSQL,
  253. Flags: []cli.Flag{
  254. &cli.BoolFlag{
  255. Name: flagYes,
  256. Usage: "automatic yes to the prompt",
  257. Required: false,
  258. }},
  259. },
  260. {
  261. Name: "run",
  262. Aliases: []string{},
  263. Usage: "Run the hermez-node in the indicated mode",
  264. Action: cmdRun,
  265. },
  266. {
  267. Name: "discard",
  268. Aliases: []string{},
  269. Usage: "Discard blocks up to a specified block number",
  270. Action: cmdDiscard,
  271. Flags: []cli.Flag{
  272. &cli.Int64Flag{
  273. Name: flagBlock,
  274. Usage: "last block number to keep",
  275. Required: false,
  276. }},
  277. },
  278. }
  279. err := app.Run(os.Args)
  280. if err != nil {
  281. fmt.Printf("\nError: %v\n", tracerr.Sprint(err))
  282. os.Exit(1)
  283. }
  284. }