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