arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
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}