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