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