github.com/shyftnetwork/go-empyrean@v1.8.3-0.20191127201940-fbfca9338f04/node/node.go (about) 1 // Copyright 2015 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package node 18 19 import ( 20 "context" 21 "errors" 22 "fmt" 23 24 "github.com/ShyftNetwork/go-empyrean" 25 26 "github.com/ShyftNetwork/go-empyrean/generated_bindings" 27 28 "github.com/ShyftNetwork/go-empyrean/accounts/abi/bind" 29 30 "github.com/ShyftNetwork/go-empyrean/common" 31 "github.com/ShyftNetwork/go-empyrean/crypto" 32 "github.com/ShyftNetwork/go-empyrean/ethclient" 33 "github.com/ShyftNetwork/go-empyrean/whisper/shhclient" 34 "github.com/ShyftNetwork/go-empyrean/whisper/whisperv6" 35 36 "net" 37 "os" 38 "path/filepath" 39 "reflect" 40 "strings" 41 "sync" 42 43 "github.com/ShyftNetwork/go-empyrean/accounts" 44 "github.com/ShyftNetwork/go-empyrean/common/hexutil" 45 "github.com/ShyftNetwork/go-empyrean/ethdb" 46 "github.com/ShyftNetwork/go-empyrean/event" 47 "github.com/ShyftNetwork/go-empyrean/internal/debug" 48 "github.com/ShyftNetwork/go-empyrean/log" 49 "github.com/ShyftNetwork/go-empyrean/p2p" 50 "github.com/ShyftNetwork/go-empyrean/rpc" 51 "github.com/prometheus/prometheus/util/flock" 52 ) 53 54 // Node is a container on which services can be registered. 55 type Node struct { 56 eventmux *event.TypeMux // Event multiplexer used between the services of a stack 57 config *Config 58 accman *accounts.Manager 59 60 ephemeralKeystore string // if non-empty, the key directory that will be removed by Stop 61 instanceDirLock flock.Releaser // prevents concurrent use of instance directory 62 63 serverConfig p2p.Config 64 server *p2p.Server // Currently running P2P networking layer 65 66 serviceFuncs []ServiceConstructor // Service constructors (in dependency order) 67 services map[reflect.Type]Service // Currently running services 68 69 rpcAPIs []rpc.API // List of APIs currently provided by the node 70 inprocHandler *rpc.Server // In-process RPC request handler to process the API requests 71 72 ipcEndpoint string // IPC endpoint to listen at (empty = IPC disabled) 73 ipcListener net.Listener // IPC RPC listener socket to serve API requests 74 ipcHandler *rpc.Server // IPC RPC request handler to process the API requests 75 76 httpEndpoint string // HTTP endpoint (interface + port) to listen at (empty = HTTP disabled) 77 httpWhitelist []string // HTTP RPC modules to allow through this endpoint 78 httpListener net.Listener // HTTP RPC listener socket to server API requests 79 httpHandler *rpc.Server // HTTP RPC request handler to process the API requests 80 81 wsEndpoint string // Websocket endpoint (interface + port) to listen at (empty = websocket disabled) 82 wsListener net.Listener // Websocket RPC listener socket to server API requests 83 wsHandler *rpc.Server // Websocket RPC request handler to process the API requests 84 85 stop chan struct{} // Channel to wait for termination notifications 86 lock sync.RWMutex 87 88 log log.Logger 89 } 90 91 // New creates a new P2P node, ready for protocol registration. 92 func New(conf *Config) (*Node, error) { 93 // Copy config and resolve the datadir so future changes to the current 94 // working directory don't affect the node. 95 confCopy := *conf 96 conf = &confCopy 97 if conf.DataDir != "" { 98 absdatadir, err := filepath.Abs(conf.DataDir) 99 if err != nil { 100 return nil, err 101 } 102 conf.DataDir = absdatadir 103 } 104 // Ensure that the instance name doesn't cause weird conflicts with 105 // other files in the data directory. 106 if strings.ContainsAny(conf.Name, `/\`) { 107 return nil, errors.New(`Config.Name must not contain '/' or '\'`) 108 } 109 if conf.Name == datadirDefaultKeyStore { 110 return nil, errors.New(`Config.Name cannot be "` + datadirDefaultKeyStore + `"`) 111 } 112 if strings.HasSuffix(conf.Name, ".ipc") { 113 return nil, errors.New(`Config.Name cannot end in ".ipc"`) 114 } 115 // Ensure that the AccountManager method works before the node has started. 116 // We rely on this in cmd/geth. 117 am, ephemeralKeystore, err := makeAccountManager(conf) 118 if err != nil { 119 return nil, err 120 } 121 if conf.Logger == nil { 122 conf.Logger = log.New() 123 } 124 // Note: any interaction with Config that would create/touch files 125 // in the data directory or instance directory is delayed until Start. 126 return &Node{ 127 accman: am, 128 ephemeralKeystore: ephemeralKeystore, 129 config: conf, 130 serviceFuncs: []ServiceConstructor{}, 131 ipcEndpoint: conf.IPCEndpoint(), 132 httpEndpoint: conf.HTTPEndpoint(), 133 wsEndpoint: conf.WSEndpoint(), 134 eventmux: new(event.TypeMux), 135 log: conf.Logger, 136 }, nil 137 } 138 139 // Register injects a new service into the node's stack. The service created by 140 // the passed constructor must be unique in its type with regard to sibling ones. 141 func (n *Node) Register(constructor ServiceConstructor) error { 142 n.lock.Lock() 143 defer n.lock.Unlock() 144 145 if n.server != nil { 146 return ErrNodeRunning 147 } 148 n.serviceFuncs = append(n.serviceFuncs, constructor) 149 return nil 150 } 151 152 // Start create a live P2P node and starts running it. 153 func (n *Node) Start() error { 154 n.lock.Lock() 155 defer n.lock.Unlock() 156 157 // Short circuit if the node's already running 158 if n.server != nil { 159 return ErrNodeRunning 160 } 161 if err := n.openDataDir(); err != nil { 162 return err 163 } 164 165 // Initialize the p2p server. This creates the node key and 166 // discovery databases. 167 n.serverConfig = n.config.P2P 168 n.serverConfig.PrivateKey = n.config.NodeKey() 169 n.serverConfig.Name = n.config.NodeName() 170 n.serverConfig.Logger = n.log 171 if n.serverConfig.StaticNodes == nil { 172 n.serverConfig.StaticNodes = n.config.StaticNodes() 173 } 174 if n.serverConfig.TrustedNodes == nil { 175 n.serverConfig.TrustedNodes = n.config.TrustedNodes() 176 } 177 if n.serverConfig.NodeDatabase == "" { 178 n.serverConfig.NodeDatabase = n.config.NodeDB() 179 } 180 running := &p2p.Server{Config: n.serverConfig} 181 n.log.Info("Starting peer-to-peer node", "instance", n.serverConfig.Name) 182 183 // Otherwise copy and specialize the P2P configuration 184 services := make(map[reflect.Type]Service) 185 for _, constructor := range n.serviceFuncs { 186 // Create a new context for the particular service 187 ctx := &ServiceContext{ 188 config: n.config, 189 services: make(map[reflect.Type]Service), 190 EventMux: n.eventmux, 191 AccountManager: n.accman, 192 } 193 for kind, s := range services { // copy needed for threaded access 194 ctx.services[kind] = s 195 } 196 // Construct and save the service 197 service, err := constructor(ctx) 198 if err != nil { 199 fmt.Println("ERROR", err) 200 return err 201 } 202 kind := reflect.TypeOf(service) 203 if _, exists := services[kind]; exists { 204 return &DuplicateServiceError{Kind: kind} 205 } 206 services[kind] = service 207 } 208 // Gather the protocols and start the freshly assembled P2P server 209 for _, service := range services { 210 running.Protocols = append(running.Protocols, service.Protocols()...) 211 } 212 if err := running.Start(); err != nil { 213 return convertFileLockError(err) 214 } 215 // Start each of the services 216 started := []reflect.Type{} 217 for kind, service := range services { 218 if err := service.Start(running); err != nil { 219 for _, kind := range started { 220 services[kind].Stop() 221 } 222 running.Stop() 223 224 return err 225 } 226 started = append(started, kind) 227 // Mark the service started for potential cleanup 228 // Start the next service, stopping all previous upon failure 229 } 230 // Lastly start the configured RPC interfaces 231 if err := n.startRPC(services); err != nil { 232 for _, service := range services { 233 service.Stop() 234 } 235 running.Stop() 236 return err 237 } 238 // Finish initializing the startup 239 n.services = services 240 n.server = running 241 n.stop = make(chan struct{}) 242 // if shhApi enabled, register whisper Subscription 243 if n.shhApi() { 244 // Check n.config.WhisperSignersContract contains contract address 245 // If not available but WhisperKeys flags available continue make subscription 246 // If contract doesnt exist but we have n.config.WhisperKeys - Proceed set up subscription 247 // TODO: Remove whisperkey flags once WhisperSignersContract is available// TODO: Remove whisperkey flags once WhisperSignersContract is available 248 signersContractAddress := n.config.WhisperSignersContract != "" 249 whisperPublicKeys := len(n.config.WhisperKeys) > 0 250 if signersContractAddress || whisperPublicKeys { 251 ctx := context.Background() 252 // Set Up a Topic Listener 253 wsConnect := "ws://" + n.config.WSEndpoint() 254 shhCli, err := shhclient.Dial(wsConnect) 255 if err != nil { 256 log.Error("Failed to Connect to shh client: ", err) 257 panic(err) 258 } 259 generatedSymKey, err := shhCli.GenerateSymmetricKeyFromPassword(ctx, "foobar") 260 symKey, _ := shhCli.GetSymmetricKey(ctx, generatedSymKey) 261 symKeyId, _ := shhCli.AddSymmetricKey(ctx, symKey) 262 log.Info("Symmetric Key Id: ", "symKeyId", symKeyId) 263 264 // topicString is "rollback".toHex() 265 topicString := "0x524f4c4c" 266 topicBytes, _ := hexutil.Decode(topicString) 267 topic := whisperv6.BytesToTopic(topicBytes) 268 topArr := []whisperv6.TopicType{topic} 269 criteria := &whisperv6.Criteria{SymKeyID: symKeyId, Topics: topArr} 270 messages := make(chan *whisperv6.Message) 271 sub, err := shhCli.SubscribeMessages(ctx, *criteria, messages) 272 if err != nil { 273 log.Error("subscription error:", err) 274 } 275 log.Info("listening for messages", "topicString", topicString) 276 go n.whisperMessageReceiver(sub, messages) 277 } 278 } 279 return nil 280 } 281 282 func (n *Node) dialIPC() *ethclient.Client { 283 conn, err := ethclient.Dial("./shyftData/geth.ipc") 284 if err != nil { 285 log.Info("Failed to connect to the Ethereum client: %v", err) 286 } 287 return conn 288 } 289 290 func (n *Node) CheckWhisperPublicFlagKeys(addr common.Address) bool { 291 if pos(n.config.WhisperKeys, addr) == -1 { 292 return false 293 } else { 294 return true 295 } 296 } 297 298 func (n *Node) CheckContractAdminStatus(addr common.Address, conn bind.ContractCaller) bool { 299 signerContract, err := shyft_contracts.NewValidSignersCaller(common.HexToAddress(n.config.WhisperSignersContract), conn) 300 if err != nil { 301 log.Info("Signer contract not initialized") 302 return false 303 } 304 //signerContract, err := shyft_contracts.NewSignerCaller(common.HexToAddress(n.config.WhisperSignersContract), conn) 305 session := ­ft_contracts.ValidSignersCallerSession{ 306 Contract: signerContract, 307 CallOpts: bind.CallOpts{ 308 Pending: true, 309 }, 310 } 311 result, err := session.IsValidSigner(addr) 312 if err != nil { 313 log.Info("No response from contract %+v \n", err) 314 } 315 return result 316 } 317 318 func (n *Node) getKeysFromContract() []string { 319 // Code to read contract address 320 // Connect to geth.ipc and call function to return string array of public keys 321 return n.config.WhisperKeys 322 } 323 324 func (n *Node) shhApi() bool { 325 for _, api := range n.rpcAPIs { 326 if api.Namespace == "shh" { 327 return true 328 } 329 } 330 return false 331 } 332 333 func parseMessage(msg string) (string, string) { 334 payload := strings.Split(msg, "--") 335 return payload[0], payload[1] 336 } 337 338 func pos(slice []string, address common.Address) int { 339 for p, v := range slice { 340 if v == address.Hex() { 341 return p 342 } 343 } 344 return -1 345 } 346 347 // Copied from signer/core/api.go to avoid cyclic dependency in testing 348 func SignHash(data []byte) ([]byte, string) { 349 msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len(data), data) 350 return crypto.Keccak256([]byte(msg)), msg 351 } 352 353 func (n *Node) whisperMessageReceiver(sub ethereum.Subscription, messages chan *whisperv6.Message) { 354 //conn := n.dialIPC() 355 fmt.Println("Started Message Receiver") 356 for { 357 select { 358 case err := <-sub.Err(): 359 log.Error("subscription error:", err) 360 case message := <-messages: 361 // get eth public keys from message 362 blockHash, sig := parseMessage(string(message.Payload[:])) 363 sigByteArray, err := hexutil.Decode(sig) 364 if err != nil { 365 log.Error("hexutil.Decode err", "err", err) 366 break 367 } 368 var sighex = hexutil.Bytes(sigByteArray) 369 sighex[64] -= 27 370 msgHash, _ := SignHash(hexutil.Bytes(blockHash)) 371 pubKey, err := crypto.SigToPub(hexutil.Bytes(msgHash), sighex) 372 if err != nil { 373 log.Error("SigToPub err", "err", err) 374 } else { 375 recoveredAddr := crypto.PubkeyToAddress(*pubKey) 376 //authMethodContract := n.smartContractAvailable(n.config.WhisperSignersContract, conn) 377 var authorized bool 378 if n.config.WhisperSignersContract != "" { 379 fmt.Println("Starting smart contract check") 380 conn := n.dialIPC() 381 authorized = n.CheckContractAdminStatus(recoveredAddr, conn) 382 } else { 383 fmt.Println("Starting whisper keys") 384 if len(n.config.WhisperKeys) > 0 { 385 authorized = n.CheckWhisperPublicFlagKeys(recoveredAddr) 386 } 387 } 388 389 if authorized { 390 n.config.WhisperChannel <- blockHash 391 } 392 } 393 } 394 } 395 } 396 397 func (n *Node) openDataDir() error { 398 if n.config.DataDir == "" { 399 return nil // ephemeral 400 } 401 402 instdir := filepath.Join(n.config.DataDir, n.config.name()) 403 if err := os.MkdirAll(instdir, 0700); err != nil { 404 return err 405 } 406 // Lock the instance directory to prevent concurrent use by another instance as well as 407 // accidental use of the instance directory as a database. 408 release, _, err := flock.New(filepath.Join(instdir, "LOCK")) 409 if err != nil { 410 return convertFileLockError(err) 411 } 412 n.instanceDirLock = release 413 return nil 414 } 415 416 // startRPC is a helper method to start all the various RPC endpoint during node 417 // startup. It's not meant to be called at any time afterwards as it makes certain 418 // assumptions about the state of the node. 419 func (n *Node) startRPC(services map[reflect.Type]Service) error { 420 // Gather all the possible APIs to surface 421 apis := n.apis() 422 for _, service := range services { 423 apis = append(apis, service.APIs()...) 424 } 425 // Start the various API endpoints, terminating all in case of errors 426 if err := n.startInProc(apis); err != nil { 427 return err 428 } 429 if err := n.startIPC(apis); err != nil { 430 n.stopInProc() 431 return err 432 } 433 if err := n.startHTTP(n.httpEndpoint, apis, n.config.HTTPModules, n.config.HTTPCors, n.config.HTTPVirtualHosts, n.config.HTTPTimeouts); err != nil { 434 n.stopIPC() 435 n.stopInProc() 436 return err 437 } 438 if err := n.startWS(n.wsEndpoint, apis, n.config.WSModules, n.config.WSOrigins, n.config.WSExposeAll); err != nil { 439 n.stopHTTP() 440 n.stopIPC() 441 n.stopInProc() 442 return err 443 } 444 // All API endpoints started successfully 445 n.rpcAPIs = apis 446 return nil 447 } 448 449 // startInProc initializes an in-process RPC endpoint. 450 func (n *Node) startInProc(apis []rpc.API) error { 451 // Register all the APIs exposed by the services 452 handler := rpc.NewServer() 453 for _, api := range apis { 454 if err := handler.RegisterName(api.Namespace, api.Service); err != nil { 455 return err 456 } 457 n.log.Debug("InProc registered", "namespace", api.Namespace) 458 } 459 n.inprocHandler = handler 460 return nil 461 } 462 463 // stopInProc terminates the in-process RPC endpoint. 464 func (n *Node) stopInProc() { 465 if n.inprocHandler != nil { 466 n.inprocHandler.Stop() 467 n.inprocHandler = nil 468 } 469 } 470 471 // startIPC initializes and starts the IPC RPC endpoint. 472 func (n *Node) startIPC(apis []rpc.API) error { 473 if n.ipcEndpoint == "" { 474 return nil // IPC disabled. 475 } 476 listener, handler, err := rpc.StartIPCEndpoint(n.ipcEndpoint, apis) 477 if err != nil { 478 return err 479 } 480 n.ipcListener = listener 481 n.ipcHandler = handler 482 n.log.Info("IPC endpoint opened", "url", n.ipcEndpoint) 483 return nil 484 } 485 486 // stopIPC terminates the IPC RPC endpoint. 487 func (n *Node) stopIPC() { 488 if n.ipcListener != nil { 489 n.ipcListener.Close() 490 n.ipcListener = nil 491 492 n.log.Info("IPC endpoint closed", "url", n.ipcEndpoint) 493 } 494 if n.ipcHandler != nil { 495 n.ipcHandler.Stop() 496 n.ipcHandler = nil 497 } 498 } 499 500 // startHTTP initializes and starts the HTTP RPC endpoint. 501 func (n *Node) startHTTP(endpoint string, apis []rpc.API, modules []string, cors []string, vhosts []string, timeouts rpc.HTTPTimeouts) error { 502 // Short circuit if the HTTP endpoint isn't being exposed 503 if endpoint == "" { 504 return nil 505 } 506 listener, handler, err := rpc.StartHTTPEndpoint(endpoint, apis, modules, cors, vhosts, timeouts) 507 if err != nil { 508 return err 509 } 510 n.log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%s", endpoint), "cors", strings.Join(cors, ","), "vhosts", strings.Join(vhosts, ",")) 511 // All listeners booted successfully 512 n.httpEndpoint = endpoint 513 n.httpListener = listener 514 n.httpHandler = handler 515 516 return nil 517 } 518 519 // stopHTTP terminates the HTTP RPC endpoint. 520 func (n *Node) stopHTTP() { 521 if n.httpListener != nil { 522 n.httpListener.Close() 523 n.httpListener = nil 524 525 n.log.Info("HTTP endpoint closed", "url", fmt.Sprintf("http://%s", n.httpEndpoint)) 526 } 527 if n.httpHandler != nil { 528 n.httpHandler.Stop() 529 n.httpHandler = nil 530 } 531 } 532 533 // startWS initializes and starts the websocket RPC endpoint. 534 func (n *Node) startWS(endpoint string, apis []rpc.API, modules []string, wsOrigins []string, exposeAll bool) error { 535 // Short circuit if the WS endpoint isn't being exposed 536 if endpoint == "" { 537 return nil 538 } 539 listener, handler, err := rpc.StartWSEndpoint(endpoint, apis, modules, wsOrigins, exposeAll) 540 if err != nil { 541 return err 542 } 543 n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%s", listener.Addr())) 544 // All listeners booted successfully 545 n.wsEndpoint = endpoint 546 n.wsListener = listener 547 n.wsHandler = handler 548 549 return nil 550 } 551 552 // stopWS terminates the websocket RPC endpoint. 553 func (n *Node) stopWS() { 554 if n.wsListener != nil { 555 n.wsListener.Close() 556 n.wsListener = nil 557 558 n.log.Info("WebSocket endpoint closed", "url", fmt.Sprintf("ws://%s", n.wsEndpoint)) 559 } 560 if n.wsHandler != nil { 561 n.wsHandler.Stop() 562 n.wsHandler = nil 563 } 564 } 565 566 // Stop terminates a running node along with all it's services. In the node was 567 // not started, an error is returned. 568 func (n *Node) Stop() error { 569 n.lock.Lock() 570 defer n.lock.Unlock() 571 572 // Short circuit if the node's not running 573 if n.server == nil { 574 return ErrNodeStopped 575 } 576 577 // Terminate the API, services and the p2p server. 578 n.stopWS() 579 n.stopHTTP() 580 n.stopIPC() 581 n.rpcAPIs = nil 582 failure := &StopError{ 583 Services: make(map[reflect.Type]error), 584 } 585 for kind, service := range n.services { 586 if err := service.Stop(); err != nil { 587 failure.Services[kind] = err 588 } 589 } 590 n.server.Stop() 591 n.services = nil 592 n.server = nil 593 594 // Release instance directory lock. 595 if n.instanceDirLock != nil { 596 if err := n.instanceDirLock.Release(); err != nil { 597 n.log.Error("Can't release datadir lock", "err", err) 598 } 599 n.instanceDirLock = nil 600 } 601 602 // unblock n.Wait 603 close(n.stop) 604 605 // Remove the keystore if it was created ephemerally. 606 var keystoreErr error 607 if n.ephemeralKeystore != "" { 608 keystoreErr = os.RemoveAll(n.ephemeralKeystore) 609 } 610 611 if len(failure.Services) > 0 { 612 return failure 613 } 614 if keystoreErr != nil { 615 return keystoreErr 616 } 617 return nil 618 } 619 620 // Wait blocks the thread until the node is stopped. If the node is not running 621 // at the time of invocation, the method immediately returns. 622 func (n *Node) Wait() { 623 n.lock.RLock() 624 if n.server == nil { 625 n.lock.RUnlock() 626 return 627 } 628 stop := n.stop 629 n.lock.RUnlock() 630 631 <-stop 632 } 633 634 // Restart terminates a running node and boots up a new one in its place. If the 635 // node isn't running, an error is returned. 636 func (n *Node) Restart() error { 637 if err := n.Stop(); err != nil { 638 return err 639 } 640 if err := n.Start(); err != nil { 641 return err 642 } 643 return nil 644 } 645 646 // Attach creates an RPC client attached to an in-process API handler. 647 func (n *Node) Attach() (*rpc.Client, error) { 648 n.lock.RLock() 649 defer n.lock.RUnlock() 650 651 if n.server == nil { 652 return nil, ErrNodeStopped 653 } 654 return rpc.DialInProc(n.inprocHandler), nil 655 } 656 657 // RPCHandler returns the in-process RPC request handler. 658 func (n *Node) RPCHandler() (*rpc.Server, error) { 659 n.lock.RLock() 660 defer n.lock.RUnlock() 661 662 if n.inprocHandler == nil { 663 return nil, ErrNodeStopped 664 } 665 return n.inprocHandler, nil 666 } 667 668 // Server retrieves the currently running P2P network layer. This method is meant 669 // only to inspect fields of the currently running server, life cycle management 670 // should be left to this Node entity. 671 func (n *Node) Server() *p2p.Server { 672 n.lock.RLock() 673 defer n.lock.RUnlock() 674 675 return n.server 676 } 677 678 // Service retrieves a currently running service registered of a specific type. 679 func (n *Node) Service(service interface{}) error { 680 n.lock.RLock() 681 defer n.lock.RUnlock() 682 683 // Short circuit if the node's not running 684 if n.server == nil { 685 return ErrNodeStopped 686 } 687 // Otherwise try to find the service to return 688 element := reflect.ValueOf(service).Elem() 689 if running, ok := n.services[element.Type()]; ok { 690 element.Set(reflect.ValueOf(running)) 691 return nil 692 } 693 return ErrServiceUnknown 694 } 695 696 // DataDir retrieves the current datadir used by the protocol stack. 697 // Deprecated: No files should be stored in this directory, use InstanceDir instead. 698 func (n *Node) DataDir() string { 699 return n.config.DataDir 700 } 701 702 // InstanceDir retrieves the instance directory used by the protocol stack. 703 func (n *Node) InstanceDir() string { 704 return n.config.instanceDir() 705 } 706 707 // AccountManager retrieves the account manager used by the protocol stack. 708 func (n *Node) AccountManager() *accounts.Manager { 709 return n.accman 710 } 711 712 // IPCEndpoint retrieves the current IPC endpoint used by the protocol stack. 713 func (n *Node) IPCEndpoint() string { 714 return n.ipcEndpoint 715 } 716 717 // HTTPEndpoint retrieves the current HTTP endpoint used by the protocol stack. 718 func (n *Node) HTTPEndpoint() string { 719 n.lock.Lock() 720 defer n.lock.Unlock() 721 722 if n.httpListener != nil { 723 return n.httpListener.Addr().String() 724 } 725 return n.httpEndpoint 726 } 727 728 // WSEndpoint retrieves the current WS endpoint used by the protocol stack. 729 func (n *Node) WSEndpoint() string { 730 n.lock.Lock() 731 defer n.lock.Unlock() 732 733 if n.wsListener != nil { 734 return n.wsListener.Addr().String() 735 } 736 return n.wsEndpoint 737 } 738 739 // EventMux retrieves the event multiplexer used by all the network services in 740 // the current protocol stack. 741 func (n *Node) EventMux() *event.TypeMux { 742 return n.eventmux 743 } 744 745 // OpenDatabase opens an existing database with the given name (or creates one if no 746 // previous can be found) from within the node's instance directory. If the node is 747 // ephemeral, a memory database is returned. 748 func (n *Node) OpenDatabase(name string, cache, handles int) (ethdb.Database, error) { 749 if n.config.DataDir == "" { 750 return ethdb.NewMemDatabase(), nil 751 } 752 return ethdb.NewLDBDatabase(n.config.ResolvePath(name), cache, handles) 753 } 754 755 func (n *Node) OpenShyftDatabase() (ethdb.SDatabase, error) { 756 return ethdb.NewShyftDatabase() 757 } 758 759 // ResolvePath returns the absolute path of a resource in the instance directory. 760 func (n *Node) ResolvePath(x string) string { 761 return n.config.ResolvePath(x) 762 } 763 764 // apis returns the collection of RPC descriptors this node offers. 765 func (n *Node) apis() []rpc.API { 766 return []rpc.API{ 767 { 768 Namespace: "admin", 769 Version: "1.0", 770 Service: NewPrivateAdminAPI(n), 771 }, { 772 Namespace: "admin", 773 Version: "1.0", 774 Service: NewPublicAdminAPI(n), 775 Public: true, 776 }, { 777 Namespace: "debug", 778 Version: "1.0", 779 Service: debug.Handler, 780 }, { 781 Namespace: "debug", 782 Version: "1.0", 783 Service: NewPublicDebugAPI(n), 784 Public: true, 785 }, { 786 Namespace: "web3", 787 Version: "1.0", 788 Service: NewPublicWeb3API(n), 789 Public: true, 790 }, 791 } 792 }