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.

242 lines
5.5 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. go func() {
  113. for sig := range ossig {
  114. if sig == os.Interrupt {
  115. stopCh <- nil
  116. }
  117. }
  118. }()
  119. <-stopCh
  120. node.Stop()
  121. return nil
  122. }
  123. // Config is the configuration of the hermez node execution
  124. type Config struct {
  125. mode node.Mode
  126. node *config.Node
  127. }
  128. func parseCli(c *cli.Context) (*Config, error) {
  129. cfg, err := getConfig(c)
  130. if err != nil {
  131. if err := cli.ShowAppHelp(c); err != nil {
  132. panic(err)
  133. }
  134. return nil, tracerr.Wrap(err)
  135. }
  136. return cfg, nil
  137. }
  138. func getConfig(c *cli.Context) (*Config, error) {
  139. var cfg Config
  140. mode := c.String(flagMode)
  141. nodeCfgPath := c.String(flagCfg)
  142. if nodeCfgPath == "" {
  143. return nil, tracerr.Wrap(fmt.Errorf("required flag \"%v\" not set", flagCfg))
  144. }
  145. var err error
  146. switch mode {
  147. case modeSync:
  148. cfg.mode = node.ModeSynchronizer
  149. cfg.node, err = config.LoadNode(nodeCfgPath)
  150. if err != nil {
  151. return nil, tracerr.Wrap(err)
  152. }
  153. case modeCoord:
  154. cfg.mode = node.ModeCoordinator
  155. cfg.node, err = config.LoadCoordinator(nodeCfgPath)
  156. if err != nil {
  157. return nil, tracerr.Wrap(err)
  158. }
  159. default:
  160. return nil, tracerr.Wrap(fmt.Errorf("invalid mode \"%v\"", mode))
  161. }
  162. return &cfg, nil
  163. }
  164. func main() {
  165. app := cli.NewApp()
  166. app.Name = "hermez-node"
  167. app.Version = "0.1.0-alpha"
  168. app.Flags = []cli.Flag{
  169. &cli.StringFlag{
  170. Name: flagMode,
  171. Usage: fmt.Sprintf("Set node `MODE` (can be \"%v\" or \"%v\")", modeSync, modeCoord),
  172. Required: true,
  173. },
  174. &cli.StringFlag{
  175. Name: flagCfg,
  176. Usage: "Node configuration `FILE`",
  177. Required: true,
  178. },
  179. }
  180. app.Commands = []*cli.Command{
  181. {
  182. Name: "importkey",
  183. Aliases: []string{},
  184. Usage: "Import ethereum private key",
  185. Action: cmdImportKey,
  186. Flags: []cli.Flag{
  187. &cli.StringFlag{
  188. Name: flagSK,
  189. Usage: "ethereum `PRIVATE_KEY` in hex",
  190. Required: true,
  191. }},
  192. },
  193. {
  194. Name: "genbjj",
  195. Aliases: []string{},
  196. Usage: "Generate a new BabyJubJub key",
  197. Action: cmdGenBJJ,
  198. },
  199. {
  200. Name: "wipesql",
  201. Aliases: []string{},
  202. Usage: "Wipe the SQL DB (HistoryDB and L2DB), " +
  203. "leaving the DB in a clean state",
  204. Action: cmdWipeSQL,
  205. Flags: []cli.Flag{
  206. &cli.BoolFlag{
  207. Name: flagYes,
  208. Usage: "automatic yes to the prompt",
  209. Required: false,
  210. }},
  211. },
  212. {
  213. Name: "run",
  214. Aliases: []string{},
  215. Usage: "Run the hermez-node in the indicated mode",
  216. Action: cmdRun,
  217. },
  218. }
  219. err := app.Run(os.Args)
  220. if err != nil {
  221. fmt.Printf("\nError: %v\n", tracerr.Sprint(err))
  222. os.Exit(1)
  223. }
  224. }