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.

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