github.com/prysmaticlabs/prysm@v1.4.4/validator/node/node.go (about) 1 // Package node is the main process which handles the lifecycle of 2 // the runtime services in a validator client process, gracefully shutting 3 // everything down upon close. 4 package node 5 6 import ( 7 "context" 8 "fmt" 9 "net/http" 10 "os" 11 "os/signal" 12 "path/filepath" 13 "strings" 14 "sync" 15 "syscall" 16 17 gwruntime "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" 18 "github.com/pkg/errors" 19 "github.com/prysmaticlabs/prysm/cmd/validator/flags" 20 pb "github.com/prysmaticlabs/prysm/proto/validator/accounts/v2" 21 "github.com/prysmaticlabs/prysm/shared" 22 "github.com/prysmaticlabs/prysm/shared/backuputil" 23 "github.com/prysmaticlabs/prysm/shared/cmd" 24 "github.com/prysmaticlabs/prysm/shared/debug" 25 "github.com/prysmaticlabs/prysm/shared/event" 26 "github.com/prysmaticlabs/prysm/shared/featureconfig" 27 "github.com/prysmaticlabs/prysm/shared/fileutil" 28 "github.com/prysmaticlabs/prysm/shared/gateway" 29 "github.com/prysmaticlabs/prysm/shared/params" 30 "github.com/prysmaticlabs/prysm/shared/prereq" 31 "github.com/prysmaticlabs/prysm/shared/prometheus" 32 "github.com/prysmaticlabs/prysm/shared/tracing" 33 "github.com/prysmaticlabs/prysm/shared/version" 34 accountsiface "github.com/prysmaticlabs/prysm/validator/accounts/iface" 35 "github.com/prysmaticlabs/prysm/validator/accounts/wallet" 36 "github.com/prysmaticlabs/prysm/validator/client" 37 "github.com/prysmaticlabs/prysm/validator/db/kv" 38 g "github.com/prysmaticlabs/prysm/validator/graffiti" 39 "github.com/prysmaticlabs/prysm/validator/keymanager" 40 "github.com/prysmaticlabs/prysm/validator/keymanager/imported" 41 "github.com/prysmaticlabs/prysm/validator/rpc" 42 slashingprotection "github.com/prysmaticlabs/prysm/validator/slashing-protection" 43 "github.com/prysmaticlabs/prysm/validator/slashing-protection/iface" 44 "github.com/prysmaticlabs/prysm/validator/web" 45 "github.com/sirupsen/logrus" 46 "github.com/urfave/cli/v2" 47 "google.golang.org/protobuf/encoding/protojson" 48 ) 49 50 // ValidatorClient defines an instance of an Ethereum validator that manages 51 // the entire lifecycle of services attached to it participating in proof of stake. 52 type ValidatorClient struct { 53 cliCtx *cli.Context 54 ctx context.Context 55 cancel context.CancelFunc 56 db *kv.Store 57 services *shared.ServiceRegistry // Lifecycle and service store. 58 lock sync.RWMutex 59 wallet *wallet.Wallet 60 walletInitialized *event.Feed 61 stop chan struct{} // Channel to wait for termination notifications. 62 } 63 64 // NewValidatorClient creates a new instance of the Prysm validator client. 65 func NewValidatorClient(cliCtx *cli.Context) (*ValidatorClient, error) { 66 if err := tracing.Setup( 67 "validator", // service name 68 cliCtx.String(cmd.TracingProcessNameFlag.Name), 69 cliCtx.String(cmd.TracingEndpointFlag.Name), 70 cliCtx.Float64(cmd.TraceSampleFractionFlag.Name), 71 cliCtx.Bool(cmd.EnableTracingFlag.Name), 72 ); err != nil { 73 return nil, err 74 } 75 76 verbosity := cliCtx.String(cmd.VerbosityFlag.Name) 77 level, err := logrus.ParseLevel(verbosity) 78 if err != nil { 79 return nil, err 80 } 81 logrus.SetLevel(level) 82 83 // Warn if user's platform is not supported 84 prereq.WarnIfPlatformNotSupported(cliCtx.Context) 85 86 registry := shared.NewServiceRegistry() 87 ctx, cancel := context.WithCancel(cliCtx.Context) 88 validatorClient := &ValidatorClient{ 89 cliCtx: cliCtx, 90 ctx: ctx, 91 cancel: cancel, 92 services: registry, 93 walletInitialized: new(event.Feed), 94 stop: make(chan struct{}), 95 } 96 97 featureconfig.ConfigureValidator(cliCtx) 98 cmd.ConfigureValidator(cliCtx) 99 100 if cliCtx.IsSet(cmd.ChainConfigFileFlag.Name) { 101 chainConfigFileName := cliCtx.String(cmd.ChainConfigFileFlag.Name) 102 params.LoadChainConfigFile(chainConfigFileName) 103 } 104 105 // If the --web flag is enabled to administer the validator 106 // client via a web portal, we start the validator client in a different way. 107 if cliCtx.IsSet(flags.EnableWebFlag.Name) { 108 log.Info("Enabling web portal to manage the validator client") 109 if err := validatorClient.initializeForWeb(cliCtx); err != nil { 110 return nil, err 111 } 112 return validatorClient, nil 113 } 114 115 if cliCtx.IsSet(cmd.ChainConfigFileFlag.Name) { 116 chainConfigFileName := cliCtx.String(cmd.ChainConfigFileFlag.Name) 117 params.LoadChainConfigFile(chainConfigFileName) 118 } 119 120 if err := validatorClient.initializeFromCLI(cliCtx); err != nil { 121 return nil, err 122 } 123 124 return validatorClient, nil 125 } 126 127 // Start every service in the validator client. 128 func (c *ValidatorClient) Start() { 129 c.lock.Lock() 130 131 log.WithFields(logrus.Fields{ 132 "version": version.Version(), 133 }).Info("Starting validator node") 134 135 c.services.StartAll() 136 137 stop := c.stop 138 c.lock.Unlock() 139 140 go func() { 141 sigc := make(chan os.Signal, 1) 142 signal.Notify(sigc, syscall.SIGINT, syscall.SIGTERM) 143 defer signal.Stop(sigc) 144 <-sigc 145 log.Info("Got interrupt, shutting down...") 146 debug.Exit(c.cliCtx) // Ensure trace and CPU profile data are flushed. 147 go c.Close() 148 for i := 10; i > 0; i-- { 149 <-sigc 150 if i > 1 { 151 log.WithField("times", i-1).Info("Already shutting down, interrupt more to panic.") 152 } 153 } 154 panic("Panic closing the validator client") 155 }() 156 157 // Wait for stop channel to be closed. 158 <-stop 159 } 160 161 // Close handles graceful shutdown of the system. 162 func (c *ValidatorClient) Close() { 163 c.lock.Lock() 164 defer c.lock.Unlock() 165 166 c.services.StopAll() 167 log.Info("Stopping Prysm validator") 168 c.cancel() 169 close(c.stop) 170 } 171 172 func (c *ValidatorClient) initializeFromCLI(cliCtx *cli.Context) error { 173 var keyManager keymanager.IKeymanager 174 var err error 175 if cliCtx.IsSet(flags.InteropNumValidators.Name) { 176 numValidatorKeys := cliCtx.Uint64(flags.InteropNumValidators.Name) 177 offset := cliCtx.Uint64(flags.InteropStartIndex.Name) 178 keyManager, err = imported.NewInteropKeymanager(cliCtx.Context, offset, numValidatorKeys) 179 if err != nil { 180 return errors.Wrap(err, "could not generate interop keys") 181 } 182 } else { 183 // Read the wallet from the specified path. 184 w, err := wallet.OpenWalletOrElseCli(cliCtx, func(cliCtx *cli.Context) (*wallet.Wallet, error) { 185 return nil, wallet.ErrNoWalletFound 186 }) 187 if err != nil { 188 return errors.Wrap(err, "could not open wallet") 189 } 190 c.wallet = w 191 log.WithFields(logrus.Fields{ 192 "wallet": w.AccountsDir(), 193 "keymanager-kind": w.KeymanagerKind().String(), 194 }).Info("Opened validator wallet") 195 keyManager, err = w.InitializeKeymanager(cliCtx.Context, accountsiface.InitKeymanagerConfig{ListenForChanges: true}) 196 if err != nil { 197 return errors.Wrap(err, "could not read keymanager for wallet") 198 } 199 } 200 dataDir := cliCtx.String(flags.WalletDirFlag.Name) 201 if c.wallet != nil { 202 dataDir = c.wallet.AccountsDir() 203 } 204 if cliCtx.String(cmd.DataDirFlag.Name) != cmd.DefaultDataDir() { 205 dataDir = cliCtx.String(cmd.DataDirFlag.Name) 206 } 207 clearFlag := cliCtx.Bool(cmd.ClearDB.Name) 208 forceClearFlag := cliCtx.Bool(cmd.ForceClearDB.Name) 209 if clearFlag || forceClearFlag { 210 if dataDir == "" && c.wallet != nil { 211 dataDir = c.wallet.AccountsDir() 212 if dataDir == "" { 213 log.Fatal( 214 "Could not determine your system'c HOME path, please specify a --datadir you wish " + 215 "to use for your validator data", 216 ) 217 } 218 219 } 220 if err := clearDB(cliCtx.Context, dataDir, forceClearFlag); err != nil { 221 return err 222 } 223 } else { 224 dataFile := filepath.Join(dataDir, kv.ProtectionDbFileName) 225 if !fileutil.FileExists(dataFile) { 226 log.Warnf("Slashing protection file %s is missing.\n"+ 227 "If you changed your --wallet-dir or --datadir, please copy your previous \"validator.db\" file into your current --datadir.\n"+ 228 "Disregard this warning if this is the first time you are running this set of keys.", dataFile) 229 } 230 } 231 log.WithField("databasePath", dataDir).Info("Checking DB") 232 233 valDB, err := kv.NewKVStore(cliCtx.Context, dataDir, &kv.Config{ 234 PubKeys: nil, 235 InitialMMapSize: cliCtx.Int(cmd.BoltMMapInitialSizeFlag.Name), 236 }) 237 if err != nil { 238 return errors.Wrap(err, "could not initialize db") 239 } 240 c.db = valDB 241 if err := valDB.RunUpMigrations(cliCtx.Context); err != nil { 242 return errors.Wrap(err, "could not run database migration") 243 } 244 245 if !cliCtx.Bool(cmd.DisableMonitoringFlag.Name) { 246 if err := c.registerPrometheusService(cliCtx); err != nil { 247 return err 248 } 249 } 250 if featureconfig.Get().SlasherProtection { 251 if err := c.registerSlasherService(); err != nil { 252 return err 253 } 254 } 255 if err := c.registerValidatorService(keyManager); err != nil { 256 return err 257 } 258 if cliCtx.Bool(flags.EnableRPCFlag.Name) { 259 if err := c.registerRPCService(cliCtx, keyManager); err != nil { 260 return err 261 } 262 if err := c.registerRPCGatewayService(cliCtx); err != nil { 263 return err 264 } 265 } 266 return nil 267 } 268 269 func (c *ValidatorClient) initializeForWeb(cliCtx *cli.Context) error { 270 var keyManager keymanager.IKeymanager 271 var err error 272 273 // Read the wallet password file from the cli context. 274 if err = setWalletPasswordFilePath(cliCtx); err != nil { 275 return errors.Wrap(err, "could not read wallet password file") 276 } 277 278 // Read the wallet from the specified path. 279 w, err := wallet.OpenWalletOrElseCli(cliCtx, func(cliCtx *cli.Context) (*wallet.Wallet, error) { 280 return nil, nil 281 }) 282 if err != nil { 283 return errors.Wrap(err, "could not open wallet") 284 } 285 if w != nil { 286 c.wallet = w 287 log.WithFields(logrus.Fields{ 288 "wallet": w.AccountsDir(), 289 "keymanager-kind": w.KeymanagerKind().String(), 290 }).Info("Opened validator wallet") 291 keyManager, err = w.InitializeKeymanager(cliCtx.Context, accountsiface.InitKeymanagerConfig{ListenForChanges: true}) 292 if err != nil { 293 return errors.Wrap(err, "could not read keymanager for wallet") 294 } 295 } 296 dataDir := cliCtx.String(flags.WalletDirFlag.Name) 297 if c.wallet != nil { 298 dataDir = c.wallet.AccountsDir() 299 } 300 if cliCtx.String(cmd.DataDirFlag.Name) != cmd.DefaultDataDir() { 301 dataDir = cliCtx.String(cmd.DataDirFlag.Name) 302 } 303 clearFlag := cliCtx.Bool(cmd.ClearDB.Name) 304 forceClearFlag := cliCtx.Bool(cmd.ForceClearDB.Name) 305 306 if clearFlag || forceClearFlag { 307 if dataDir == "" { 308 dataDir = cmd.DefaultDataDir() 309 if dataDir == "" { 310 log.Fatal( 311 "Could not determine your system'c HOME path, please specify a --datadir you wish " + 312 "to use for your validator data", 313 ) 314 } 315 316 } 317 if err := clearDB(cliCtx.Context, dataDir, forceClearFlag); err != nil { 318 return err 319 } 320 } 321 log.WithField("databasePath", dataDir).Info("Checking DB") 322 valDB, err := kv.NewKVStore(cliCtx.Context, dataDir, &kv.Config{ 323 PubKeys: nil, 324 InitialMMapSize: cliCtx.Int(cmd.BoltMMapInitialSizeFlag.Name), 325 }) 326 if err != nil { 327 return errors.Wrap(err, "could not initialize db") 328 } 329 c.db = valDB 330 if err := valDB.RunUpMigrations(cliCtx.Context); err != nil { 331 return errors.Wrap(err, "could not run database migration") 332 } 333 334 if !cliCtx.Bool(cmd.DisableMonitoringFlag.Name) { 335 if err := c.registerPrometheusService(cliCtx); err != nil { 336 return err 337 } 338 } 339 if featureconfig.Get().SlasherProtection { 340 if err := c.registerSlasherService(); err != nil { 341 return err 342 } 343 } 344 if err := c.registerValidatorService(keyManager); err != nil { 345 return err 346 } 347 if err := c.registerRPCService(cliCtx, keyManager); err != nil { 348 return err 349 } 350 if err := c.registerRPCGatewayService(cliCtx); err != nil { 351 return err 352 } 353 gatewayHost := cliCtx.String(flags.GRPCGatewayHost.Name) 354 gatewayPort := cliCtx.Int(flags.GRPCGatewayPort.Name) 355 webAddress := fmt.Sprintf("http://%s:%d", gatewayHost, gatewayPort) 356 log.WithField("address", webAddress).Info( 357 "Starting Prysm web UI on address, open in browser to access", 358 ) 359 return nil 360 } 361 362 func (c *ValidatorClient) registerPrometheusService(cliCtx *cli.Context) error { 363 var additionalHandlers []prometheus.Handler 364 if cliCtx.IsSet(cmd.EnableBackupWebhookFlag.Name) { 365 additionalHandlers = append( 366 additionalHandlers, 367 prometheus.Handler{ 368 Path: "/db/backup", 369 Handler: backuputil.BackupHandler(c.db, cliCtx.String(cmd.BackupWebhookOutputDir.Name)), 370 }, 371 ) 372 } 373 service := prometheus.NewService( 374 fmt.Sprintf("%s:%d", c.cliCtx.String(cmd.MonitoringHostFlag.Name), c.cliCtx.Int(flags.MonitoringPortFlag.Name)), 375 c.services, 376 additionalHandlers..., 377 ) 378 logrus.AddHook(prometheus.NewLogrusCollector()) 379 return c.services.RegisterService(service) 380 } 381 382 func (c *ValidatorClient) registerValidatorService( 383 keyManager keymanager.IKeymanager, 384 ) error { 385 endpoint := c.cliCtx.String(flags.BeaconRPCProviderFlag.Name) 386 dataDir := c.cliCtx.String(cmd.DataDirFlag.Name) 387 logValidatorBalances := !c.cliCtx.Bool(flags.DisablePenaltyRewardLogFlag.Name) 388 emitAccountMetrics := !c.cliCtx.Bool(flags.DisableAccountMetricsFlag.Name) 389 cert := c.cliCtx.String(flags.CertFlag.Name) 390 graffiti := c.cliCtx.String(flags.GraffitiFlag.Name) 391 maxCallRecvMsgSize := c.cliCtx.Int(cmd.GrpcMaxCallRecvMsgSizeFlag.Name) 392 grpcRetries := c.cliCtx.Uint(flags.GrpcRetriesFlag.Name) 393 grpcRetryDelay := c.cliCtx.Duration(flags.GrpcRetryDelayFlag.Name) 394 var sp *slashingprotection.Service 395 var protector iface.Protector 396 if err := c.services.FetchService(&sp); err == nil { 397 protector = sp 398 } 399 400 gStruct := &g.Graffiti{} 401 var err error 402 if c.cliCtx.IsSet(flags.GraffitiFileFlag.Name) { 403 n := c.cliCtx.String(flags.GraffitiFileFlag.Name) 404 gStruct, err = g.ParseGraffitiFile(n) 405 if err != nil { 406 log.WithError(err).Warn("Could not parse graffiti file") 407 } 408 } 409 410 v, err := client.NewValidatorService(c.cliCtx.Context, &client.Config{ 411 Endpoint: endpoint, 412 DataDir: dataDir, 413 KeyManager: keyManager, 414 LogValidatorBalances: logValidatorBalances, 415 EmitAccountMetrics: emitAccountMetrics, 416 CertFlag: cert, 417 GraffitiFlag: g.ParseHexGraffiti(graffiti), 418 GrpcMaxCallRecvMsgSizeFlag: maxCallRecvMsgSize, 419 GrpcRetriesFlag: grpcRetries, 420 GrpcRetryDelay: grpcRetryDelay, 421 GrpcHeadersFlag: c.cliCtx.String(flags.GrpcHeadersFlag.Name), 422 Protector: protector, 423 ValDB: c.db, 424 UseWeb: c.cliCtx.Bool(flags.EnableWebFlag.Name), 425 WalletInitializedFeed: c.walletInitialized, 426 GraffitiStruct: gStruct, 427 LogDutyCountDown: c.cliCtx.Bool(flags.EnableDutyCountDown.Name), 428 }) 429 if err != nil { 430 return errors.Wrap(err, "could not initialize validator service") 431 } 432 433 return c.services.RegisterService(v) 434 } 435 func (c *ValidatorClient) registerSlasherService() error { 436 endpoint := c.cliCtx.String(flags.SlasherRPCProviderFlag.Name) 437 if endpoint == "" { 438 return errors.New("external slasher feature flag is set but no slasher endpoint is configured") 439 440 } 441 cert := c.cliCtx.String(flags.SlasherCertFlag.Name) 442 maxCallRecvMsgSize := c.cliCtx.Int(cmd.GrpcMaxCallRecvMsgSizeFlag.Name) 443 grpcRetries := c.cliCtx.Uint(flags.GrpcRetriesFlag.Name) 444 grpcRetryDelay := c.cliCtx.Duration(flags.GrpcRetryDelayFlag.Name) 445 sp, err := slashingprotection.NewService(c.cliCtx.Context, &slashingprotection.Config{ 446 Endpoint: endpoint, 447 CertFlag: cert, 448 GrpcMaxCallRecvMsgSizeFlag: maxCallRecvMsgSize, 449 GrpcRetriesFlag: grpcRetries, 450 GrpcRetryDelay: grpcRetryDelay, 451 GrpcHeadersFlag: c.cliCtx.String(flags.GrpcHeadersFlag.Name), 452 }) 453 if err != nil { 454 return errors.Wrap(err, "could not initialize slasher service") 455 } 456 return c.services.RegisterService(sp) 457 } 458 459 func (c *ValidatorClient) registerRPCService(cliCtx *cli.Context, km keymanager.IKeymanager) error { 460 var vs *client.ValidatorService 461 if err := c.services.FetchService(&vs); err != nil { 462 return err 463 } 464 validatorGatewayHost := cliCtx.String(flags.GRPCGatewayHost.Name) 465 validatorGatewayPort := cliCtx.Int(flags.GRPCGatewayPort.Name) 466 validatorMonitoringHost := cliCtx.String(cmd.MonitoringHostFlag.Name) 467 validatorMonitoringPort := cliCtx.Int(flags.MonitoringPortFlag.Name) 468 rpcHost := cliCtx.String(flags.RPCHost.Name) 469 rpcPort := cliCtx.Int(flags.RPCPort.Name) 470 nodeGatewayEndpoint := cliCtx.String(flags.BeaconRPCGatewayProviderFlag.Name) 471 beaconClientEndpoint := cliCtx.String(flags.BeaconRPCProviderFlag.Name) 472 maxCallRecvMsgSize := c.cliCtx.Int(cmd.GrpcMaxCallRecvMsgSizeFlag.Name) 473 grpcRetries := c.cliCtx.Uint(flags.GrpcRetriesFlag.Name) 474 grpcRetryDelay := c.cliCtx.Duration(flags.GrpcRetryDelayFlag.Name) 475 walletDir := cliCtx.String(flags.WalletDirFlag.Name) 476 grpcHeaders := c.cliCtx.String(flags.GrpcHeadersFlag.Name) 477 clientCert := c.cliCtx.String(flags.CertFlag.Name) 478 server := rpc.NewServer(cliCtx.Context, &rpc.Config{ 479 ValDB: c.db, 480 Host: rpcHost, 481 Port: fmt.Sprintf("%d", rpcPort), 482 WalletInitializedFeed: c.walletInitialized, 483 ValidatorService: vs, 484 SyncChecker: vs, 485 GenesisFetcher: vs, 486 NodeGatewayEndpoint: nodeGatewayEndpoint, 487 WalletDir: walletDir, 488 Wallet: c.wallet, 489 Keymanager: km, 490 ValidatorGatewayHost: validatorGatewayHost, 491 ValidatorGatewayPort: validatorGatewayPort, 492 ValidatorMonitoringHost: validatorMonitoringHost, 493 ValidatorMonitoringPort: validatorMonitoringPort, 494 BeaconClientEndpoint: beaconClientEndpoint, 495 ClientMaxCallRecvMsgSize: maxCallRecvMsgSize, 496 ClientGrpcRetries: grpcRetries, 497 ClientGrpcRetryDelay: grpcRetryDelay, 498 ClientGrpcHeaders: strings.Split(grpcHeaders, ","), 499 ClientWithCert: clientCert, 500 }) 501 return c.services.RegisterService(server) 502 } 503 504 func (c *ValidatorClient) registerRPCGatewayService(cliCtx *cli.Context) error { 505 gatewayHost := cliCtx.String(flags.GRPCGatewayHost.Name) 506 if gatewayHost != flags.DefaultGatewayHost { 507 log.WithField("web-host", gatewayHost).Warn( 508 "You are using a non-default web host. Web traffic is served by HTTP, so be wary of " + 509 "changing this parameter if you are exposing this host to the Internet!", 510 ) 511 } 512 gatewayPort := cliCtx.Int(flags.GRPCGatewayPort.Name) 513 rpcHost := cliCtx.String(flags.RPCHost.Name) 514 rpcPort := cliCtx.Int(flags.RPCPort.Name) 515 rpcAddr := fmt.Sprintf("%s:%d", rpcHost, rpcPort) 516 gatewayAddress := fmt.Sprintf("%s:%d", gatewayHost, gatewayPort) 517 allowedOrigins := strings.Split(cliCtx.String(flags.GPRCGatewayCorsDomain.Name), ",") 518 maxCallSize := cliCtx.Uint64(cmd.GrpcMaxCallRecvMsgSizeFlag.Name) 519 520 registrations := []gateway.PbHandlerRegistration{ 521 pb.RegisterAuthHandler, 522 pb.RegisterWalletHandler, 523 pb.RegisterHealthHandler, 524 pb.RegisterAccountsHandler, 525 pb.RegisterBeaconHandler, 526 pb.RegisterSlashingProtectionHandler, 527 } 528 mux := gwruntime.NewServeMux( 529 gwruntime.WithMarshalerOption(gwruntime.MIMEWildcard, &gwruntime.HTTPBodyMarshaler{ 530 Marshaler: &gwruntime.JSONPb{ 531 MarshalOptions: protojson.MarshalOptions{ 532 EmitUnpopulated: true, 533 }, 534 UnmarshalOptions: protojson.UnmarshalOptions{ 535 DiscardUnknown: true, 536 }, 537 }, 538 }), 539 gwruntime.WithMarshalerOption( 540 "text/event-stream", &gwruntime.EventSourceJSONPb{}, 541 ), 542 ) 543 muxHandler := func(h http.Handler, w http.ResponseWriter, req *http.Request) { 544 if strings.HasPrefix(req.URL.Path, "/api") { 545 http.StripPrefix("/api", h).ServeHTTP(w, req) 546 } else { 547 web.Handler(w, req) 548 } 549 } 550 551 pbHandler := gateway.PbMux{ 552 Registrations: registrations, 553 Patterns: []string{"/accounts/", "/v2/"}, 554 Mux: mux, 555 } 556 557 gw := gateway.New( 558 cliCtx.Context, 559 []gateway.PbMux{pbHandler}, 560 muxHandler, 561 rpcAddr, 562 gatewayAddress, 563 ).WithAllowedOrigins(allowedOrigins).WithMaxCallRecvMsgSize(maxCallSize) 564 565 return c.services.RegisterService(gw) 566 } 567 568 func setWalletPasswordFilePath(cliCtx *cli.Context) error { 569 walletDir := cliCtx.String(flags.WalletDirFlag.Name) 570 defaultWalletPasswordFilePath := filepath.Join(walletDir, wallet.DefaultWalletPasswordFile) 571 if fileutil.FileExists(defaultWalletPasswordFilePath) { 572 // Ensure file has proper permissions. 573 hasPerms, err := fileutil.HasReadWritePermissions(defaultWalletPasswordFilePath) 574 if err != nil { 575 return err 576 } 577 if !hasPerms { 578 return fmt.Errorf( 579 "wallet password file %s does not have proper 0600 permissions", 580 defaultWalletPasswordFilePath, 581 ) 582 } 583 584 // Set the filepath into the cli context. 585 if err := cliCtx.Set(flags.WalletPasswordFileFlag.Name, defaultWalletPasswordFilePath); err != nil { 586 return errors.Wrap(err, "could not set default wallet password file path") 587 } 588 } 589 return nil 590 } 591 592 func clearDB(ctx context.Context, dataDir string, force bool) error { 593 var err error 594 clearDBConfirmed := force 595 596 if !force { 597 actionText := "This will delete your validator's historical actions database stored in your data directory. " + 598 "This may lead to potential slashing - do you want to proceed? (Y/N)" 599 deniedText := "The historical actions database will not be deleted. No changes have been made." 600 clearDBConfirmed, err = cmd.ConfirmAction(actionText, deniedText) 601 if err != nil { 602 return errors.Wrapf(err, "Could not clear DB in dir %s", dataDir) 603 } 604 } 605 606 if clearDBConfirmed { 607 valDB, err := kv.NewKVStore(ctx, dataDir, &kv.Config{}) 608 if err != nil { 609 return errors.Wrapf(err, "Could not create DB in dir %s", dataDir) 610 } 611 if err := valDB.Close(); err != nil { 612 return errors.Wrapf(err, "could not close DB in dir %s", dataDir) 613 } 614 615 log.Warning("Removing database") 616 if err := valDB.ClearDB(); err != nil { 617 return errors.Wrapf(err, "Could not clear DB in dir %s", dataDir) 618 } 619 } 620 621 return nil 622 }