github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/bft/node/node.go (about) 1 package node 2 3 // Ignore pprof import for gosec, as profiling 4 // is enabled by the user by setting a profiling address 5 6 import ( 7 "fmt" 8 "log/slog" 9 "net" 10 "net/http" 11 "strings" 12 "sync" 13 "time" 14 15 "github.com/gnolang/gno/tm2/pkg/bft/appconn" 16 "github.com/gnolang/gno/tm2/pkg/bft/state/eventstore/file" 17 "github.com/rs/cors" 18 19 "github.com/gnolang/gno/tm2/pkg/amino" 20 abci "github.com/gnolang/gno/tm2/pkg/bft/abci/types" 21 bc "github.com/gnolang/gno/tm2/pkg/bft/blockchain" 22 cfg "github.com/gnolang/gno/tm2/pkg/bft/config" 23 cs "github.com/gnolang/gno/tm2/pkg/bft/consensus" 24 mempl "github.com/gnolang/gno/tm2/pkg/bft/mempool" 25 "github.com/gnolang/gno/tm2/pkg/bft/privval" 26 "github.com/gnolang/gno/tm2/pkg/bft/proxy" 27 rpccore "github.com/gnolang/gno/tm2/pkg/bft/rpc/core" 28 _ "github.com/gnolang/gno/tm2/pkg/bft/rpc/core/types" 29 rpcserver "github.com/gnolang/gno/tm2/pkg/bft/rpc/lib/server" 30 sm "github.com/gnolang/gno/tm2/pkg/bft/state" 31 "github.com/gnolang/gno/tm2/pkg/bft/state/eventstore" 32 "github.com/gnolang/gno/tm2/pkg/bft/state/eventstore/null" 33 "github.com/gnolang/gno/tm2/pkg/bft/store" 34 "github.com/gnolang/gno/tm2/pkg/bft/types" 35 tmtime "github.com/gnolang/gno/tm2/pkg/bft/types/time" 36 "github.com/gnolang/gno/tm2/pkg/bft/version" 37 "github.com/gnolang/gno/tm2/pkg/crypto" 38 dbm "github.com/gnolang/gno/tm2/pkg/db" 39 "github.com/gnolang/gno/tm2/pkg/errors" 40 "github.com/gnolang/gno/tm2/pkg/events" 41 "github.com/gnolang/gno/tm2/pkg/p2p" 42 "github.com/gnolang/gno/tm2/pkg/service" 43 verset "github.com/gnolang/gno/tm2/pkg/versionset" 44 ) 45 46 // ------------------------------------------------------------------------------ 47 48 // DBContext specifies config information for loading a new DB. 49 type DBContext struct { 50 ID string 51 Config *cfg.Config 52 } 53 54 // DBProvider takes a DBContext and returns an instantiated DB. 55 type DBProvider func(*DBContext) (dbm.DB, error) 56 57 // DefaultDBProvider returns a database using the db.Backend and DBDir 58 // specified in the ctx.Config. 59 func DefaultDBProvider(ctx *DBContext) (dbm.DB, error) { 60 dbType := dbm.BackendType(ctx.Config.DBBackend) 61 return dbm.NewDB(ctx.ID, dbType, ctx.Config.DBDir()) 62 } 63 64 // GenesisDocProvider returns a GenesisDoc. 65 // It allows the GenesisDoc to be pulled from sources other than the 66 // filesystem, for instance from a distributed key-value store cluster. 67 type GenesisDocProvider func() (*types.GenesisDoc, error) 68 69 // DefaultGenesisDocProviderFunc returns a GenesisDocProvider that loads 70 // the GenesisDoc from the genesis path on the filesystem. 71 func DefaultGenesisDocProviderFunc(genesisFile string) GenesisDocProvider { 72 return func() (*types.GenesisDoc, error) { 73 return types.GenesisDocFromFile(genesisFile) 74 } 75 } 76 77 // NodeProvider takes a config and a logger and returns a ready to go Node. 78 type NodeProvider func(*cfg.Config, *slog.Logger) (*Node, error) 79 80 // DefaultNewNode returns a Tendermint node with default settings for the 81 // PrivValidator, ClientCreator, GenesisDoc, and DBProvider. 82 // It implements NodeProvider. 83 func DefaultNewNode(config *cfg.Config, genesisFile string, logger *slog.Logger) (*Node, error) { 84 // Generate node PrivKey 85 nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile()) 86 if err != nil { 87 return nil, err 88 } 89 90 // Get privValKeys. 91 newPrivValKey := config.PrivValidatorKeyFile() 92 newPrivValState := config.PrivValidatorStateFile() 93 94 // Get app client creator. 95 appClientCreator := proxy.DefaultClientCreator( 96 config.LocalApp, 97 config.ProxyApp, 98 config.ABCI, 99 config.DBDir(), 100 ) 101 102 return NewNode(config, 103 privval.LoadOrGenFilePV(newPrivValKey, newPrivValState), 104 nodeKey, 105 appClientCreator, 106 DefaultGenesisDocProviderFunc(genesisFile), 107 DefaultDBProvider, 108 logger, 109 ) 110 } 111 112 // Option sets a parameter for the node. 113 type Option func(*Node) 114 115 // CustomReactors allows you to add custom reactors (name -> p2p.Reactor) to 116 // the node's Switch. 117 // 118 // WARNING: using any name from the below list of the existing reactors will 119 // result in replacing it with the custom one. 120 // 121 // - MEMPOOL 122 // - BLOCKCHAIN 123 // - CONSENSUS 124 // - EVIDENCE 125 // - PEX 126 func CustomReactors(reactors map[string]p2p.Reactor) Option { 127 return func(n *Node) { 128 for name, reactor := range reactors { 129 if existingReactor := n.sw.Reactor(name); existingReactor != nil { 130 n.sw.Logger.Info("Replacing existing reactor with a custom one", 131 "name", name, "existing", existingReactor, "custom", reactor) 132 n.sw.RemoveReactor(name, existingReactor) 133 } 134 n.sw.AddReactor(name, reactor) 135 } 136 } 137 } 138 139 // ------------------------------------------------------------------------------ 140 141 // Node is the highest level interface to a full Tendermint node. 142 // It includes all configuration information and running services. 143 type Node struct { 144 service.BaseService 145 146 // config 147 config *cfg.Config 148 genesisDoc *types.GenesisDoc // initial validator set 149 privValidator types.PrivValidator // local node's validator key 150 151 // network 152 transport *p2p.MultiplexTransport 153 sw *p2p.Switch // p2p connections 154 nodeInfo p2p.NodeInfo 155 nodeKey *p2p.NodeKey // our node privkey 156 isListening bool 157 158 // services 159 evsw events.EventSwitch 160 stateDB dbm.DB 161 blockStore *store.BlockStore // store the blockchain to disk 162 bcReactor p2p.Reactor // for fast-syncing 163 mempoolReactor *mempl.Reactor // for gossipping transactions 164 mempool mempl.Mempool 165 consensusState *cs.ConsensusState // latest consensus state 166 consensusReactor *cs.ConsensusReactor // for participating in the consensus 167 proxyApp appconn.AppConns // connection to the application 168 rpcListeners []net.Listener // rpc servers 169 txEventStore eventstore.TxEventStore 170 eventStoreService *eventstore.Service 171 firstBlockSignal <-chan struct{} 172 } 173 174 func initDBs(config *cfg.Config, dbProvider DBProvider) (blockStore *store.BlockStore, stateDB dbm.DB, err error) { 175 var blockStoreDB dbm.DB 176 blockStoreDB, err = dbProvider(&DBContext{"blockstore", config}) 177 if err != nil { 178 return 179 } 180 blockStore = store.NewBlockStore(blockStoreDB) 181 182 stateDB, err = dbProvider(&DBContext{"state", config}) 183 if err != nil { 184 return 185 } 186 187 return 188 } 189 190 func createAndStartProxyAppConns(clientCreator proxy.ClientCreator, logger *slog.Logger) (appconn.AppConns, error) { 191 proxyApp := appconn.NewAppConns(clientCreator) 192 proxyApp.SetLogger(logger.With("module", "proxy")) 193 if err := proxyApp.Start(); err != nil { 194 return nil, fmt.Errorf("error starting proxy app connections: %w", err) 195 } 196 return proxyApp, nil 197 } 198 199 func createAndStartEventStoreService( 200 cfg *cfg.Config, 201 evsw events.EventSwitch, 202 logger *slog.Logger, 203 ) (*eventstore.Service, eventstore.TxEventStore, error) { 204 var ( 205 err error 206 txEventStore eventstore.TxEventStore 207 ) 208 209 // Instantiate the event store based on the configuration 210 switch cfg.TxEventStore.EventStoreType { 211 case file.EventStoreType: 212 // Transaction events should be logged to files 213 txEventStore, err = file.NewTxEventStore(cfg.TxEventStore) 214 if err != nil { 215 return nil, nil, fmt.Errorf("unable to create file tx event store, %w", err) 216 } 217 default: 218 // Transaction event storing should be omitted 219 txEventStore = null.NewNullEventStore() 220 } 221 222 indexerService := eventstore.NewEventStoreService(txEventStore, evsw) 223 indexerService.SetLogger(logger.With("module", "eventstore")) 224 if err := indexerService.Start(); err != nil { 225 return nil, nil, err 226 } 227 228 return indexerService, txEventStore, nil 229 } 230 231 func doHandshake(stateDB dbm.DB, state sm.State, blockStore sm.BlockStore, 232 genDoc *types.GenesisDoc, evsw events.EventSwitch, proxyApp appconn.AppConns, consensusLogger *slog.Logger, 233 ) error { 234 handshaker := cs.NewHandshaker(stateDB, state, blockStore, genDoc) 235 handshaker.SetLogger(consensusLogger) 236 handshaker.SetEventSwitch(evsw) 237 if err := handshaker.Handshake(proxyApp); err != nil { 238 return fmt.Errorf("error during handshake: %w", err) 239 } 240 return nil 241 } 242 243 func logNodeStartupInfo(state sm.State, pubKey crypto.PubKey, logger, consensusLogger *slog.Logger) { 244 // Log the version info. 245 logger.Info("Version info", 246 "version", version.Version, 247 ) 248 249 addr := pubKey.Address() 250 // Log whether this node is a validator or an observer 251 if state.Validators.HasAddress(addr) { 252 consensusLogger.Info("This node is a validator", "addr", addr, "pubKey", pubKey) 253 } else { 254 consensusLogger.Info("This node is not a validator", "addr", addr, "pubKey", pubKey) 255 } 256 } 257 258 func onlyValidatorIsUs(state sm.State, privVal types.PrivValidator) bool { 259 if state.Validators.Size() > 1 { 260 return false 261 } 262 addr, _ := state.Validators.GetByIndex(0) 263 return privVal.GetPubKey().Address() == addr 264 } 265 266 func createMempoolAndMempoolReactor(config *cfg.Config, proxyApp appconn.AppConns, 267 state sm.State, logger *slog.Logger, 268 ) (*mempl.Reactor, *mempl.CListMempool) { 269 mempool := mempl.NewCListMempool( 270 config.Mempool, 271 proxyApp.Mempool(), 272 state.LastBlockHeight, 273 state.ConsensusParams.Block.MaxTxBytes, 274 mempl.WithPreCheck(sm.TxPreCheck(state)), 275 ) 276 mempoolLogger := logger.With("module", "mempool") 277 mempoolReactor := mempl.NewReactor(config.Mempool, mempool) 278 mempoolReactor.SetLogger(mempoolLogger) 279 280 if config.Consensus.WaitForTxs() { 281 mempool.EnableTxsAvailable() 282 } 283 return mempoolReactor, mempool 284 } 285 286 func createBlockchainReactor(config *cfg.Config, 287 state sm.State, 288 blockExec *sm.BlockExecutor, 289 blockStore *store.BlockStore, 290 fastSync bool, 291 logger *slog.Logger, 292 ) (bcReactor p2p.Reactor, err error) { 293 bcReactor = bc.NewBlockchainReactor(state.Copy(), blockExec, blockStore, fastSync) 294 295 bcReactor.SetLogger(logger.With("module", "blockchain")) 296 return bcReactor, nil 297 } 298 299 func createConsensusReactor(config *cfg.Config, 300 state sm.State, 301 blockExec *sm.BlockExecutor, 302 blockStore sm.BlockStore, 303 mempool *mempl.CListMempool, 304 privValidator types.PrivValidator, 305 fastSync bool, 306 evsw events.EventSwitch, 307 consensusLogger *slog.Logger, 308 ) (*cs.ConsensusReactor, *cs.ConsensusState) { 309 consensusState := cs.NewConsensusState( 310 config.Consensus, 311 state.Copy(), 312 blockExec, 313 blockStore, 314 mempool, 315 ) 316 consensusState.SetLogger(consensusLogger) 317 if privValidator != nil { 318 consensusState.SetPrivValidator(privValidator) 319 } 320 consensusReactor := cs.NewConsensusReactor(consensusState, fastSync) 321 consensusReactor.SetLogger(consensusLogger) 322 consensusReactor.SetEventSwitch(evsw) 323 // services which will be publishing and/or subscribing for messages (events) 324 // consensusReactor will set it on consensusState and blockExecutor 325 return consensusReactor, consensusState 326 } 327 328 func createTransport(config *cfg.Config, nodeInfo p2p.NodeInfo, nodeKey *p2p.NodeKey, proxyApp appconn.AppConns) (*p2p.MultiplexTransport, []p2p.PeerFilterFunc) { 329 var ( 330 mConnConfig = p2p.MConnConfig(config.P2P) 331 transport = p2p.NewMultiplexTransport(nodeInfo, *nodeKey, mConnConfig) 332 connFilters = []p2p.ConnFilterFunc{} 333 peerFilters = []p2p.PeerFilterFunc{} 334 ) 335 336 if !config.P2P.AllowDuplicateIP { 337 connFilters = append(connFilters, p2p.ConnDuplicateIPFilter()) 338 } 339 340 // Filter peers by addr or pubkey with an ABCI query. 341 // If the query return code is OK, add peer. 342 if config.FilterPeers { 343 connFilters = append( 344 connFilters, 345 // ABCI query for address filtering. 346 func(_ p2p.ConnSet, c net.Conn, _ []net.IP) error { 347 res, err := proxyApp.Query().QuerySync(abci.RequestQuery{ 348 Path: fmt.Sprintf("/p2p/filter/addr/%s", c.RemoteAddr().String()), 349 }) 350 if err != nil { 351 return err 352 } 353 if res.IsErr() { 354 return fmt.Errorf("error querying abci app: %v", res) 355 } 356 357 return nil 358 }, 359 ) 360 361 peerFilters = append( 362 peerFilters, 363 // ABCI query for ID filtering. 364 func(_ p2p.IPeerSet, p p2p.Peer) error { 365 res, err := proxyApp.Query().QuerySync(abci.RequestQuery{ 366 Path: fmt.Sprintf("/p2p/filter/id/%s", p.ID()), 367 }) 368 if err != nil { 369 return err 370 } 371 if res.IsErr() { 372 return fmt.Errorf("error querying abci app: %v", res) 373 } 374 375 return nil 376 }, 377 ) 378 } 379 380 p2p.MultiplexTransportConnFilters(connFilters...)(transport) 381 return transport, peerFilters 382 } 383 384 func createSwitch(config *cfg.Config, 385 transport *p2p.MultiplexTransport, 386 peerFilters []p2p.PeerFilterFunc, 387 mempoolReactor *mempl.Reactor, 388 bcReactor p2p.Reactor, 389 consensusReactor *cs.ConsensusReactor, 390 nodeInfo p2p.NodeInfo, 391 nodeKey *p2p.NodeKey, 392 p2pLogger *slog.Logger, 393 ) *p2p.Switch { 394 sw := p2p.NewSwitch( 395 config.P2P, 396 transport, 397 p2p.SwitchPeerFilters(peerFilters...), 398 ) 399 sw.SetLogger(p2pLogger) 400 sw.AddReactor("MEMPOOL", mempoolReactor) 401 sw.AddReactor("BLOCKCHAIN", bcReactor) 402 sw.AddReactor("CONSENSUS", consensusReactor) 403 404 sw.SetNodeInfo(nodeInfo) 405 sw.SetNodeKey(nodeKey) 406 407 p2pLogger.Info("P2P Node ID", "ID", nodeKey.ID(), "file", config.NodeKeyFile()) 408 return sw 409 } 410 411 // NewNode returns a new, ready to go, Tendermint Node. 412 func NewNode(config *cfg.Config, 413 privValidator types.PrivValidator, 414 nodeKey *p2p.NodeKey, 415 clientCreator appconn.ClientCreator, 416 genesisDocProvider GenesisDocProvider, 417 dbProvider DBProvider, 418 logger *slog.Logger, 419 options ...Option, 420 ) (*Node, error) { 421 blockStore, stateDB, err := initDBs(config, dbProvider) 422 if err != nil { 423 return nil, err 424 } 425 426 state, genDoc, err := LoadStateFromDBOrGenesisDocProvider(stateDB, genesisDocProvider) 427 if err != nil { 428 return nil, err 429 } 430 431 // Create the proxyApp and establish connections to the ABCI app (consensus, mempool, query). 432 proxyApp, err := createAndStartProxyAppConns(clientCreator, logger) 433 if err != nil { 434 return nil, err 435 } 436 437 // EventSwitch and EventStoreService must be started before the handshake because 438 // we might need to store the txs of the replayed block as this might not have happened 439 // when the node stopped last time (i.e. the node stopped after it saved the block 440 // but before it indexed the txs, or, endblocker panicked) 441 evsw := events.NewEventSwitch() 442 443 // Signal readiness when receiving the first block. 444 const readinessListenerID = "first_block_listener" 445 446 cFirstBlock := make(chan struct{}) 447 var once sync.Once 448 evsw.AddListener(readinessListenerID, func(ev events.Event) { 449 if _, ok := ev.(types.EventNewBlock); ok { 450 once.Do(func() { 451 close(cFirstBlock) 452 evsw.RemoveListener(readinessListenerID) 453 }) 454 } 455 }) 456 457 // Transaction event storing 458 eventStoreService, txEventStore, err := createAndStartEventStoreService(config, evsw, logger) 459 if err != nil { 460 return nil, err 461 } 462 463 // Create the handshaker, which calls RequestInfo, sets the AppVersion on the state, 464 // and replays any blocks as necessary to sync tendermint with the app. 465 consensusLogger := logger.With("module", "consensus") 466 if err := doHandshake(stateDB, state, blockStore, genDoc, evsw, proxyApp, consensusLogger); err != nil { 467 return nil, err 468 } 469 470 // Reload the state. It will have the Version.Consensus.App set by the 471 // Handshake, and may have other modifications as well (ie. depending on 472 // what happened during block replay). 473 state = sm.LoadState(stateDB) 474 475 // If an address is provided, listen on the socket for a connection from an 476 // external signing process. 477 if config.PrivValidatorListenAddr != "" { 478 // FIXME: we should start services inside OnStart 479 privValidator, err = createAndStartPrivValidatorSocketClient(config.PrivValidatorListenAddr, logger) 480 if err != nil { 481 return nil, errors.Wrap(err, "error with private validator socket client") 482 } 483 } 484 485 pubKey := privValidator.GetPubKey() 486 if pubKey == nil { 487 // TODO: GetPubKey should return errors - https://github.com/gnolang/gno/tm2/pkg/bft/issues/3602 488 return nil, errors.New("could not retrieve public key from private validator") 489 } 490 491 logNodeStartupInfo(state, pubKey, logger, consensusLogger) 492 493 // Decide whether to fast-sync or not 494 // We don't fast-sync when the only validator is us. 495 fastSync := config.FastSyncMode && !onlyValidatorIsUs(state, privValidator) 496 497 // Make MempoolReactor 498 mempoolReactor, mempool := createMempoolAndMempoolReactor(config, proxyApp, state, logger) 499 500 // make block executor for consensus and blockchain reactors to execute blocks 501 blockExec := sm.NewBlockExecutor( 502 stateDB, 503 logger.With("module", "state"), 504 proxyApp.Consensus(), 505 mempool, 506 ) 507 508 // Make BlockchainReactor 509 bcReactor, err := createBlockchainReactor(config, state, blockExec, blockStore, fastSync, logger) 510 if err != nil { 511 return nil, errors.Wrap(err, "could not create blockchain reactor") 512 } 513 514 // Make ConsensusReactor 515 consensusReactor, consensusState := createConsensusReactor( 516 config, state, blockExec, blockStore, mempool, 517 privValidator, fastSync, evsw, consensusLogger, 518 ) 519 520 nodeInfo, err := makeNodeInfo(config, nodeKey, txEventStore, genDoc, state) 521 if err != nil { 522 return nil, errors.Wrap(err, "error making NodeInfo") 523 } 524 525 // Setup Transport. 526 transport, peerFilters := createTransport(config, nodeInfo, nodeKey, proxyApp) 527 528 // Setup Switch. 529 p2pLogger := logger.With("module", "p2p") 530 sw := createSwitch( 531 config, transport, peerFilters, mempoolReactor, bcReactor, 532 consensusReactor, nodeInfo, nodeKey, p2pLogger, 533 ) 534 535 err = sw.AddPersistentPeers(splitAndTrimEmpty(config.P2P.PersistentPeers, ",", " ")) 536 if err != nil { 537 return nil, errors.Wrap(err, "could not add peers from persistent_peers field") 538 } 539 540 if config.ProfListenAddress != "" { 541 server := &http.Server{ 542 Addr: config.ProfListenAddress, 543 ReadHeaderTimeout: 60 * time.Second, 544 } 545 546 go func() { 547 logger.Error("Profile server", "err", server.ListenAndServe()) 548 }() 549 } 550 551 node := &Node{ 552 config: config, 553 genesisDoc: genDoc, 554 privValidator: privValidator, 555 556 transport: transport, 557 sw: sw, 558 nodeInfo: nodeInfo, 559 nodeKey: nodeKey, 560 561 evsw: evsw, 562 stateDB: stateDB, 563 blockStore: blockStore, 564 bcReactor: bcReactor, 565 mempoolReactor: mempoolReactor, 566 mempool: mempool, 567 consensusState: consensusState, 568 consensusReactor: consensusReactor, 569 proxyApp: proxyApp, 570 txEventStore: txEventStore, 571 eventStoreService: eventStoreService, 572 firstBlockSignal: cFirstBlock, 573 } 574 node.BaseService = *service.NewBaseService(logger, "Node", node) 575 576 for _, option := range options { 577 option(node) 578 } 579 580 return node, nil 581 } 582 583 // OnStart starts the Node. It implements service.Service. 584 func (n *Node) OnStart() error { 585 now := tmtime.Now() 586 genTime := n.genesisDoc.GenesisTime 587 if genTime.After(now) { 588 n.Logger.Info("Genesis time is in the future. Sleeping until then...", "genTime", genTime) 589 time.Sleep(genTime.Sub(now)) 590 } 591 592 // Set up the GLOBAL variables in rpc/core which refer to this node. 593 // This is done separately from startRPC(), as the values in rpc/core are used, 594 // for instance, to set up Local clients (rpc/client) which work without 595 // a network connection. 596 n.configureRPC() 597 if n.config.RPC.Unsafe { 598 rpccore.AddUnsafeRoutes() 599 } 600 rpccore.Start() 601 602 // Start the RPC server before the P2P server 603 // so we can eg. receive txs for the first block 604 if n.config.RPC.ListenAddress != "" { 605 listeners, err := n.startRPC() 606 if err != nil { 607 return err 608 } 609 n.rpcListeners = listeners 610 } 611 612 // Start the transport. 613 addr, err := p2p.NewNetAddressFromString(p2p.NetAddressString(n.nodeKey.ID(), n.config.P2P.ListenAddress)) 614 if err != nil { 615 return err 616 } 617 if err := n.transport.Listen(*addr); err != nil { 618 return err 619 } 620 if addr.Port == 0 { 621 // if the port we have from config.P2p.ListenAdress is 0, 622 // it means the port was selected when doing net.Listen (using autoselect on the kernel). 623 // fix the config variable using the correct address 624 na := n.transport.NetAddress() 625 n.config.P2P.ListenAddress = na.DialString() 626 } 627 628 n.isListening = true 629 630 if n.config.Mempool.WalEnabled() { 631 n.mempool.InitWAL() // no need to have the mempool wal during tests 632 } 633 634 // Start the switch (the P2P server). 635 err = n.sw.Start() 636 if err != nil { 637 return err 638 } 639 640 // Always connect to persistent peers 641 err = n.sw.DialPeersAsync(splitAndTrimEmpty(n.config.P2P.PersistentPeers, ",", " ")) 642 if err != nil { 643 return errors.Wrap(err, "could not dial peers from persistent_peers field") 644 } 645 646 return nil 647 } 648 649 // OnStop stops the Node. It implements service.Service. 650 func (n *Node) OnStop() { 651 n.BaseService.OnStop() 652 653 n.Logger.Info("Stopping Node") 654 655 // first stop the non-reactor services 656 n.evsw.Stop() 657 n.eventStoreService.Stop() 658 659 // now stop the reactors 660 n.sw.Stop() 661 662 // stop mempool WAL 663 if n.config.Mempool.WalEnabled() { 664 n.mempool.CloseWAL() 665 } 666 667 n.isListening = false 668 669 // finally stop the listeners / external services 670 for _, l := range n.rpcListeners { 671 n.Logger.Info("Closing rpc listener", "listener", l) 672 if err := l.Close(); err != nil { 673 n.Logger.Error("Error closing listener", "listener", l, "err", err) 674 } 675 } 676 677 if pvsc, ok := n.privValidator.(service.Service); ok { 678 pvsc.Stop() 679 } 680 } 681 682 // Ready signals that the node is ready by returning a blocking channel. This channel is closed when the node receives its first block. 683 func (n *Node) Ready() <-chan struct{} { 684 return n.firstBlockSignal 685 } 686 687 // configureRPC sets all variables in rpccore so they will serve 688 // rpc calls from this node 689 func (n *Node) configureRPC() { 690 rpccore.SetStateDB(n.stateDB) 691 rpccore.SetBlockStore(n.blockStore) 692 rpccore.SetConsensusState(n.consensusState) 693 rpccore.SetMempool(n.mempool) 694 rpccore.SetP2PPeers(n.sw) 695 rpccore.SetP2PTransport(n) 696 pubKey := n.privValidator.GetPubKey() 697 rpccore.SetPubKey(pubKey) 698 rpccore.SetGenesisDoc(n.genesisDoc) 699 rpccore.SetProxyAppQuery(n.proxyApp.Query()) 700 rpccore.SetGetFastSync(n.consensusReactor.FastSync) 701 rpccore.SetLogger(n.Logger.With("module", "rpc")) 702 rpccore.SetEventSwitch(n.evsw) 703 rpccore.SetConfig(*n.config.RPC) 704 } 705 706 func (n *Node) startRPC() ([]net.Listener, error) { 707 listenAddrs := splitAndTrimEmpty(n.config.RPC.ListenAddress, ",", " ") 708 709 config := rpcserver.DefaultConfig() 710 config.MaxBodyBytes = n.config.RPC.MaxBodyBytes 711 config.MaxHeaderBytes = n.config.RPC.MaxHeaderBytes 712 config.MaxOpenConnections = n.config.RPC.MaxOpenConnections 713 // If necessary adjust global WriteTimeout to ensure it's greater than 714 // TimeoutBroadcastTxCommit. 715 // See https://github.com/gnolang/gno/tm2/pkg/bft/issues/3435 716 if config.WriteTimeout <= n.config.RPC.TimeoutBroadcastTxCommit { 717 config.WriteTimeout = n.config.RPC.TimeoutBroadcastTxCommit + 1*time.Second 718 } 719 720 // we may expose the rpc over both a unix and tcp socket 721 var rebuildAddresses bool 722 listeners := make([]net.Listener, len(listenAddrs)) 723 for i, listenAddr := range listenAddrs { 724 mux := http.NewServeMux() 725 rpcLogger := n.Logger.With("module", "rpc-server") 726 wmLogger := rpcLogger.With("protocol", "websocket") 727 wm := rpcserver.NewWebsocketManager(rpccore.Routes, 728 rpcserver.OnDisconnect(func(remoteAddr string) { 729 // any cleanup... 730 // (we used to unsubscribe from all event subscriptions) 731 }), 732 rpcserver.ReadLimit(config.MaxBodyBytes), 733 ) 734 wm.SetLogger(wmLogger) 735 mux.HandleFunc("/websocket", wm.WebsocketHandler) 736 rpcserver.RegisterRPCFuncs(mux, rpccore.Routes, rpcLogger) 737 if strings.HasPrefix(listenAddr, "tcp://") && strings.HasSuffix(listenAddr, ":0") { 738 rebuildAddresses = true 739 } 740 listener, err := rpcserver.Listen( 741 listenAddr, 742 config, 743 ) 744 if err != nil { 745 return nil, err 746 } 747 748 var rootHandler http.Handler = mux 749 if n.config.RPC.IsCorsEnabled() { 750 corsMiddleware := cors.New(cors.Options{ 751 AllowedOrigins: n.config.RPC.CORSAllowedOrigins, 752 AllowedMethods: n.config.RPC.CORSAllowedMethods, 753 AllowedHeaders: n.config.RPC.CORSAllowedHeaders, 754 }) 755 rootHandler = corsMiddleware.Handler(mux) 756 } 757 if n.config.RPC.IsTLSEnabled() { 758 go rpcserver.StartHTTPAndTLSServer( 759 listener, 760 rootHandler, 761 n.config.RPC.CertFile(), 762 n.config.RPC.KeyFile(), 763 rpcLogger, 764 config, 765 ) 766 } else { 767 go rpcserver.StartHTTPServer( 768 listener, 769 rootHandler, 770 rpcLogger, 771 config, 772 ) 773 } 774 775 listeners[i] = listener 776 } 777 if rebuildAddresses { 778 n.config.RPC.ListenAddress = joinListenerAddresses(listeners) 779 } 780 781 return listeners, nil 782 } 783 784 func joinListenerAddresses(ll []net.Listener) string { 785 sl := make([]string, len(ll)) 786 for i, l := range ll { 787 sl[i] = l.Addr().Network() + "://" + l.Addr().String() 788 } 789 return strings.Join(sl, ",") 790 } 791 792 // Switch returns the Node's Switch. 793 func (n *Node) Switch() *p2p.Switch { 794 return n.sw 795 } 796 797 // EventSwitch returns the node's EventSwitch. 798 func (n *Node) EventSwitch() events.EventSwitch { 799 return n.evsw 800 } 801 802 // BlockStore returns the Node's BlockStore. 803 func (n *Node) BlockStore() *store.BlockStore { 804 return n.blockStore 805 } 806 807 // ConsensusState returns the Node's ConsensusState. 808 func (n *Node) ConsensusState() *cs.ConsensusState { 809 return n.consensusState 810 } 811 812 // ConsensusReactor returns the Node's ConsensusReactor. 813 func (n *Node) ConsensusReactor() *cs.ConsensusReactor { 814 return n.consensusReactor 815 } 816 817 // MempoolReactor returns the Node's mempool reactor. 818 func (n *Node) MempoolReactor() *mempl.Reactor { 819 return n.mempoolReactor 820 } 821 822 // Mempool returns the Node's mempool. 823 func (n *Node) Mempool() mempl.Mempool { 824 return n.mempool 825 } 826 827 // PrivValidator returns the Node's PrivValidator. 828 // XXX: for convenience only! 829 func (n *Node) PrivValidator() types.PrivValidator { 830 return n.privValidator 831 } 832 833 // GenesisDoc returns the Node's GenesisDoc. 834 func (n *Node) GenesisDoc() *types.GenesisDoc { 835 return n.genesisDoc 836 } 837 838 // ProxyApp returns the Node's AppConns, representing its connections to the ABCI application. 839 func (n *Node) ProxyApp() appconn.AppConns { 840 return n.proxyApp 841 } 842 843 // Config returns the Node's config. 844 func (n *Node) Config() *cfg.Config { 845 return n.config 846 } 847 848 // ------------------------------------------------------------------------------ 849 850 func (n *Node) Listeners() []string { 851 return []string{ 852 fmt.Sprintf("Listener(@%v)", n.config.P2P.ExternalAddress), 853 } 854 } 855 856 func (n *Node) IsListening() bool { 857 return n.isListening 858 } 859 860 // NodeInfo returns the Node's Info from the Switch. 861 func (n *Node) NodeInfo() p2p.NodeInfo { 862 return n.nodeInfo 863 } 864 865 func makeNodeInfo( 866 config *cfg.Config, 867 nodeKey *p2p.NodeKey, 868 txEventStore eventstore.TxEventStore, 869 genDoc *types.GenesisDoc, 870 state sm.State, 871 ) (p2p.NodeInfo, error) { 872 txIndexerStatus := eventstore.StatusOff 873 if txEventStore.GetType() != null.EventStoreType { 874 txIndexerStatus = eventstore.StatusOn 875 } 876 877 bcChannel := bc.BlockchainChannel 878 vset := version.VersionSet 879 vset.Set(verset.VersionInfo{ 880 Name: "app", 881 Version: state.AppVersion, 882 }) 883 884 nodeInfo := p2p.NodeInfo{ 885 VersionSet: vset, 886 Network: genDoc.ChainID, 887 Version: version.Version, 888 Channels: []byte{ 889 bcChannel, 890 cs.StateChannel, cs.DataChannel, cs.VoteChannel, cs.VoteSetBitsChannel, 891 mempl.MempoolChannel, 892 }, 893 Moniker: config.Moniker, 894 Other: p2p.NodeInfoOther{ 895 TxIndex: txIndexerStatus, 896 RPCAddress: config.RPC.ListenAddress, 897 }, 898 } 899 900 lAddr := config.P2P.ExternalAddress 901 if lAddr == "" { 902 lAddr = config.P2P.ListenAddress 903 } 904 addr, err := p2p.NewNetAddressFromString(p2p.NetAddressString(nodeKey.ID(), lAddr)) 905 if err != nil { 906 return nodeInfo, errors.Wrap(err, "invalid (local) node net address") 907 } 908 nodeInfo.NetAddress = addr 909 910 err = nodeInfo.Validate() 911 return nodeInfo, err 912 } 913 914 // ------------------------------------------------------------------------------ 915 916 var genesisDocKey = []byte("genesisDoc") 917 918 // LoadStateFromDBOrGenesisDocProvider attempts to load the state from the 919 // database, or creates one using the given genesisDocProvider and persists the 920 // result to the database. On success this also returns the genesis doc loaded 921 // through the given provider. 922 func LoadStateFromDBOrGenesisDocProvider(stateDB dbm.DB, genesisDocProvider GenesisDocProvider) (sm.State, *types.GenesisDoc, error) { 923 // Get genesis doc 924 genDoc, err := loadGenesisDoc(stateDB) 925 if err != nil { 926 genDoc, err = genesisDocProvider() 927 if err != nil { 928 return sm.State{}, nil, err 929 } 930 // save genesis doc to prevent a certain class of user errors (e.g. when it 931 // was changed, accidentally or not). Also good for audit trail. 932 saveGenesisDoc(stateDB, genDoc) 933 } 934 state, err := sm.LoadStateFromDBOrGenesisDoc(stateDB, genDoc) 935 if err != nil { 936 return sm.State{}, nil, err 937 } 938 return state, genDoc, nil 939 } 940 941 // panics if failed to unmarshal bytes 942 func loadGenesisDoc(db dbm.DB) (*types.GenesisDoc, error) { 943 b := db.Get(genesisDocKey) 944 if len(b) == 0 { 945 return nil, errors.New("Genesis doc not found") 946 } 947 var genDoc *types.GenesisDoc 948 err := amino.UnmarshalJSON(b, &genDoc) 949 if err != nil { 950 panic(fmt.Sprintf("Failed to load genesis doc due to unmarshaling error: %v (bytes: %X)", err, b)) 951 } 952 return genDoc, nil 953 } 954 955 // panics if failed to marshal the given genesis document 956 func saveGenesisDoc(db dbm.DB, genDoc *types.GenesisDoc) { 957 b, err := amino.MarshalJSON(genDoc) 958 if err != nil { 959 panic(fmt.Sprintf("Failed to save genesis doc due to marshaling error: %v", err)) 960 } 961 db.SetSync(genesisDocKey, b) 962 } 963 964 func createAndStartPrivValidatorSocketClient( 965 listenAddr string, 966 logger *slog.Logger, 967 ) (types.PrivValidator, error) { 968 pve, err := privval.NewSignerListener(listenAddr, logger) 969 if err != nil { 970 return nil, errors.Wrap(err, "failed to start private validator") 971 } 972 973 pvsc, err := privval.NewSignerClient(pve) 974 if err != nil { 975 return nil, errors.Wrap(err, "failed to start private validator") 976 } 977 978 return pvsc, nil 979 } 980 981 // splitAndTrimEmpty slices s into all subslices separated by sep and returns a 982 // slice of the string s with all leading and trailing Unicode code points 983 // contained in cutset removed. If sep is empty, SplitAndTrim splits after each 984 // UTF-8 sequence. First part is equivalent to strings.SplitN with a count of 985 // -1. also filter out empty strings, only return non-empty strings. 986 func splitAndTrimEmpty(s, sep, cutset string) []string { 987 if s == "" { 988 return []string{} 989 } 990 991 spl := strings.Split(s, sep) 992 nonEmptyStrings := make([]string, 0, len(spl)) 993 for i := 0; i < len(spl); i++ { 994 element := strings.Trim(spl[i], cutset) 995 if element != "" { 996 nonEmptyStrings = append(nonEmptyStrings, element) 997 } 998 } 999 return nonEmptyStrings 1000 }