From 3b2c9275fda8acbc2daada2c25baf1cb634a0843 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Wed, 15 Apr 2020 18:20:07 +0200
Subject: [PATCH 001/160] created a new package node_2 where i am experimenting
w/ interfaces and starting node
---
node_2/api.go | 317 +++++++++++++++++++
node_2/config.go | 545 ++++++++++++++++++++++++++++++++
node_2/defaults.go | 113 +++++++
node_2/endpoints.go | 99 ++++++
node_2/errors.go | 63 ++++
node_2/node.go | 737 ++++++++++++++++++++++++++++++++++++++++++++
node_2/rpcstack.go | 185 +++++++++++
node_2/service.go | 133 ++++++++
8 files changed, 2192 insertions(+)
create mode 100644 node_2/api.go
create mode 100644 node_2/config.go
create mode 100644 node_2/defaults.go
create mode 100644 node_2/endpoints.go
create mode 100644 node_2/errors.go
create mode 100644 node_2/node.go
create mode 100644 node_2/rpcstack.go
create mode 100644 node_2/service.go
diff --git a/node_2/api.go b/node_2/api.go
new file mode 100644
index 000000000000..53f4f2dbc9c1
--- /dev/null
+++ b/node_2/api.go
@@ -0,0 +1,317 @@
+// Copyright 2015 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package node_2
+
+import (
+ "context"
+ "fmt"
+ "strings"
+
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/p2p"
+ "github.com/ethereum/go-ethereum/p2p/enode"
+ "github.com/ethereum/go-ethereum/rpc"
+)
+
+// PrivateAdminAPI is the collection of administrative API methods exposed only
+// over a secure RPC channel.
+type PrivateAdminAPI struct {
+ node *Node // Node interfaced by this API
+}
+
+// NewPrivateAdminAPI creates a new API definition for the private admin methods
+// of the node itself.
+func NewPrivateAdminAPI(node *Node) *PrivateAdminAPI {
+ return &PrivateAdminAPI{node: node}
+}
+
+// AddPeer requests connecting to a remote node, and also maintaining the new
+// connection at all times, even reconnecting if it is lost.
+func (api *PrivateAdminAPI) AddPeer(url string) (bool, error) {
+ // Make sure the server is running, fail otherwise
+ server := api.node.Server()
+ if server == nil {
+ return false, ErrNodeStopped
+ }
+ // Try to add the url as a static peer and return
+ node, err := enode.Parse(enode.ValidSchemes, url)
+ if err != nil {
+ return false, fmt.Errorf("invalid enode: %v", err)
+ }
+ server.AddPeer(node)
+ return true, nil
+}
+
+// RemovePeer disconnects from a remote node if the connection exists
+func (api *PrivateAdminAPI) RemovePeer(url string) (bool, error) {
+ // Make sure the server is running, fail otherwise
+ server := api.node.Server()
+ if server == nil {
+ return false, ErrNodeStopped
+ }
+ // Try to remove the url as a static peer and return
+ node, err := enode.Parse(enode.ValidSchemes, url)
+ if err != nil {
+ return false, fmt.Errorf("invalid enode: %v", err)
+ }
+ server.RemovePeer(node)
+ return true, nil
+}
+
+// AddTrustedPeer allows a remote node to always connect, even if slots are full
+func (api *PrivateAdminAPI) AddTrustedPeer(url string) (bool, error) {
+ // Make sure the server is running, fail otherwise
+ server := api.node.Server()
+ if server == nil {
+ return false, ErrNodeStopped
+ }
+ node, err := enode.Parse(enode.ValidSchemes, url)
+ if err != nil {
+ return false, fmt.Errorf("invalid enode: %v", err)
+ }
+ server.AddTrustedPeer(node)
+ return true, nil
+}
+
+// RemoveTrustedPeer removes a remote node from the trusted peer set, but it
+// does not disconnect it automatically.
+func (api *PrivateAdminAPI) RemoveTrustedPeer(url string) (bool, error) {
+ // Make sure the server is running, fail otherwise
+ server := api.node.Server()
+ if server == nil {
+ return false, ErrNodeStopped
+ }
+ node, err := enode.Parse(enode.ValidSchemes, url)
+ if err != nil {
+ return false, fmt.Errorf("invalid enode: %v", err)
+ }
+ server.RemoveTrustedPeer(node)
+ return true, nil
+}
+
+// PeerEvents creates an RPC subscription which receives peer events from the
+// node's p2p.Server
+func (api *PrivateAdminAPI) PeerEvents(ctx context.Context) (*rpc.Subscription, error) {
+ // Make sure the server is running, fail otherwise
+ server := api.node.Server()
+ if server == nil {
+ return nil, ErrNodeStopped
+ }
+
+ // Create the subscription
+ notifier, supported := rpc.NotifierFromContext(ctx)
+ if !supported {
+ return nil, rpc.ErrNotificationsUnsupported
+ }
+ rpcSub := notifier.CreateSubscription()
+
+ go func() {
+ events := make(chan *p2p.PeerEvent)
+ sub := server.SubscribeEvents(events)
+ defer sub.Unsubscribe()
+
+ for {
+ select {
+ case event := <-events:
+ notifier.Notify(rpcSub.ID, event)
+ case <-sub.Err():
+ return
+ case <-rpcSub.Err():
+ return
+ case <-notifier.Closed():
+ return
+ }
+ }
+ }()
+
+ return rpcSub, nil
+}
+
+// StartRPC starts the HTTP RPC API server.
+func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis *string, vhosts *string) (bool, error) {
+ api.node.lock.Lock()
+ defer api.node.lock.Unlock()
+
+ if api.node.httpHandler != nil {
+ return false, fmt.Errorf("HTTP RPC already running on %s", api.node.httpEndpoint)
+ }
+
+ if host == nil {
+ h := DefaultHTTPHost
+ if api.node.config.HTTPHost != "" {
+ h = api.node.config.HTTPHost
+ }
+ host = &h
+ }
+ if port == nil {
+ port = &api.node.config.HTTPPort
+ }
+
+ allowedOrigins := api.node.config.HTTPCors
+ if cors != nil {
+ allowedOrigins = nil
+ for _, origin := range strings.Split(*cors, ",") {
+ allowedOrigins = append(allowedOrigins, strings.TrimSpace(origin))
+ }
+ }
+
+ allowedVHosts := api.node.config.HTTPVirtualHosts
+ if vhosts != nil {
+ allowedVHosts = nil
+ for _, vhost := range strings.Split(*host, ",") {
+ allowedVHosts = append(allowedVHosts, strings.TrimSpace(vhost))
+ }
+ }
+
+ modules := api.node.httpWhitelist
+ if apis != nil {
+ modules = nil
+ for _, m := range strings.Split(*apis, ",") {
+ modules = append(modules, strings.TrimSpace(m))
+ }
+ }
+
+ if err := api.node.startHTTP(fmt.Sprintf("%s:%d", *host, *port), api.node.rpcAPIs, modules, allowedOrigins, allowedVHosts, api.node.config.HTTPTimeouts, api.node.config.WSOrigins); err != nil {
+ return false, err
+ }
+ return true, nil
+}
+
+// StopRPC terminates an already running HTTP RPC API endpoint.
+func (api *PrivateAdminAPI) StopRPC() (bool, error) {
+ api.node.lock.Lock()
+ defer api.node.lock.Unlock()
+
+ if api.node.httpHandler == nil {
+ return false, fmt.Errorf("HTTP RPC not running")
+ }
+ api.node.stopHTTP()
+ return true, nil
+}
+
+// StartWS starts the websocket RPC API server.
+func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *string, apis *string) (bool, error) {
+ api.node.lock.Lock()
+ defer api.node.lock.Unlock()
+
+ if api.node.wsHandler != nil {
+ return false, fmt.Errorf("WebSocket RPC already running on %s", api.node.wsEndpoint)
+ }
+
+ if host == nil {
+ h := DefaultWSHost
+ if api.node.config.WSHost != "" {
+ h = api.node.config.WSHost
+ }
+ host = &h
+ }
+ if port == nil {
+ port = &api.node.config.WSPort
+ }
+
+ origins := api.node.config.WSOrigins
+ if allowedOrigins != nil {
+ origins = nil
+ for _, origin := range strings.Split(*allowedOrigins, ",") {
+ origins = append(origins, strings.TrimSpace(origin))
+ }
+ }
+
+ modules := api.node.config.WSModules
+ if apis != nil {
+ modules = nil
+ for _, m := range strings.Split(*apis, ",") {
+ modules = append(modules, strings.TrimSpace(m))
+ }
+ }
+
+ if err := api.node.startWS(fmt.Sprintf("%s:%d", *host, *port), api.node.rpcAPIs, modules, origins, api.node.config.WSExposeAll); err != nil {
+ return false, err
+ }
+ return true, nil
+}
+
+// StopWS terminates an already running websocket RPC API endpoint.
+func (api *PrivateAdminAPI) StopWS() (bool, error) {
+ api.node.lock.Lock()
+ defer api.node.lock.Unlock()
+
+ if api.node.wsHandler == nil {
+ return false, fmt.Errorf("WebSocket RPC not running")
+ }
+ api.node.stopWS()
+ return true, nil
+}
+
+// PublicAdminAPI is the collection of administrative API methods exposed over
+// both secure and unsecure RPC channels.
+type PublicAdminAPI struct {
+ node *Node // Node interfaced by this API
+}
+
+// NewPublicAdminAPI creates a new API definition for the public admin methods
+// of the node itself.
+func NewPublicAdminAPI(node *Node) *PublicAdminAPI {
+ return &PublicAdminAPI{node: node}
+}
+
+// Peers retrieves all the information we know about each individual peer at the
+// protocol granularity.
+func (api *PublicAdminAPI) Peers() ([]*p2p.PeerInfo, error) {
+ server := api.node.Server()
+ if server == nil {
+ return nil, ErrNodeStopped
+ }
+ return server.PeersInfo(), nil
+}
+
+// NodeInfo retrieves all the information we know about the host node at the
+// protocol granularity.
+func (api *PublicAdminAPI) NodeInfo() (*p2p.NodeInfo, error) {
+ server := api.node.Server()
+ if server == nil {
+ return nil, ErrNodeStopped
+ }
+ return server.NodeInfo(), nil
+}
+
+// Datadir retrieves the current data directory the node is using.
+func (api *PublicAdminAPI) Datadir() string {
+ return api.node.DataDir()
+}
+
+// PublicWeb3API offers helper utils
+type PublicWeb3API struct {
+ stack *Node
+}
+
+// NewPublicWeb3API creates a new Web3Service instance
+func NewPublicWeb3API(stack *Node) *PublicWeb3API {
+ return &PublicWeb3API{stack}
+}
+
+// ClientVersion returns the node name
+func (s *PublicWeb3API) ClientVersion() string {
+ return s.stack.Server().Name
+}
+
+// Sha3 applies the ethereum sha3 implementation on the input.
+// It assumes the input is hex encoded.
+func (s *PublicWeb3API) Sha3(input hexutil.Bytes) hexutil.Bytes {
+ return crypto.Keccak256(input)
+}
diff --git a/node_2/config.go b/node_2/config.go
new file mode 100644
index 000000000000..4a7814adeb70
--- /dev/null
+++ b/node_2/config.go
@@ -0,0 +1,545 @@
+// Copyright 2014 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package node_2
+
+import (
+ "crypto/ecdsa"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "sync"
+
+ "github.com/ethereum/go-ethereum/accounts"
+ "github.com/ethereum/go-ethereum/accounts/external"
+ "github.com/ethereum/go-ethereum/accounts/keystore"
+ "github.com/ethereum/go-ethereum/accounts/scwallet"
+ "github.com/ethereum/go-ethereum/accounts/usbwallet"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/log"
+ "github.com/ethereum/go-ethereum/p2p"
+ "github.com/ethereum/go-ethereum/p2p/enode"
+ "github.com/ethereum/go-ethereum/rpc"
+)
+
+const (
+ datadirPrivateKey = "nodekey" // Path within the datadir to the node's private key
+ datadirDefaultKeyStore = "keystore" // Path within the datadir to the keystore
+ datadirStaticNodes = "static-nodes.json" // Path within the datadir to the static node list
+ datadirTrustedNodes = "trusted-nodes.json" // Path within the datadir to the trusted node list
+ datadirNodeDatabase = "nodes" // Path within the datadir to store the node infos
+)
+
+// Config represents a small collection of configuration values to fine tune the
+// P2P network layer of a protocol stack. These values can be further extended by
+// all registered services.
+type Config struct {
+ // Name sets the instance name of the node. It must not contain the / character and is
+ // used in the devp2p node identifier. The instance name of geth is "geth". If no
+ // value is specified, the basename of the current executable is used.
+ Name string `toml:"-"`
+
+ // UserIdent, if set, is used as an additional component in the devp2p node identifier.
+ UserIdent string `toml:",omitempty"`
+
+ // Version should be set to the version number of the program. It is used
+ // in the devp2p node identifier.
+ Version string `toml:"-"`
+
+ // DataDir is the file system folder the node should use for any data storage
+ // requirements. The configured data directory will not be directly shared with
+ // registered services, instead those can use utility methods to create/access
+ // databases or flat files. This enables ephemeral nodes which can fully reside
+ // in memory.
+ DataDir string
+
+ // Configuration of peer-to-peer networking.
+ P2P p2p.Config
+
+ // KeyStoreDir is the file system folder that contains private keys. The directory can
+ // be specified as a relative path, in which case it is resolved relative to the
+ // current directory.
+ //
+ // If KeyStoreDir is empty, the default location is the "keystore" subdirectory of
+ // DataDir. If DataDir is unspecified and KeyStoreDir is empty, an ephemeral directory
+ // is created by New and destroyed when the node is stopped.
+ KeyStoreDir string `toml:",omitempty"`
+
+ // ExternalSigner specifies an external URI for a clef-type signer
+ ExternalSigner string `toml:"omitempty"`
+
+ // UseLightweightKDF lowers the memory and CPU requirements of the key store
+ // scrypt KDF at the expense of security.
+ UseLightweightKDF bool `toml:",omitempty"`
+
+ // InsecureUnlockAllowed allows user to unlock accounts in unsafe http environment.
+ InsecureUnlockAllowed bool `toml:",omitempty"`
+
+ // NoUSB disables hardware wallet monitoring and connectivity.
+ NoUSB bool `toml:",omitempty"`
+
+ // SmartCardDaemonPath is the path to the smartcard daemon's socket
+ SmartCardDaemonPath string `toml:",omitempty"`
+
+ // IPCPath is the requested location to place the IPC endpoint. If the path is
+ // a simple file name, it is placed inside the data directory (or on the root
+ // pipe path on Windows), whereas if it's a resolvable path name (absolute or
+ // relative), then that specific path is enforced. An empty path disables IPC.
+ IPCPath string `toml:",omitempty"`
+
+ // HTTPHost is the host interface on which to start the HTTP RPC server. If this
+ // field is empty, no HTTP API endpoint will be started.
+ HTTPHost string `toml:",omitempty"`
+
+ // HTTPPort is the TCP port number on which to start the HTTP RPC server. The
+ // default zero value is/ valid and will pick a port number randomly (useful
+ // for ephemeral nodes).
+ HTTPPort int `toml:",omitempty"`
+
+ // HTTPCors is the Cross-Origin Resource Sharing header to send to requesting
+ // clients. Please be aware that CORS is a browser enforced security, it's fully
+ // useless for custom HTTP clients.
+ HTTPCors []string `toml:",omitempty"`
+
+ // HTTPVirtualHosts is the list of virtual hostnames which are allowed on incoming requests.
+ // This is by default {'localhost'}. Using this prevents attacks like
+ // DNS rebinding, which bypasses SOP by simply masquerading as being within the same
+ // origin. These attacks do not utilize CORS, since they are not cross-domain.
+ // By explicitly checking the Host-header, the server will not allow requests
+ // made against the server with a malicious host domain.
+ // Requests using ip address directly are not affected
+ HTTPVirtualHosts []string `toml:",omitempty"`
+
+ // HTTPModules is a list of API modules to expose via the HTTP RPC interface.
+ // If the module list is empty, all RPC API endpoints designated public will be
+ // exposed.
+ HTTPModules []string `toml:",omitempty"`
+
+ // HTTPTimeouts allows for customization of the timeout values used by the HTTP RPC
+ // interface.
+ HTTPTimeouts rpc.HTTPTimeouts
+
+ // WSHost is the host interface on which to start the websocket RPC server. If
+ // this field is empty, no websocket API endpoint will be started.
+ WSHost string `toml:",omitempty"`
+
+ // WSPort is the TCP port number on which to start the websocket RPC server. The
+ // default zero value is/ valid and will pick a port number randomly (useful for
+ // ephemeral nodes).
+ WSPort int `toml:",omitempty"`
+
+ // WSOrigins is the list of domain to accept websocket requests from. Please be
+ // aware that the server can only act upon the HTTP request the client sends and
+ // cannot verify the validity of the request header.
+ WSOrigins []string `toml:",omitempty"`
+
+ // WSModules is a list of API modules to expose via the websocket RPC interface.
+ // If the module list is empty, all RPC API endpoints designated public will be
+ // exposed.
+ WSModules []string `toml:",omitempty"`
+
+ // WSExposeAll exposes all API modules via the WebSocket RPC interface rather
+ // than just the public ones.
+ //
+ // *WARNING* Only set this if the node is running in a trusted network, exposing
+ // private APIs to untrusted users is a major security risk.
+ WSExposeAll bool `toml:",omitempty"`
+
+ // GraphQLHost is the host interface on which to start the GraphQL server. If this
+ // field is empty, no GraphQL API endpoint will be started.
+ GraphQLHost string `toml:",omitempty"`
+
+ // GraphQLPort is the TCP port number on which to start the GraphQL server. The
+ // default zero value is/ valid and will pick a port number randomly (useful
+ // for ephemeral nodes).
+ GraphQLPort int `toml:",omitempty"`
+
+ // GraphQLCors is the Cross-Origin Resource Sharing header to send to requesting
+ // clients. Please be aware that CORS is a browser enforced security, it's fully
+ // useless for custom HTTP clients.
+ GraphQLCors []string `toml:",omitempty"`
+
+ // GraphQLVirtualHosts is the list of virtual hostnames which are allowed on incoming requests.
+ // This is by default {'localhost'}. Using this prevents attacks like
+ // DNS rebinding, which bypasses SOP by simply masquerading as being within the same
+ // origin. These attacks do not utilize CORS, since they are not cross-domain.
+ // By explicitly checking the Host-header, the server will not allow requests
+ // made against the server with a malicious host domain.
+ // Requests using ip address directly are not affected
+ GraphQLVirtualHosts []string `toml:",omitempty"`
+
+ // Logger is a custom logger to use with the p2p.Server.
+ Logger log.Logger `toml:",omitempty"`
+
+ staticNodesWarning bool
+ trustedNodesWarning bool
+ oldGethResourceWarning bool
+}
+
+// IPCEndpoint resolves an IPC endpoint based on a configured value, taking into
+// account the set data folders as well as the designated platform we're currently
+// running on.
+func (c *Config) IPCEndpoint() string {
+ // Short circuit if IPC has not been enabled
+ if c.IPCPath == "" {
+ return ""
+ }
+ // On windows we can only use plain top-level pipes
+ if runtime.GOOS == "windows" {
+ if strings.HasPrefix(c.IPCPath, `\\.\pipe\`) {
+ return c.IPCPath
+ }
+ return `\\.\pipe\` + c.IPCPath
+ }
+ // Resolve names into the data directory full paths otherwise
+ if filepath.Base(c.IPCPath) == c.IPCPath {
+ if c.DataDir == "" {
+ return filepath.Join(os.TempDir(), c.IPCPath)
+ }
+ return filepath.Join(c.DataDir, c.IPCPath)
+ }
+ return c.IPCPath
+}
+
+// NodeDB returns the path to the discovery node database.
+func (c *Config) NodeDB() string {
+ if c.DataDir == "" {
+ return "" // ephemeral
+ }
+ return c.ResolvePath(datadirNodeDatabase)
+}
+
+// DefaultIPCEndpoint returns the IPC path used by default.
+func DefaultIPCEndpoint(clientIdentifier string) string {
+ if clientIdentifier == "" {
+ clientIdentifier = strings.TrimSuffix(filepath.Base(os.Args[0]), ".exe")
+ if clientIdentifier == "" {
+ panic("empty executable name")
+ }
+ }
+ config := &Config{DataDir: DefaultDataDir(), IPCPath: clientIdentifier + ".ipc"}
+ return config.IPCEndpoint()
+}
+
+// HTTPEndpoint resolves an HTTP endpoint based on the configured host interface
+// and port parameters.
+func (c *Config) HTTPEndpoint() string {
+ if c.HTTPHost == "" {
+ return ""
+ }
+ return fmt.Sprintf("%s:%d", c.HTTPHost, c.HTTPPort)
+}
+
+// GraphQLEndpoint resolves a GraphQL endpoint based on the configured host interface
+// and port parameters.
+func (c *Config) GraphQLEndpoint() string {
+ if c.GraphQLHost == "" {
+ return ""
+ }
+ return fmt.Sprintf("%s:%d", c.GraphQLHost, c.GraphQLPort)
+}
+
+// DefaultHTTPEndpoint returns the HTTP endpoint used by default.
+func DefaultHTTPEndpoint() string {
+ config := &Config{HTTPHost: DefaultHTTPHost, HTTPPort: DefaultHTTPPort}
+ return config.HTTPEndpoint()
+}
+
+// WSEndpoint resolves a websocket endpoint based on the configured host interface
+// and port parameters.
+func (c *Config) WSEndpoint() string {
+ if c.WSHost == "" {
+ return ""
+ }
+ return fmt.Sprintf("%s:%d", c.WSHost, c.WSPort)
+}
+
+// DefaultWSEndpoint returns the websocket endpoint used by default.
+func DefaultWSEndpoint() string {
+ config := &Config{WSHost: DefaultWSHost, WSPort: DefaultWSPort}
+ return config.WSEndpoint()
+}
+
+// ExtRPCEnabled returns the indicator whether node enables the external
+// RPC(http, ws or graphql).
+func (c *Config) ExtRPCEnabled() bool {
+ return c.HTTPHost != "" || c.WSHost != "" || c.GraphQLHost != ""
+}
+
+// NodeName returns the devp2p node identifier.
+func (c *Config) NodeName() string {
+ name := c.name()
+ // Backwards compatibility: previous versions used title-cased "Geth", keep that.
+ if name == "geth" || name == "geth-testnet" {
+ name = "Geth"
+ }
+ if c.UserIdent != "" {
+ name += "/" + c.UserIdent
+ }
+ if c.Version != "" {
+ name += "/v" + c.Version
+ }
+ name += "/" + runtime.GOOS + "-" + runtime.GOARCH
+ name += "/" + runtime.Version()
+ return name
+}
+
+func (c *Config) name() string {
+ if c.Name == "" {
+ progname := strings.TrimSuffix(filepath.Base(os.Args[0]), ".exe")
+ if progname == "" {
+ panic("empty executable name, set Config.Name")
+ }
+ return progname
+ }
+ return c.Name
+}
+
+// These resources are resolved differently for "geth" instances.
+var isOldGethResource = map[string]bool{
+ "chaindata": true,
+ "nodes": true,
+ "nodekey": true,
+ "static-nodes.json": false, // no warning for these because they have their
+ "trusted-nodes.json": false, // own separate warning.
+}
+
+// ResolvePath resolves path in the instance directory.
+func (c *Config) ResolvePath(path string) string {
+ if filepath.IsAbs(path) {
+ return path
+ }
+ if c.DataDir == "" {
+ return ""
+ }
+ // Backwards-compatibility: ensure that data directory files created
+ // by geth 1.4 are used if they exist.
+ if warn, isOld := isOldGethResource[path]; isOld {
+ oldpath := ""
+ if c.name() == "geth" {
+ oldpath = filepath.Join(c.DataDir, path)
+ }
+ if oldpath != "" && common.FileExist(oldpath) {
+ if warn {
+ c.warnOnce(&c.oldGethResourceWarning, "Using deprecated resource file %s, please move this file to the 'geth' subdirectory of datadir.", oldpath)
+ }
+ return oldpath
+ }
+ }
+ return filepath.Join(c.instanceDir(), path)
+}
+
+func (c *Config) instanceDir() string {
+ if c.DataDir == "" {
+ return ""
+ }
+ return filepath.Join(c.DataDir, c.name())
+}
+
+// NodeKey retrieves the currently configured private key of the node, checking
+// first any manually set key, falling back to the one found in the configured
+// data folder. If no key can be found, a new one is generated.
+func (c *Config) NodeKey() *ecdsa.PrivateKey {
+ // Use any specifically configured key.
+ if c.P2P.PrivateKey != nil {
+ return c.P2P.PrivateKey
+ }
+ // Generate ephemeral key if no datadir is being used.
+ if c.DataDir == "" {
+ key, err := crypto.GenerateKey()
+ if err != nil {
+ log.Crit(fmt.Sprintf("Failed to generate ephemeral node key: %v", err))
+ }
+ return key
+ }
+
+ keyfile := c.ResolvePath(datadirPrivateKey)
+ if key, err := crypto.LoadECDSA(keyfile); err == nil {
+ return key
+ }
+ // No persistent key found, generate and store a new one.
+ key, err := crypto.GenerateKey()
+ if err != nil {
+ log.Crit(fmt.Sprintf("Failed to generate node key: %v", err))
+ }
+ instanceDir := filepath.Join(c.DataDir, c.name())
+ if err := os.MkdirAll(instanceDir, 0700); err != nil {
+ log.Error(fmt.Sprintf("Failed to persist node key: %v", err))
+ return key
+ }
+ keyfile = filepath.Join(instanceDir, datadirPrivateKey)
+ if err := crypto.SaveECDSA(keyfile, key); err != nil {
+ log.Error(fmt.Sprintf("Failed to persist node key: %v", err))
+ }
+ return key
+}
+
+// StaticNodes returns a list of node enode URLs configured as static nodes.
+func (c *Config) StaticNodes() []*enode.Node {
+ return c.parsePersistentNodes(&c.staticNodesWarning, c.ResolvePath(datadirStaticNodes))
+}
+
+// TrustedNodes returns a list of node enode URLs configured as trusted nodes.
+func (c *Config) TrustedNodes() []*enode.Node {
+ return c.parsePersistentNodes(&c.trustedNodesWarning, c.ResolvePath(datadirTrustedNodes))
+}
+
+// parsePersistentNodes parses a list of discovery node URLs loaded from a .json
+// file from within the data directory.
+func (c *Config) parsePersistentNodes(w *bool, path string) []*enode.Node {
+ // Short circuit if no node config is present
+ if c.DataDir == "" {
+ return nil
+ }
+ if _, err := os.Stat(path); err != nil {
+ return nil
+ }
+ c.warnOnce(w, "Found deprecated node list file %s, please use the TOML config file instead.", path)
+
+ // Load the nodes from the config file.
+ var nodelist []string
+ if err := common.LoadJSON(path, &nodelist); err != nil {
+ log.Error(fmt.Sprintf("Can't load node list file: %v", err))
+ return nil
+ }
+ // Interpret the list as a discovery node array
+ var nodes []*enode.Node
+ for _, url := range nodelist {
+ if url == "" {
+ continue
+ }
+ node, err := enode.Parse(enode.ValidSchemes, url)
+ if err != nil {
+ log.Error(fmt.Sprintf("Node URL %s: %v\n", url, err))
+ continue
+ }
+ nodes = append(nodes, node)
+ }
+ return nodes
+}
+
+// AccountConfig determines the settings for scrypt and keydirectory
+func (c *Config) AccountConfig() (int, int, string, error) {
+ scryptN := keystore.StandardScryptN
+ scryptP := keystore.StandardScryptP
+ if c.UseLightweightKDF {
+ scryptN = keystore.LightScryptN
+ scryptP = keystore.LightScryptP
+ }
+
+ var (
+ keydir string
+ err error
+ )
+ switch {
+ case filepath.IsAbs(c.KeyStoreDir):
+ keydir = c.KeyStoreDir
+ case c.DataDir != "":
+ if c.KeyStoreDir == "" {
+ keydir = filepath.Join(c.DataDir, datadirDefaultKeyStore)
+ } else {
+ keydir, err = filepath.Abs(c.KeyStoreDir)
+ }
+ case c.KeyStoreDir != "":
+ keydir, err = filepath.Abs(c.KeyStoreDir)
+ }
+ return scryptN, scryptP, keydir, err
+}
+
+func makeAccountManager(conf *Config) (*accounts.Manager, string, error) {
+ scryptN, scryptP, keydir, err := conf.AccountConfig()
+ var ephemeral string
+ if keydir == "" {
+ // There is no datadir.
+ keydir, err = ioutil.TempDir("", "go-ethereum-keystore")
+ ephemeral = keydir
+ }
+
+ if err != nil {
+ return nil, "", err
+ }
+ if err := os.MkdirAll(keydir, 0700); err != nil {
+ return nil, "", err
+ }
+ // Assemble the account manager and supported backends
+ var backends []accounts.Backend
+ if len(conf.ExternalSigner) > 0 {
+ log.Info("Using external signer", "url", conf.ExternalSigner)
+ if extapi, err := external.NewExternalBackend(conf.ExternalSigner); err == nil {
+ backends = append(backends, extapi)
+ } else {
+ return nil, "", fmt.Errorf("error connecting to external signer: %v", err)
+ }
+ }
+ if len(backends) == 0 {
+ // For now, we're using EITHER external signer OR local signers.
+ // If/when we implement some form of lockfile for USB and keystore wallets,
+ // we can have both, but it's very confusing for the user to see the same
+ // accounts in both externally and locally, plus very racey.
+ backends = append(backends, keystore.NewKeyStore(keydir, scryptN, scryptP))
+ if !conf.NoUSB {
+ // Start a USB hub for Ledger hardware wallets
+ if ledgerhub, err := usbwallet.NewLedgerHub(); err != nil {
+ log.Warn(fmt.Sprintf("Failed to start Ledger hub, disabling: %v", err))
+ } else {
+ backends = append(backends, ledgerhub)
+ }
+ // Start a USB hub for Trezor hardware wallets (HID version)
+ if trezorhub, err := usbwallet.NewTrezorHubWithHID(); err != nil {
+ log.Warn(fmt.Sprintf("Failed to start HID Trezor hub, disabling: %v", err))
+ } else {
+ backends = append(backends, trezorhub)
+ }
+ // Start a USB hub for Trezor hardware wallets (WebUSB version)
+ if trezorhub, err := usbwallet.NewTrezorHubWithWebUSB(); err != nil {
+ log.Warn(fmt.Sprintf("Failed to start WebUSB Trezor hub, disabling: %v", err))
+ } else {
+ backends = append(backends, trezorhub)
+ }
+ }
+ if len(conf.SmartCardDaemonPath) > 0 {
+ // Start a smart card hub
+ if schub, err := scwallet.NewHub(conf.SmartCardDaemonPath, scwallet.Scheme, keydir); err != nil {
+ log.Warn(fmt.Sprintf("Failed to start smart card hub, disabling: %v", err))
+ } else {
+ backends = append(backends, schub)
+ }
+ }
+ }
+
+ return accounts.NewManager(&accounts.Config{InsecureUnlockAllowed: conf.InsecureUnlockAllowed}, backends...), ephemeral, nil
+}
+
+var warnLock sync.Mutex
+
+func (c *Config) warnOnce(w *bool, format string, args ...interface{}) {
+ warnLock.Lock()
+ defer warnLock.Unlock()
+
+ if *w {
+ return
+ }
+ l := c.Logger
+ if l == nil {
+ l = log.Root()
+ }
+ l.Warn(fmt.Sprintf(format, args...))
+ *w = true
+}
diff --git a/node_2/defaults.go b/node_2/defaults.go
new file mode 100644
index 000000000000..9951aaa0265e
--- /dev/null
+++ b/node_2/defaults.go
@@ -0,0 +1,113 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package node_2
+
+import (
+ "os"
+ "os/user"
+ "path/filepath"
+ "runtime"
+
+ "github.com/ethereum/go-ethereum/p2p"
+ "github.com/ethereum/go-ethereum/p2p/nat"
+ "github.com/ethereum/go-ethereum/rpc"
+)
+
+const (
+ DefaultHTTPHost = "localhost" // Default host interface for the HTTP RPC server
+ DefaultHTTPPort = 8545 // Default TCP port for the HTTP RPC server
+ DefaultWSHost = "localhost" // Default host interface for the websocket RPC server
+ DefaultWSPort = 8546 // Default TCP port for the websocket RPC server
+ DefaultGraphQLHost = "localhost" // Default host interface for the GraphQL server
+ DefaultGraphQLPort = 8547 // Default TCP port for the GraphQL server
+)
+
+// DefaultConfig contains reasonable default settings.
+var DefaultConfig = Config{
+ DataDir: DefaultDataDir(),
+ HTTPPort: DefaultHTTPPort,
+ HTTPModules: []string{"net", "web3"},
+ HTTPVirtualHosts: []string{"localhost"},
+ HTTPTimeouts: rpc.DefaultHTTPTimeouts,
+ WSPort: DefaultWSPort,
+ WSModules: []string{"net", "web3"},
+ GraphQLPort: DefaultGraphQLPort,
+ GraphQLVirtualHosts: []string{"localhost"},
+ P2P: p2p.Config{
+ ListenAddr: ":30303",
+ MaxPeers: 50,
+ NAT: nat.Any(),
+ },
+}
+
+// DefaultDataDir is the default data directory to use for the databases and other
+// persistence requirements.
+func DefaultDataDir() string {
+ // Try to place the data folder in the user's home dir
+ home := homeDir()
+ if home != "" {
+ switch runtime.GOOS {
+ case "darwin":
+ return filepath.Join(home, "Library", "Ethereum")
+ case "windows":
+ // We used to put everything in %HOME%\AppData\Roaming, but this caused
+ // problems with non-typical setups. If this fallback location exists and
+ // is non-empty, use it, otherwise DTRT and check %LOCALAPPDATA%.
+ fallback := filepath.Join(home, "AppData", "Roaming", "Ethereum")
+ appdata := windowsAppData()
+ if appdata == "" || isNonEmptyDir(fallback) {
+ return fallback
+ }
+ return filepath.Join(appdata, "Ethereum")
+ default:
+ return filepath.Join(home, ".ethereum")
+ }
+ }
+ // As we cannot guess a stable location, return empty and handle later
+ return ""
+}
+
+func windowsAppData() string {
+ v := os.Getenv("LOCALAPPDATA")
+ if v == "" {
+ // Windows XP and below don't have LocalAppData. Crash here because
+ // we don't support Windows XP and undefining the variable will cause
+ // other issues.
+ panic("environment variable LocalAppData is undefined")
+ }
+ return v
+}
+
+func isNonEmptyDir(dir string) bool {
+ f, err := os.Open(dir)
+ if err != nil {
+ return false
+ }
+ names, _ := f.Readdir(1)
+ f.Close()
+ return len(names) > 0
+}
+
+func homeDir() string {
+ if home := os.Getenv("HOME"); home != "" {
+ return home
+ }
+ if usr, err := user.Current(); err == nil {
+ return usr.HomeDir
+ }
+ return ""
+}
diff --git a/node_2/endpoints.go b/node_2/endpoints.go
new file mode 100644
index 000000000000..0dce7b5acfe3
--- /dev/null
+++ b/node_2/endpoints.go
@@ -0,0 +1,99 @@
+// Copyright 2018 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package node_2
+
+import (
+ "net"
+ "net/http"
+ "time"
+
+ "github.com/ethereum/go-ethereum/log"
+ "github.com/ethereum/go-ethereum/rpc"
+)
+
+// StartHTTPEndpoint starts the HTTP RPC endpoint.
+func StartHTTPEndpoint(endpoint string, timeouts rpc.HTTPTimeouts, handler http.Handler) (net.Listener, error) {
+ // start the HTTP listener
+ var (
+ listener net.Listener
+ err error
+ )
+ if listener, err = net.Listen("tcp", endpoint); err != nil {
+ return nil, err
+ }
+ // make sure timeout values are meaningful
+ CheckTimeouts(&timeouts)
+ // Bundle and start the HTTP server
+ httpSrv := &http.Server{
+ Handler: handler,
+ ReadTimeout: timeouts.ReadTimeout,
+ WriteTimeout: timeouts.WriteTimeout,
+ IdleTimeout: timeouts.IdleTimeout,
+ }
+ go httpSrv.Serve(listener)
+ return listener, err
+}
+
+// startWSEndpoint starts a websocket endpoint.
+func startWSEndpoint(endpoint string, handler http.Handler) (net.Listener, error) {
+ // start the HTTP listener
+ var (
+ listener net.Listener
+ err error
+ )
+ if listener, err = net.Listen("tcp", endpoint); err != nil {
+ return nil, err
+ }
+ wsSrv := &http.Server{Handler: handler}
+ go wsSrv.Serve(listener)
+ return listener, err
+}
+
+// checkModuleAvailability checks that all names given in modules are actually
+// available API services. It assumes that the MetadataApi module ("rpc") is always available;
+// the registration of this "rpc" module happens in NewServer() and is thus common to all endpoints.
+func checkModuleAvailability(modules []string, apis []rpc.API) (bad, available []string) {
+ availableSet := make(map[string]struct{})
+ for _, api := range apis {
+ if _, ok := availableSet[api.Namespace]; !ok {
+ availableSet[api.Namespace] = struct{}{}
+ available = append(available, api.Namespace)
+ }
+ }
+ for _, name := range modules {
+ if _, ok := availableSet[name]; !ok && name != rpc.MetadataApi {
+ bad = append(bad, name)
+ }
+ }
+ return bad, available
+}
+
+// CheckTimeouts ensures that timeout values are meaningful
+func CheckTimeouts(timeouts *rpc.HTTPTimeouts) {
+ if timeouts.ReadTimeout < time.Second {
+ log.Warn("Sanitizing invalid HTTP read timeout", "provided", timeouts.ReadTimeout, "updated", rpc.DefaultHTTPTimeouts.ReadTimeout)
+ timeouts.ReadTimeout = rpc.DefaultHTTPTimeouts.ReadTimeout
+ }
+ if timeouts.WriteTimeout < time.Second {
+ log.Warn("Sanitizing invalid HTTP write timeout", "provided", timeouts.WriteTimeout, "updated", rpc.DefaultHTTPTimeouts.WriteTimeout)
+ timeouts.WriteTimeout = rpc.DefaultHTTPTimeouts.WriteTimeout
+ }
+ if timeouts.IdleTimeout < time.Second {
+ log.Warn("Sanitizing invalid HTTP idle timeout", "provided", timeouts.IdleTimeout, "updated", rpc.DefaultHTTPTimeouts.IdleTimeout)
+ timeouts.IdleTimeout = rpc.DefaultHTTPTimeouts.IdleTimeout
+ }
+}
diff --git a/node_2/errors.go b/node_2/errors.go
new file mode 100644
index 000000000000..7ae4440208cc
--- /dev/null
+++ b/node_2/errors.go
@@ -0,0 +1,63 @@
+// Copyright 2015 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package node_2
+
+import (
+ "errors"
+ "fmt"
+ "reflect"
+ "syscall"
+)
+
+var (
+ ErrDatadirUsed = errors.New("datadir already used by another process")
+ ErrNodeStopped = errors.New("node not started")
+ ErrNodeRunning = errors.New("node already running")
+ ErrServiceUnknown = errors.New("unknown service")
+
+ datadirInUseErrnos = map[uint]bool{11: true, 32: true, 35: true}
+)
+
+func convertFileLockError(err error) error {
+ if errno, ok := err.(syscall.Errno); ok && datadirInUseErrnos[uint(errno)] {
+ return ErrDatadirUsed
+ }
+ return err
+}
+
+// DuplicateServiceError is returned during Node startup if a registered service
+// constructor returns a service of the same type that was already started.
+type DuplicateServiceError struct {
+ Kind reflect.Type
+}
+
+// Error generates a textual representation of the duplicate service error.
+func (e *DuplicateServiceError) Error() string {
+ return fmt.Sprintf("duplicate service: %v", e.Kind)
+}
+
+// StopError is returned if a Node fails to stop either any of its registered
+// services or itself.
+type StopError struct {
+ Server error
+ Services map[reflect.Type]error
+}
+
+// Error generates a textual representation of the stop error.
+func (e *StopError) Error() string {
+ return fmt.Sprintf("server: %v, services: %v", e.Server, e.Services)
+}
diff --git a/node_2/node.go b/node_2/node.go
new file mode 100644
index 000000000000..555868ecdcfb
--- /dev/null
+++ b/node_2/node.go
@@ -0,0 +1,737 @@
+// Copyright 2015 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package node_2
+
+import (
+ "errors"
+ "fmt"
+ "os"
+ "path/filepath"
+ "reflect"
+ "strings"
+ "sync"
+
+ "github.com/ethereum/go-ethereum/accounts"
+ "github.com/ethereum/go-ethereum/core/rawdb"
+ "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/ethereum/go-ethereum/internal/debug"
+ "github.com/ethereum/go-ethereum/log"
+ "github.com/ethereum/go-ethereum/p2p"
+ "github.com/ethereum/go-ethereum/rpc"
+ "github.com/prometheus/tsdb/fileutil"
+)
+
+// Node is a container on which services can be registered.
+type Node struct {
+ eventmux *event.TypeMux // Event multiplexer used between the services of a stack
+ config *Config
+ accman *accounts.Manager
+
+ ephemeralKeystore string // if non-empty, the key directory that will be removed by Stop
+ instanceDirLock fileutil.Releaser // prevents concurrent use of instance directory
+
+ server *p2p.Server // Currently running P2P networking layer
+
+ backends map[reflect.Type]Backend // TODO
+ services map[reflect.Type]Service // Currently running services
+ auxServices map[reflect.Type]AuxiliaryService // TODO
+
+ rpcAPIs []rpc.API // List of APIs currently provided by the node
+ inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
+
+ ipcHandler *httpHandler // TODO
+ httpHandler *httpHandler // TODO
+ wsHandler *httpHandler // TODO
+
+ stop chan struct{} // Channel to wait for termination notifications
+ lock sync.RWMutex
+
+ log log.Logger
+}
+
+// New creates a new P2P node, ready for protocol registration.
+func New(conf *Config) (*Node, error) {
+ // Copy config and resolve the datadir so future changes to the current
+ // working directory don't affect the node.
+ confCopy := *conf
+ conf = &confCopy
+ if conf.DataDir != "" {
+ absdatadir, err := filepath.Abs(conf.DataDir)
+ if err != nil {
+ return nil, err
+ }
+ conf.DataDir = absdatadir
+ }
+ // Ensure that the instance name doesn't cause weird conflicts with
+ // other files in the data directory.
+ if strings.ContainsAny(conf.Name, `/\`) {
+ return nil, errors.New(`Config.Name must not contain '/' or '\'`)
+ }
+ if conf.Name == datadirDefaultKeyStore {
+ return nil, errors.New(`Config.Name cannot be "` + datadirDefaultKeyStore + `"`)
+ }
+ if strings.HasSuffix(conf.Name, ".ipc") {
+ return nil, errors.New(`Config.Name cannot end in ".ipc"`)
+ }
+ // Ensure that the AccountManager method works before the node has started.
+ // We rely on this in cmd/geth.
+ am, ephemeralKeystore, err := makeAccountManager(conf)
+ if err != nil {
+ return nil, err
+ }
+ if conf.Logger == nil {
+ conf.Logger = log.New()
+ }
+ // Note: any interaction with Config that would create/touch files
+ // in the data directory or instance directory is delayed until Start.
+ return &Node{
+ accman: am,
+ ephemeralKeystore: ephemeralKeystore,
+ config: conf,
+ ipcHandler: &httpHandler{
+ endpoint: endpoint{
+ endpoint: conf.IPCEndpoint(),
+ },
+ },
+ httpHandler: &httpHandler{
+ endpoint: endpoint{
+ endpoint: conf.HTTPEndpoint(),
+ host: conf.HTTPHost,
+ port: conf.HTTPPort,
+ },
+ CorsAllowedOrigins: conf.HTTPCors,
+ Vhosts: conf.HTTPVirtualHosts,
+ Timeouts: conf.HTTPTimeouts,
+ WsOrigins: conf.WSOrigins, // TODO do i already add this?
+ RPCAllowed: true,
+
+ },
+ wsHandler: &httpHandler{
+ endpoint: endpoint{
+ endpoint: conf.WSEndpoint(),
+ host: conf.WSHost,
+ port: conf.WSPort,
+ },
+ WsOrigins: conf.WSOrigins,
+ WSAllowed: true,
+ },
+ eventmux: new(event.TypeMux),
+ log: conf.Logger,
+ }, nil
+}
+
+// Close stops the Node and releases resources acquired in
+// Node constructor New.
+func (n *Node) Close() error {
+ var errs []error
+
+ // Terminate all subsystems and collect any errors
+ if err := n.Stop(); err != nil && err != ErrNodeStopped {
+ errs = append(errs, err)
+ }
+ if err := n.accman.Close(); err != nil {
+ errs = append(errs, err)
+ }
+ // Report any errors that might have occurred
+ switch len(errs) {
+ case 0:
+ return nil
+ case 1:
+ return errs[0]
+ default:
+ return fmt.Errorf("%v", errs)
+ }
+}
+
+// Register injects a new service into the node's stack. The service created by
+// the passed constructor must be unique in its type with regard to sibling ones.
+func (n *Node) Register(constructor ServiceConstructor) error {
+ n.lock.Lock()
+ defer n.lock.Unlock()
+
+ // TODO this should create the service and add it to the maps already
+
+ //if n.server != nil {
+ // return ErrNodeRunning
+ //}
+ //n.serviceFuncs = append(n.serviceFuncs, constructor)
+ return nil
+}
+
+// Start creates a live P2P node and starts running it.
+func (n *Node) Start() error {
+ n.lock.Lock()
+ defer n.lock.Unlock()
+
+ // Short circuit if the node's already running
+ if n.server != nil {
+ return ErrNodeRunning
+ }
+ if err := n.openDataDir(); err != nil {
+ return err
+ }
+
+ // Initialize the p2p server. This creates the node key and
+ // discovery databases.
+ running := &p2p.Server{}
+
+ running.PrivateKey = n.config.NodeKey()
+ running.Name = n.config.NodeName()
+ running.Logger = n.log
+ if running.StaticNodes == nil {
+ running.StaticNodes = n.config.StaticNodes()
+ }
+ if running.TrustedNodes == nil {
+ running.TrustedNodes = n.config.TrustedNodes()
+ }
+ if running.NodeDatabase == "" {
+ running.NodeDatabase = n.config.NodeDB()
+ }
+ n.log.Info("Starting peer-to-peer node", "instance", running.Name)
+
+ // TODO document
+ backends := make(map[reflect.Type]Backend)
+ services := make(map[reflect.Type]Service)
+ auxServices := make(map[reflect.Type]AuxiliaryService)
+
+ // Gather the protocols and start the freshly assembled P2P server
+ for _, backend := range backends {
+ running.Protocols = append(running.Protocols, backend.Protocols()...)
+ }
+ if err := running.Start(); err != nil {
+ return convertFileLockError(err)
+ }
+
+ //TODO instead of constructor, make it actually construct the backends, services and aux services?
+
+ // TODO this should just check for duplicates, and then start the backends, services, and auxServices
+
+ var started []reflect.Type
+
+ // Start each of the backends
+ for kind, backend := range backends {
+ if err := backend.Start(); err != nil {
+ for _, kind := range started {
+ services[kind].Stop()
+ }
+ running.Stop()
+
+ return err
+ }
+ // Mark the service started for potential cleanup
+ started = append(started, kind)
+ }
+
+ // Start each of the services
+ for kind, service := range services {
+ // Start the next service, stopping all previous upon failure
+ if err := service.Start(); err != nil {
+ for _, kind := range started {
+ services[kind].Stop()
+ }
+ running.Stop()
+
+ return err
+ }
+ // Mark the service started for potential cleanup
+ started = append(started, kind)
+ }
+
+ // Gather all the possible APIs to surface
+ apis := n.apis()
+ for _, backend := range backends {
+ apis = append(apis, backend.APIs()...)
+ }
+ for _, service := range services {
+ apis = append(apis, service.APIs()...)
+ }
+
+ // Lastly, start the configured RPC interfaces
+ if err := n.startRPC(apis); err != nil {
+ for _, service := range services {
+ service.Stop()
+ }
+ running.Stop()
+ return err
+ }
+
+ // Finish initializing the startup
+ n.backends = backends
+ n.services = services
+ n.auxServices = auxServices
+ n.server = running
+ n.stop = make(chan struct{})
+ return nil
+}
+
+// Config returns the configuration of node.
+func (n *Node) Config() *Config {
+ return n.config
+}
+
+func (n *Node) openDataDir() error {
+ if n.config.DataDir == "" {
+ return nil // ephemeral
+ }
+
+ instdir := filepath.Join(n.config.DataDir, n.config.name())
+ if err := os.MkdirAll(instdir, 0700); err != nil {
+ return err
+ }
+ // Lock the instance directory to prevent concurrent use by another instance as well as
+ // accidental use of the instance directory as a database.
+ release, _, err := fileutil.Flock(filepath.Join(instdir, "LOCK"))
+ if err != nil {
+ return convertFileLockError(err)
+ }
+ n.instanceDirLock = release
+ return nil
+}
+
+// startRPC is a helper method to start all the various RPC endpoints during node
+// startup. It's not meant to be called at any time afterwards as it makes certain
+// assumptions about the state of the node.
+func (n *Node) startRPC(apis []rpc.API) error {
+ // Start the various API endpoints, terminating all in case of errors
+ if err := n.startInProc(apis); err != nil {
+ return err
+ }
+ if err := n.startIPC(apis); err != nil {
+ n.stopInProc()
+ return err
+ }
+ if err := n.startHTTP(n.httpEndpoint, apis, n.config.HTTPModules, n.config.HTTPCors, n.config.HTTPVirtualHosts, n.config.HTTPTimeouts, n.config.WSOrigins); err != nil {
+ n.stopIPC()
+ n.stopInProc()
+ return err
+ }
+ // if endpoints are not the same, start separate servers
+ if n.httpEndpoint != n.wsEndpoint {
+ if err := n.startWS(n.wsEndpoint, apis, n.config.WSModules, n.config.WSOrigins, n.config.WSExposeAll); err != nil {
+ n.stopHTTP()
+ n.stopIPC()
+ n.stopInProc()
+ return err
+ }
+ }
+
+ // All API endpoints started successfully
+ n.rpcAPIs = apis
+ return nil
+}
+
+// startInProc initializes an in-process RPC endpoint.
+func (n *Node) startInProc(apis []rpc.API) error {
+ // Register all the APIs exposed by the services
+ handler := rpc.NewServer()
+ for _, api := range apis {
+ if err := handler.RegisterName(api.Namespace, api.Service); err != nil {
+ return err
+ }
+ n.log.Debug("InProc registered", "namespace", api.Namespace)
+ }
+ n.inprocHandler = handler
+ return nil
+}
+
+// stopInProc terminates the in-process RPC endpoint.
+func (n *Node) stopInProc() {
+ if n.inprocHandler != nil {
+ n.inprocHandler.Stop()
+ n.inprocHandler = nil
+ }
+}
+
+// startIPC initializes and starts the IPC RPC endpoint.
+func (n *Node) startIPC(apis []rpc.API) error {
+ if n.ipcEndpoint == "" {
+ return nil // IPC disabled.
+ }
+ listener, handler, err := rpc.StartIPCEndpoint(n.ipcEndpoint, apis)
+ if err != nil {
+ return err
+ }
+ n.ipcListener = listener
+ n.ipcHandler = handler
+ n.log.Info("IPC endpoint opened", "url", n.ipcEndpoint)
+ return nil
+}
+
+// stopIPC terminates the IPC RPC endpoint.
+func (n *Node) stopIPC() {
+ if n.ipcListener != nil {
+ n.ipcListener.Close()
+ n.ipcListener = nil
+
+ n.log.Info("IPC endpoint closed", "url", n.ipcEndpoint)
+ }
+ if n.ipcHandler != nil {
+ n.ipcHandler.Stop()
+ n.ipcHandler = nil
+ }
+}
+
+// startHTTP initializes and starts the HTTP RPC endpoint.
+func (n *Node) startHTTP(endpoint string, apis []rpc.API, modules []string, cors []string, vhosts []string, timeouts rpc.HTTPTimeouts, wsOrigins []string) error {
+ // Short circuit if the HTTP endpoint isn't being exposed
+ if endpoint == "" {
+ return nil
+ }
+ // register apis and create handler stack
+ srv := rpc.NewServer()
+ err := RegisterApisFromWhitelist(apis, modules, srv, false)
+ if err != nil {
+ return err
+ }
+ handler := NewHTTPHandlerStack(srv, cors, vhosts)
+ // wrap handler in websocket handler only if websocket port is the same as http rpc
+ if n.httpEndpoint == n.wsEndpoint {
+ handler = NewWebsocketUpgradeHandler(handler, srv.WebsocketHandler(wsOrigins))
+ }
+ listener, err := StartHTTPEndpoint(endpoint, timeouts, handler)
+ if err != nil {
+ return err
+ }
+ n.log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%v/", listener.Addr()),
+ "cors", strings.Join(cors, ","),
+ "vhosts", strings.Join(vhosts, ","))
+ if n.httpEndpoint == n.wsEndpoint {
+ n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", listener.Addr()))
+ }
+ // All listeners booted successfully
+ n.httpEndpoint = endpoint
+ n.httpListener = listener
+ n.httpHandler = srv
+
+ return nil
+}
+
+// stopHTTP terminates the HTTP RPC endpoint.
+func (n *Node) stopHTTP() {
+ if n.httpListener != nil {
+ url := fmt.Sprintf("http://%v/", n.httpListener.Addr())
+ n.httpListener.Close()
+ n.httpListener = nil
+ n.log.Info("HTTP endpoint closed", "url", url)
+ }
+ if n.httpHandler != nil {
+ n.httpHandler.Stop()
+ n.httpHandler = nil
+ }
+}
+
+// startWS initializes and starts the websocket RPC endpoint.
+func (n *Node) startWS(endpoint string, apis []rpc.API, modules []string, wsOrigins []string, exposeAll bool) error {
+ // Short circuit if the WS endpoint isn't being exposed
+ if endpoint == "" {
+ return nil
+ }
+
+ srv := rpc.NewServer()
+ handler := srv.WebsocketHandler(wsOrigins)
+ err := RegisterApisFromWhitelist(apis, modules, srv, exposeAll)
+ if err != nil {
+ return err
+ }
+ listener, err := startWSEndpoint(endpoint, handler)
+ if err != nil {
+ return err
+ }
+ n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%s", listener.Addr()))
+ // All listeners booted successfully
+ n.wsEndpoint = endpoint
+ n.wsListener = listener
+ n.wsHandler = srv
+
+ return nil
+}
+
+// stopWS terminates the websocket RPC endpoint.
+func (n *Node) stopWS() {
+ if n.wsListener != nil {
+ n.wsListener.Close()
+ n.wsListener = nil
+
+ n.log.Info("WebSocket endpoint closed", "url", fmt.Sprintf("ws://%s", n.wsEndpoint))
+ }
+ if n.wsHandler != nil {
+ n.wsHandler.Stop()
+ n.wsHandler = nil
+ }
+}
+
+// Stop terminates a running node along with all it's services. In the node was
+// not started, an error is returned.
+func (n *Node) Stop() error {
+ n.lock.Lock()
+ defer n.lock.Unlock()
+
+ // Short circuit if the node's not running
+ if n.server == nil {
+ return ErrNodeStopped
+ }
+
+ // Terminate the API, services and the p2p server.
+ n.stopWS()
+ n.stopHTTP()
+ n.stopIPC()
+ n.rpcAPIs = nil
+ failure := &StopError{
+ Services: make(map[reflect.Type]error),
+ }
+ for kind, service := range n.services {
+ if err := service.Stop(); err != nil {
+ failure.Services[kind] = err
+ }
+ }
+ n.server.Stop()
+ n.services = nil
+ n.server = nil
+
+ // Release instance directory lock.
+ if n.instanceDirLock != nil {
+ if err := n.instanceDirLock.Release(); err != nil {
+ n.log.Error("Can't release datadir lock", "err", err)
+ }
+ n.instanceDirLock = nil
+ }
+
+ // unblock n.Wait
+ close(n.stop)
+
+ // Remove the keystore if it was created ephemerally.
+ var keystoreErr error
+ if n.ephemeralKeystore != "" {
+ keystoreErr = os.RemoveAll(n.ephemeralKeystore)
+ }
+
+ if len(failure.Services) > 0 {
+ return failure
+ }
+ if keystoreErr != nil {
+ return keystoreErr
+ }
+ return nil
+}
+
+// Wait blocks the thread until the node is stopped. If the node is not running
+// at the time of invocation, the method immediately returns.
+func (n *Node) Wait() {
+ n.lock.RLock()
+ if n.server == nil {
+ n.lock.RUnlock()
+ return
+ }
+ stop := n.stop
+ n.lock.RUnlock()
+
+ <-stop
+}
+
+// Restart terminates a running node and boots up a new one in its place. If the
+// node isn't running, an error is returned.
+func (n *Node) Restart() error {
+ if err := n.Stop(); err != nil {
+ return err
+ }
+ if err := n.Start(); err != nil {
+ return err
+ }
+ return nil
+}
+
+// Attach creates an RPC client attached to an in-process API handler.
+func (n *Node) Attach() (*rpc.Client, error) {
+ n.lock.RLock()
+ defer n.lock.RUnlock()
+
+ if n.server == nil {
+ return nil, ErrNodeStopped
+ }
+ return rpc.DialInProc(n.inprocHandler), nil
+}
+
+// RPCHandler returns the in-process RPC request handler.
+func (n *Node) RPCHandler() (*rpc.Server, error) {
+ n.lock.RLock()
+ defer n.lock.RUnlock()
+
+ if n.inprocHandler == nil {
+ return nil, ErrNodeStopped
+ }
+ return n.inprocHandler, nil
+}
+
+// Server retrieves the currently running P2P network layer. This method is meant
+// only to inspect fields of the currently running server, life cycle management
+// should be left to this Node entity.
+func (n *Node) Server() *p2p.Server {
+ n.lock.RLock()
+ defer n.lock.RUnlock()
+
+ return n.server
+}
+
+// Service retrieves a currently running service registered of a specific type.
+func (n *Node) Service(service interface{}) error {
+ n.lock.RLock()
+ defer n.lock.RUnlock()
+
+ // Short circuit if the node's not running
+ if n.server == nil {
+ return ErrNodeStopped
+ }
+ // Otherwise try to find the service to return
+ element := reflect.ValueOf(service).Elem()
+ if running, ok := n.services[element.Type()]; ok {
+ element.Set(reflect.ValueOf(running))
+ return nil
+ }
+ return ErrServiceUnknown
+}
+
+// DataDir retrieves the current datadir used by the protocol stack.
+// Deprecated: No files should be stored in this directory, use InstanceDir instead.
+func (n *Node) DataDir() string {
+ return n.config.DataDir
+}
+
+// InstanceDir retrieves the instance directory used by the protocol stack.
+func (n *Node) InstanceDir() string {
+ return n.config.instanceDir()
+}
+
+// AccountManager retrieves the account manager used by the protocol stack.
+func (n *Node) AccountManager() *accounts.Manager {
+ return n.accman
+}
+
+// IPCEndpoint retrieves the current IPC endpoint used by the protocol stack.
+func (n *Node) IPCEndpoint() string {
+ return n.ipcEndpoint
+}
+
+// HTTPEndpoint retrieves the current HTTP endpoint used by the protocol stack.
+func (n *Node) HTTPEndpoint() string {
+ n.lock.Lock()
+ defer n.lock.Unlock()
+
+ if n.httpListener != nil {
+ return n.httpListener.Addr().String()
+ }
+ return n.httpEndpoint
+}
+
+// WSEndpoint retrieves the current WS endpoint used by the protocol stack.
+func (n *Node) WSEndpoint() string {
+ n.lock.Lock()
+ defer n.lock.Unlock()
+
+ if n.wsListener != nil {
+ return n.wsListener.Addr().String()
+ }
+ return n.wsEndpoint
+}
+
+// EventMux retrieves the event multiplexer used by all the network services in
+// the current protocol stack.
+func (n *Node) EventMux() *event.TypeMux {
+ return n.eventmux
+}
+
+// OpenDatabase opens an existing database with the given name (or creates one if no
+// previous can be found) from within the node's instance directory. If the node is
+// ephemeral, a memory database is returned.
+func (n *Node) OpenDatabase(name string, cache, handles int, namespace string) (ethdb.Database, error) {
+ if n.config.DataDir == "" {
+ return rawdb.NewMemoryDatabase(), nil
+ }
+ return rawdb.NewLevelDBDatabase(n.config.ResolvePath(name), cache, handles, namespace)
+}
+
+// OpenDatabaseWithFreezer opens an existing database with the given name (or
+// creates one if no previous can be found) from within the node's data directory,
+// also attaching a chain freezer to it that moves ancient chain data from the
+// database to immutable append-only files. If the node is an ephemeral one, a
+// memory database is returned.
+func (n *Node) OpenDatabaseWithFreezer(name string, cache, handles int, freezer, namespace string) (ethdb.Database, error) {
+ if n.config.DataDir == "" {
+ return rawdb.NewMemoryDatabase(), nil
+ }
+ root := n.config.ResolvePath(name)
+
+ switch {
+ case freezer == "":
+ freezer = filepath.Join(root, "ancient")
+ case !filepath.IsAbs(freezer):
+ freezer = n.config.ResolvePath(freezer)
+ }
+ return rawdb.NewLevelDBDatabaseWithFreezer(root, cache, handles, freezer, namespace)
+}
+
+// ResolvePath returns the absolute path of a resource in the instance directory.
+func (n *Node) ResolvePath(x string) string {
+ return n.config.ResolvePath(x)
+}
+
+// apis returns the collection of RPC descriptors this node offers.
+func (n *Node) apis() []rpc.API {
+ return []rpc.API{
+ {
+ Namespace: "admin",
+ Version: "1.0",
+ Service: NewPrivateAdminAPI(n),
+ }, {
+ Namespace: "admin",
+ Version: "1.0",
+ Service: NewPublicAdminAPI(n),
+ Public: true,
+ }, {
+ Namespace: "debug",
+ Version: "1.0",
+ Service: debug.Handler,
+ }, {
+ Namespace: "web3",
+ Version: "1.0",
+ Service: NewPublicWeb3API(n),
+ Public: true,
+ },
+ }
+}
+
+// RegisterApisFromWhitelist checks the given modules' availability, generates a whitelist based on the allowed modules,
+// and then registers all of the APIs exposed by the services.
+func RegisterApisFromWhitelist(apis []rpc.API, modules []string, srv *rpc.Server, exposeAll bool) error {
+ if bad, available := checkModuleAvailability(modules, apis); len(bad) > 0 {
+ log.Error("Unavailable modules in HTTP API list", "unavailable", bad, "available", available)
+ }
+ // Generate the whitelist based on the allowed modules
+ whitelist := make(map[string]bool)
+ for _, module := range modules {
+ whitelist[module] = true
+ }
+ // Register all the APIs exposed by the services
+ for _, api := range apis {
+ if exposeAll || whitelist[api.Namespace] || (len(whitelist) == 0 && api.Public) {
+ if err := srv.RegisterName(api.Namespace, api.Service); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
diff --git a/node_2/rpcstack.go b/node_2/rpcstack.go
new file mode 100644
index 000000000000..cec762c0633a
--- /dev/null
+++ b/node_2/rpcstack.go
@@ -0,0 +1,185 @@
+// Copyright 2020 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package node_2
+
+import (
+ "compress/gzip"
+ "github.com/ethereum/go-ethereum/rpc"
+ "io"
+ "io/ioutil"
+ "net"
+ "net/http"
+ "strings"
+ "sync"
+
+ "github.com/ethereum/go-ethereum/log"
+ "github.com/rs/cors"
+)
+
+type httpHandler struct {
+ handler http.Handler
+ Srv *rpc.Server
+
+ endpoint endpoint
+
+ Whitelist []string
+
+ CorsAllowedOrigins []string
+ Vhosts []string
+ WsOrigins []string
+ Timeouts rpc.HTTPTimeouts
+
+ Listener net.Listener
+
+ RPCAllowed bool
+ WSAllowed bool
+}
+
+type endpoint struct {
+ endpoint string
+ host string
+ port int
+}
+
+// NewHTTPHandlerStack returns wrapped http-related handlers
+func NewHTTPHandlerStack(srv http.Handler, cors []string, vhosts []string) http.Handler {
+ // Wrap the CORS-handler within a host-handler
+ handler := newCorsHandler(srv, cors)
+ handler = newVHostHandler(vhosts, handler)
+ return newGzipHandler(handler)
+}
+
+func newCorsHandler(srv http.Handler, allowedOrigins []string) http.Handler {
+ // disable CORS support if user has not specified a custom CORS configuration
+ if len(allowedOrigins) == 0 {
+ return srv
+ }
+ c := cors.New(cors.Options{
+ AllowedOrigins: allowedOrigins,
+ AllowedMethods: []string{http.MethodPost, http.MethodGet},
+ MaxAge: 600,
+ AllowedHeaders: []string{"*"},
+ })
+ return c.Handler(srv)
+}
+
+// virtualHostHandler is a handler which validates the Host-header of incoming requests.
+// Using virtual hosts can help prevent DNS rebinding attacks, where a 'random' domain name points to
+// the service ip address (but without CORS headers). By verifying the targeted virtual host, we can
+// ensure that it's a destination that the node operator has defined.
+type virtualHostHandler struct {
+ vhosts map[string]struct{}
+ next http.Handler
+}
+
+func newVHostHandler(vhosts []string, next http.Handler) http.Handler {
+ vhostMap := make(map[string]struct{})
+ for _, allowedHost := range vhosts {
+ vhostMap[strings.ToLower(allowedHost)] = struct{}{}
+ }
+ return &virtualHostHandler{vhostMap, next}
+}
+
+// ServeHTTP serves JSON-RPC requests over HTTP, implements http.Handler
+func (h *virtualHostHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ // if r.Host is not set, we can continue serving since a browser would set the Host header
+ if r.Host == "" {
+ h.next.ServeHTTP(w, r)
+ return
+ }
+ host, _, err := net.SplitHostPort(r.Host)
+ if err != nil {
+ // Either invalid (too many colons) or no port specified
+ host = r.Host
+ }
+ if ipAddr := net.ParseIP(host); ipAddr != nil {
+ // It's an IP address, we can serve that
+ h.next.ServeHTTP(w, r)
+ return
+
+ }
+ // Not an IP address, but a hostname. Need to validate
+ if _, exist := h.vhosts["*"]; exist {
+ h.next.ServeHTTP(w, r)
+ return
+ }
+ if _, exist := h.vhosts[host]; exist {
+ h.next.ServeHTTP(w, r)
+ return
+ }
+ http.Error(w, "invalid host specified", http.StatusForbidden)
+}
+
+var gzPool = sync.Pool{
+ New: func() interface{} {
+ w := gzip.NewWriter(ioutil.Discard)
+ return w
+ },
+}
+
+type gzipResponseWriter struct {
+ io.Writer
+ http.ResponseWriter
+}
+
+func (w *gzipResponseWriter) WriteHeader(status int) {
+ w.Header().Del("Content-Length")
+ w.ResponseWriter.WriteHeader(status)
+}
+
+func (w *gzipResponseWriter) Write(b []byte) (int, error) {
+ return w.Writer.Write(b)
+}
+
+func newGzipHandler(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
+ next.ServeHTTP(w, r)
+ return
+ }
+
+ w.Header().Set("Content-Encoding", "gzip")
+
+ gz := gzPool.Get().(*gzip.Writer)
+ defer gzPool.Put(gz)
+
+ gz.Reset(w)
+ defer gz.Close()
+
+ next.ServeHTTP(&gzipResponseWriter{ResponseWriter: w, Writer: gz}, r)
+ })
+}
+
+// NewWebsocketUpgradeHandler returns a websocket handler that serves an incoming request only if it contains an upgrade
+// request to the websocket protocol. If not, serves the the request with the http handler.
+func NewWebsocketUpgradeHandler(h http.Handler, ws http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if isWebsocket(r) {
+ ws.ServeHTTP(w, r)
+ log.Debug("serving websocket request")
+ return
+ }
+
+ h.ServeHTTP(w, r)
+ })
+}
+
+// isWebsocket checks the header of an http request for a websocket upgrade request.
+func isWebsocket(r *http.Request) bool {
+ return strings.ToLower(r.Header.Get("Upgrade")) == "websocket" &&
+ strings.ToLower(r.Header.Get("Connection")) == "upgrade"
+}
diff --git a/node_2/service.go b/node_2/service.go
new file mode 100644
index 000000000000..aabafa0737b9
--- /dev/null
+++ b/node_2/service.go
@@ -0,0 +1,133 @@
+// Copyright 2015 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package node_2
+
+import (
+ "path/filepath"
+ "reflect"
+
+ "github.com/ethereum/go-ethereum/accounts"
+ "github.com/ethereum/go-ethereum/core/rawdb"
+ "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/ethereum/go-ethereum/p2p"
+ "github.com/ethereum/go-ethereum/rpc"
+)
+
+// ServiceContext is a collection of service independent options inherited from
+// the protocol stack, that is passed to all constructors to be optionally used;
+// as well as utility methods to operate on the service environment.
+type ServiceContext struct {
+ services map[reflect.Type]Service // Index of the already constructed services
+ Config Config
+ EventMux *event.TypeMux // Event multiplexer used for decoupled notifications
+ AccountManager *accounts.Manager // Account manager created by the node.
+}
+
+// OpenDatabase opens an existing database with the given name (or creates one
+// if no previous can be found) from within the node's data directory. If the
+// node is an ephemeral one, a memory database is returned.
+func (ctx *ServiceContext) OpenDatabase(name string, cache int, handles int, namespace string) (ethdb.Database, error) {
+ if ctx.Config.DataDir == "" {
+ return rawdb.NewMemoryDatabase(), nil
+ }
+ return rawdb.NewLevelDBDatabase(ctx.Config.ResolvePath(name), cache, handles, namespace)
+}
+
+// OpenDatabaseWithFreezer opens an existing database with the given name (or
+// creates one if no previous can be found) from within the node's data directory,
+// also attaching a chain freezer to it that moves ancient chain data from the
+// database to immutable append-only files. If the node is an ephemeral one, a
+// memory database is returned.
+func (ctx *ServiceContext) OpenDatabaseWithFreezer(name string, cache int, handles int, freezer string, namespace string) (ethdb.Database, error) {
+ if ctx.Config.DataDir == "" {
+ return rawdb.NewMemoryDatabase(), nil
+ }
+ root := ctx.Config.ResolvePath(name)
+
+ switch {
+ case freezer == "":
+ freezer = filepath.Join(root, "ancient")
+ case !filepath.IsAbs(freezer):
+ freezer = ctx.Config.ResolvePath(freezer)
+ }
+ return rawdb.NewLevelDBDatabaseWithFreezer(root, cache, handles, freezer, namespace)
+}
+
+// ResolvePath resolves a user path into the data directory if that was relative
+// and if the user actually uses persistent storage. It will return an empty string
+// for emphemeral storage and the user's own input for absolute paths.
+func (ctx *ServiceContext) ResolvePath(path string) string {
+ return ctx.Config.ResolvePath(path)
+}
+
+// Service retrieves a currently running service registered of a specific type.
+func (ctx *ServiceContext) Service(service interface{}) error {
+ element := reflect.ValueOf(service).Elem()
+ if running, ok := ctx.services[element.Type()]; ok {
+ element.Set(reflect.ValueOf(running))
+ return nil
+ }
+ return ErrServiceUnknown
+}
+
+// ExtRPCEnabled returns the indicator whether node enables the external
+// RPC(http, ws or graphql).
+func (ctx *ServiceContext) ExtRPCEnabled() bool {
+ return ctx.Config.ExtRPCEnabled()
+}
+
+// ServiceConstructor is the function signature of the constructors needed to be
+// registered for service instantiation.
+type ServiceConstructor func(ctx *ServiceContext) (Service, error)
+
+// Backend is an individual protocol that can be registered into a node.
+//
+// Notes:
+//
+// • Backend service life-cycle management is delegated to the node. The backend service is allowed to
+// initialize itself upon creation, but no goroutines should be spun up outside of the
+// Start method.
+type Backend interface {
+ // Protocols retrieves the P2P protocols the service wishes to start.
+ Protocols() []p2p.Protocol
+
+ Service
+}
+
+// TODO document
+type Service interface {
+ // APIs retrieves the list of RPC descriptors the service provides
+ APIs() []rpc.API
+
+ // Start is called after all services have been constructed and the networking
+ // layer was also initialized to spawn any goroutines required by the service.
+ Start() error
+
+ // Stop terminates all goroutines belonging to the service, blocking until they
+ // are all terminated.
+ Stop() error
+}
+
+// TODO document
+type AuxiliaryService interface {
+ Start() error
+
+ Stop() error
+}
+
+
From d44ac535ea88fb464c19d25ed9d1d88d6e5aa438 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Mon, 20 Apr 2020 16:59:42 +0200
Subject: [PATCH 002/160] httpHandler -> httpServer
---
node_2/node.go | 12 ++++++------
node_2/rpcstack.go | 2 +-
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/node_2/node.go b/node_2/node.go
index 555868ecdcfb..9668fee80f81 100644
--- a/node_2/node.go
+++ b/node_2/node.go
@@ -54,9 +54,9 @@ type Node struct {
rpcAPIs []rpc.API // List of APIs currently provided by the node
inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
- ipcHandler *httpHandler // TODO
- httpHandler *httpHandler // TODO
- wsHandler *httpHandler // TODO
+ ipcHandler *httpServer // TODO
+ httpHandler *httpServer // TODO
+ wsHandler *httpServer // TODO
stop chan struct{} // Channel to wait for termination notifications
lock sync.RWMutex
@@ -103,12 +103,12 @@ func New(conf *Config) (*Node, error) {
accman: am,
ephemeralKeystore: ephemeralKeystore,
config: conf,
- ipcHandler: &httpHandler{
+ ipcHandler: &httpServer{
endpoint: endpoint{
endpoint: conf.IPCEndpoint(),
},
},
- httpHandler: &httpHandler{
+ httpHandler: &httpServer{
endpoint: endpoint{
endpoint: conf.HTTPEndpoint(),
host: conf.HTTPHost,
@@ -121,7 +121,7 @@ func New(conf *Config) (*Node, error) {
RPCAllowed: true,
},
- wsHandler: &httpHandler{
+ wsHandler: &httpServer{
endpoint: endpoint{
endpoint: conf.WSEndpoint(),
host: conf.WSHost,
diff --git a/node_2/rpcstack.go b/node_2/rpcstack.go
index cec762c0633a..eb3928655782 100644
--- a/node_2/rpcstack.go
+++ b/node_2/rpcstack.go
@@ -30,7 +30,7 @@ import (
"github.com/rs/cors"
)
-type httpHandler struct {
+type httpServer struct {
handler http.Handler
Srv *rpc.Server
From ec0c79155fd39a9750bfbaa1fe19eb4d8c691ce4 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Thu, 23 Apr 2020 14:49:12 +0200
Subject: [PATCH 003/160] saving progress, working on ethstats impl
---
cmd/faucet/faucet.go | 7 +-
cmd/utils/flags.go | 4 +-
ethstats/ethstats.go | 20 +-
node/node.go | 132 +++++---
node/rpcstack.go | 25 ++
node/service.go | 36 ++-
node_2/api.go | 317 -------------------
node_2/config.go | 545 --------------------------------
node_2/defaults.go | 113 -------
node_2/endpoints.go | 99 ------
node_2/errors.go | 63 ----
node_2/node.go | 737 -------------------------------------------
node_2/rpcstack.go | 185 -----------
node_2/service.go | 133 --------
14 files changed, 158 insertions(+), 2258 deletions(-)
delete mode 100644 node_2/api.go
delete mode 100644 node_2/config.go
delete mode 100644 node_2/defaults.go
delete mode 100644 node_2/endpoints.go
delete mode 100644 node_2/errors.go
delete mode 100644 node_2/node.go
delete mode 100644 node_2/rpcstack.go
delete mode 100644 node_2/service.go
diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go
index 5a905c4f129a..475430e7f95a 100644
--- a/cmd/faucet/faucet.go
+++ b/cmd/faucet/faucet.go
@@ -236,7 +236,7 @@ func newFaucet(genesis *core.Genesis, port int, enodes []*discv5.Node, network u
return nil, err
}
// Assemble the Ethereum light client protocol
- if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
+ if err := stack.RegisterBackendLifecycle(func(stack *node.Node) (node.Backend, error) {
cfg := eth.DefaultConfig
cfg.SyncMode = downloader.LightSync
cfg.NetworkId = network
@@ -247,10 +247,9 @@ func newFaucet(genesis *core.Genesis, port int, enodes []*discv5.Node, network u
}
// Assemble the ethstats monitoring and reporting service'
if stats != "" {
- if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
+ if err := stack.RegisterAuxServiceLifecycle(func(stack *node.Node) (node.AuxiliaryService, error) {
var serv *les.LightEthereum
- ctx.Service(&serv)
- return ethstats.New(stats, nil, serv)
+ return ethstats.New(stack, stats, nil, serv)
}); err != nil {
return nil, err
}
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index 68c3449fe544..e179cb9669c9 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -1725,7 +1725,7 @@ func RegisterShhService(stack *node.Node, cfg *whisper.Config) {
// RegisterEthStatsService configures the Ethereum Stats daemon and adds it to
// the given node.
func RegisterEthStatsService(stack *node.Node, url string) {
- if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
+ if err := stack.Register(func(stack *node.Node) (node.AuxiliaryService, error) {
// Retrieve both eth and les services
var ethServ *eth.Ethereum
ctx.Service(ðServ)
@@ -1742,7 +1742,7 @@ func RegisterEthStatsService(stack *node.Node, url string) {
// RegisterGraphQLService is a utility function to construct a new service and register it against a node.
func RegisterGraphQLService(stack *node.Node, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) {
- if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
+ if err := stack.RegisterAuxServiceLifecycle(func(stack *node.Node) (node.AuxiliaryService, error) {
// Try to construct the GraphQL service backed by a full node
var ethServ *eth.Ethereum
if err := ctx.Service(ðServ); err == nil {
diff --git a/ethstats/ethstats.go b/ethstats/ethstats.go
index b60ac56eabce..7d630f7b9cf7 100644
--- a/ethstats/ethstats.go
+++ b/ethstats/ethstats.go
@@ -22,6 +22,7 @@ import (
"encoding/json"
"errors"
"fmt"
+ "github.com/ethereum/go-ethereum/node"
"math/big"
"net/http"
"regexp"
@@ -40,7 +41,6 @@ import (
"github.com/ethereum/go-ethereum/les"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p"
- "github.com/ethereum/go-ethereum/rpc"
"github.com/gorilla/websocket"
)
@@ -83,7 +83,7 @@ type Service struct {
}
// New returns a monitoring service ready for stats reporting.
-func New(url string, ethServ *eth.Ethereum, lesServ *les.LightEthereum) (*Service, error) {
+func New(node *node.Node, url string, ethServ *eth.Ethereum, lesServ *les.LightEthereum) (node.AuxiliaryService, error) {
// Parse the netstats connection url
re := regexp.MustCompile("([^:@]*)(:([^@]*))?@(.+)")
parts := re.FindStringSubmatch(url)
@@ -98,6 +98,7 @@ func New(url string, ethServ *eth.Ethereum, lesServ *les.LightEthereum) (*Servic
engine = lesServ.Engine()
}
return &Service{
+ server: node.Server(),
eth: ethServ,
les: lesServ,
engine: engine,
@@ -109,17 +110,8 @@ func New(url string, ethServ *eth.Ethereum, lesServ *les.LightEthereum) (*Servic
}, nil
}
-// Protocols implements node.Service, returning the P2P network protocols used
-// by the stats service (nil as it doesn't use the devp2p overlay network).
-func (s *Service) Protocols() []p2p.Protocol { return nil }
-
-// APIs implements node.Service, returning the RPC API endpoints provided by the
-// stats service (nil as it doesn't provide any user callable APIs).
-func (s *Service) APIs() []rpc.API { return nil }
-
// Start implements node.Service, starting up the monitoring and reporting daemon.
-func (s *Service) Start(server *p2p.Server) error {
- s.server = server
+func (s *Service) Start() error {
go s.loop()
log.Info("Stats daemon started")
@@ -132,6 +124,10 @@ func (s *Service) Stop() error {
return nil
}
+func (s *Service) Server() (*node.HttpServer, error) {
+ return nil, nil
+}
+
// loop keeps trying to connect to the netstats server, reporting chain events
// until termination.
func (s *Service) loop() {
diff --git a/node/node.go b/node/node.go
index 329ff425b98a..14bc99b726bc 100644
--- a/node/node.go
+++ b/node/node.go
@@ -20,8 +20,6 @@ import (
"context"
"errors"
"fmt"
- "net"
- "net/http"
"os"
"path/filepath"
"reflect"
@@ -48,29 +46,23 @@ type Node struct {
ephemeralKeystore string // if non-empty, the key directory that will be removed by Stop
instanceDirLock fileutil.Releaser // prevents concurrent use of instance directory
- serverConfig p2p.Config
+ // TODO: removed p2pConfig b/c p2pServer already contains p2pConfig (is there a reason for it to be duplicated?
server *p2p.Server // Currently running P2P networking layer
- serviceFuncs []ServiceConstructor // Service constructors (in dependency order)
- services map[reflect.Type]Service // Currently running services
+ serviceConstructors []ServiceConstructor // Service constructors (in dependency order)
+ auxServiceConstructors []AuxiliarServiceConstructor // AuxiliaryService constructors
+
+ backend Backend // The registered Backend of the node
+ services map[reflect.Type]Service // Currently running services
+ auxServices map[reflect.Type]AuxiliaryService // Currently running auxiliary services
rpcAPIs []rpc.API // List of APIs currently provided by the node
inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
- ipcEndpoint string // IPC endpoint to listen at (empty = IPC disabled)
- ipcListener net.Listener // IPC RPC listener socket to serve API requests
- ipcHandler *rpc.Server // IPC RPC request handler to process the API requests
-
- httpEndpoint string // HTTP endpoint (interface + port) to listen at (empty = HTTP disabled)
- httpWhitelist []string // HTTP RPC modules to allow through this endpoint
- httpListenerAddr net.Addr // Address of HTTP RPC listener socket serving API requests
- httpServer *http.Server // HTTP RPC HTTP server
- httpHandler *rpc.Server // HTTP RPC request handler to process the API requests
+ ipcHandler *HttpServer // TODO
+ httpHandler *HttpServer // TODO
+ wsHandler *HttpServer // TODO
- wsEndpoint string // WebSocket endpoint (interface + port) to listen at (empty = WebSocket disabled)
- wsListenerAddr net.Addr // Address of WebSocket RPC listener socket serving API requests
- wsHTTPServer *http.Server // WebSocket RPC HTTP server
- wsHandler *rpc.Server // WebSocket RPC request handler to process the API requests
stop chan struct{} // Channel to wait for termination notifications
lock sync.RWMutex
@@ -149,19 +141,73 @@ func (n *Node) Close() error {
}
}
+// TODO document
+func (n * Node) RegisterBackendLifecycle(constructor BackendConstructor) error {
+ n.lock.Lock()
+ defer n.lock.Unlock()
+
+ if n.running() {
+ return ErrNodeRunning
+ }
+
+ backend, err := constructor(n)
+ if err != nil {
+ return err
+ }
+ n.backend = backend
+ return nil
+}
+
// Register injects a new service into the node's stack. The service created by
// the passed constructor must be unique in its type with regard to sibling ones.
-func (n *Node) Register(constructor ServiceConstructor) error {
+func (n *Node) RegisterServiceLifecycle(constructor ServiceConstructor) error {
n.lock.Lock()
defer n.lock.Unlock()
- if n.server != nil {
+ if n.running() {
+ return ErrNodeRunning
+ }
+
+ service, err := constructor(n)
+ if err != nil {
+ return err
+ }
+ kind := reflect.TypeOf(service)
+ if _, exists := n.services[kind]; exists {
+ return &DuplicateServiceError{Kind: kind}
+ }
+ n.services[kind] = service
+
+ return nil
+}
+
+// TODO document
+func (n *Node) RegisterAuxServiceLifecycle(constructor AuxiliaryServiceConstructor) error {
+ n.lock.Lock()
+ defer n.lock.Unlock()
+
+ if n.running() {
return ErrNodeRunning
}
- n.serviceFuncs = append(n.serviceFuncs, constructor)
+
+ service, err := constructor(n)
+ if err != nil {
+ return err
+ }
+ kind := reflect.TypeOf(service)
+ if _, exists := n.auxServices[kind]; exists {
+ return &DuplicateServiceError{Kind: kind}
+ }
+ n.auxServices[kind] = service
+
return nil
}
+// running returns true if the node's p2p server is already running
+func (n *Node) running() bool {
+ return n.server != nil
+}
+
// Start creates a live P2P node and starts running it.
func (n *Node) Start() error {
n.lock.Lock()
@@ -195,28 +241,28 @@ func (n *Node) Start() error {
// Otherwise copy and specialize the P2P configuration
services := make(map[reflect.Type]Service)
- for _, constructor := range n.serviceFuncs {
- // Create a new context for the particular service
- ctx := &ServiceContext{
- Config: *n.config,
- services: make(map[reflect.Type]Service),
- EventMux: n.eventmux,
- AccountManager: n.accman,
- }
- for kind, s := range services { // copy needed for threaded access
- ctx.services[kind] = s
- }
- // Construct and save the service
- service, err := constructor(ctx)
- if err != nil {
- return err
- }
- kind := reflect.TypeOf(service)
- if _, exists := services[kind]; exists {
- return &DuplicateServiceError{Kind: kind}
- }
- services[kind] = service
- }
+ //for _, constructor := range n.serviceFuncs {
+ // // Create a new context for the particular service
+ // ctx := &ServiceContext{
+ // Config: *n.config,
+ // services: make(map[reflect.Type]Service),
+ // EventMux: n.eventmux,
+ // AccountManager: n.accman,
+ // }
+ // for kind, s := range services { // copy needed for threaded access
+ // ctx.services[kind] = s
+ // }
+ // // Construct and save the service
+ // service, err := constructor(ctx)
+ // if err != nil {
+ // return err
+ // }
+ // kind := reflect.TypeOf(service)
+ // if _, exists := services[kind]; exists {
+ // return &DuplicateServiceError{Kind: kind}
+ // }
+ // services[kind] = service
+ //}
// Gather the protocols and start the freshly assembled P2P server
for _, service := range services {
running.Protocols = append(running.Protocols, service.Protocols()...)
diff --git a/node/rpcstack.go b/node/rpcstack.go
index 70aa0d4555e6..86c7b6fd683e 100644
--- a/node/rpcstack.go
+++ b/node/rpcstack.go
@@ -18,6 +18,7 @@ package node
import (
"compress/gzip"
+ "github.com/ethereum/go-ethereum/rpc"
"io"
"io/ioutil"
"net"
@@ -29,6 +30,30 @@ import (
"github.com/rs/cors"
)
+type HttpServer struct {
+ handler http.Handler
+ Srv *rpc.Server
+ Listener net.Listener
+
+ endpoint endpoint
+
+ Whitelist []string
+
+ CorsAllowedOrigins []string
+ Vhosts []string
+ WsOrigins []string
+ Timeouts rpc.HTTPTimeouts
+
+ RPCAllowed bool
+ WSAllowed bool
+}
+
+type endpoint struct {
+ endpoint string
+ host string
+ port int
+}
+
// NewHTTPHandlerStack returns wrapped http-related handlers
func NewHTTPHandlerStack(srv http.Handler, cors []string, vhosts []string) http.Handler {
// Wrap the CORS-handler within a host-handler
diff --git a/node/service.go b/node/service.go
index ef5b995e4b39..94bb012c699e 100644
--- a/node/service.go
+++ b/node/service.go
@@ -91,9 +91,23 @@ func (ctx *ServiceContext) ExtRPCEnabled() bool {
return ctx.Config.ExtRPCEnabled()
}
+// TODO document
+type BackendConstructor func(node *Node) (Backend, error)
+
// ServiceConstructor is the function signature of the constructors needed to be
// registered for service instantiation.
-type ServiceConstructor func(ctx *ServiceContext) (Service, error)
+type ServiceConstructor func(node *Node) (Service, error)
+
+//TODO document
+type AuxiliaryServiceConstructor func(node *Node) (AuxiliaryService, error)
+
+type Backend interface {
+ // Protocols retrieves the P2P protocols the service wishes to start.
+ Protocols() []p2p.Protocol
+
+ // Backend also implements the Service interface.
+ Service
+}
// Service is an individual protocol that can be registered into a node.
//
@@ -106,15 +120,27 @@ type ServiceConstructor func(ctx *ServiceContext) (Service, error)
// • Restart logic is not required as the node will create a fresh instance
// every time a service is started.
type Service interface {
- // Protocols retrieves the P2P protocols the service wishes to start.
- Protocols() []p2p.Protocol
-
// APIs retrieves the list of RPC descriptors the service provides
APIs() []rpc.API
+ // Service also implements Lifecycle
+ Lifecycle
+}
+
+// TODO document
+type AuxiliaryService interface {
+ // TODO document
+ Server() (*HttpServer, error)
+
+ // AuxiliaryService also implements Lifecycle
+ Lifecycle
+}
+
+// TODO, this might be overkill
+type Lifecycle interface {
// Start is called after all services have been constructed and the networking
// layer was also initialized to spawn any goroutines required by the service.
- Start(server *p2p.Server) error
+ Start() error
// Stop terminates all goroutines belonging to the service, blocking until they
// are all terminated.
diff --git a/node_2/api.go b/node_2/api.go
deleted file mode 100644
index 53f4f2dbc9c1..000000000000
--- a/node_2/api.go
+++ /dev/null
@@ -1,317 +0,0 @@
-// Copyright 2015 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package node_2
-
-import (
- "context"
- "fmt"
- "strings"
-
- "github.com/ethereum/go-ethereum/common/hexutil"
- "github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/p2p"
- "github.com/ethereum/go-ethereum/p2p/enode"
- "github.com/ethereum/go-ethereum/rpc"
-)
-
-// PrivateAdminAPI is the collection of administrative API methods exposed only
-// over a secure RPC channel.
-type PrivateAdminAPI struct {
- node *Node // Node interfaced by this API
-}
-
-// NewPrivateAdminAPI creates a new API definition for the private admin methods
-// of the node itself.
-func NewPrivateAdminAPI(node *Node) *PrivateAdminAPI {
- return &PrivateAdminAPI{node: node}
-}
-
-// AddPeer requests connecting to a remote node, and also maintaining the new
-// connection at all times, even reconnecting if it is lost.
-func (api *PrivateAdminAPI) AddPeer(url string) (bool, error) {
- // Make sure the server is running, fail otherwise
- server := api.node.Server()
- if server == nil {
- return false, ErrNodeStopped
- }
- // Try to add the url as a static peer and return
- node, err := enode.Parse(enode.ValidSchemes, url)
- if err != nil {
- return false, fmt.Errorf("invalid enode: %v", err)
- }
- server.AddPeer(node)
- return true, nil
-}
-
-// RemovePeer disconnects from a remote node if the connection exists
-func (api *PrivateAdminAPI) RemovePeer(url string) (bool, error) {
- // Make sure the server is running, fail otherwise
- server := api.node.Server()
- if server == nil {
- return false, ErrNodeStopped
- }
- // Try to remove the url as a static peer and return
- node, err := enode.Parse(enode.ValidSchemes, url)
- if err != nil {
- return false, fmt.Errorf("invalid enode: %v", err)
- }
- server.RemovePeer(node)
- return true, nil
-}
-
-// AddTrustedPeer allows a remote node to always connect, even if slots are full
-func (api *PrivateAdminAPI) AddTrustedPeer(url string) (bool, error) {
- // Make sure the server is running, fail otherwise
- server := api.node.Server()
- if server == nil {
- return false, ErrNodeStopped
- }
- node, err := enode.Parse(enode.ValidSchemes, url)
- if err != nil {
- return false, fmt.Errorf("invalid enode: %v", err)
- }
- server.AddTrustedPeer(node)
- return true, nil
-}
-
-// RemoveTrustedPeer removes a remote node from the trusted peer set, but it
-// does not disconnect it automatically.
-func (api *PrivateAdminAPI) RemoveTrustedPeer(url string) (bool, error) {
- // Make sure the server is running, fail otherwise
- server := api.node.Server()
- if server == nil {
- return false, ErrNodeStopped
- }
- node, err := enode.Parse(enode.ValidSchemes, url)
- if err != nil {
- return false, fmt.Errorf("invalid enode: %v", err)
- }
- server.RemoveTrustedPeer(node)
- return true, nil
-}
-
-// PeerEvents creates an RPC subscription which receives peer events from the
-// node's p2p.Server
-func (api *PrivateAdminAPI) PeerEvents(ctx context.Context) (*rpc.Subscription, error) {
- // Make sure the server is running, fail otherwise
- server := api.node.Server()
- if server == nil {
- return nil, ErrNodeStopped
- }
-
- // Create the subscription
- notifier, supported := rpc.NotifierFromContext(ctx)
- if !supported {
- return nil, rpc.ErrNotificationsUnsupported
- }
- rpcSub := notifier.CreateSubscription()
-
- go func() {
- events := make(chan *p2p.PeerEvent)
- sub := server.SubscribeEvents(events)
- defer sub.Unsubscribe()
-
- for {
- select {
- case event := <-events:
- notifier.Notify(rpcSub.ID, event)
- case <-sub.Err():
- return
- case <-rpcSub.Err():
- return
- case <-notifier.Closed():
- return
- }
- }
- }()
-
- return rpcSub, nil
-}
-
-// StartRPC starts the HTTP RPC API server.
-func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis *string, vhosts *string) (bool, error) {
- api.node.lock.Lock()
- defer api.node.lock.Unlock()
-
- if api.node.httpHandler != nil {
- return false, fmt.Errorf("HTTP RPC already running on %s", api.node.httpEndpoint)
- }
-
- if host == nil {
- h := DefaultHTTPHost
- if api.node.config.HTTPHost != "" {
- h = api.node.config.HTTPHost
- }
- host = &h
- }
- if port == nil {
- port = &api.node.config.HTTPPort
- }
-
- allowedOrigins := api.node.config.HTTPCors
- if cors != nil {
- allowedOrigins = nil
- for _, origin := range strings.Split(*cors, ",") {
- allowedOrigins = append(allowedOrigins, strings.TrimSpace(origin))
- }
- }
-
- allowedVHosts := api.node.config.HTTPVirtualHosts
- if vhosts != nil {
- allowedVHosts = nil
- for _, vhost := range strings.Split(*host, ",") {
- allowedVHosts = append(allowedVHosts, strings.TrimSpace(vhost))
- }
- }
-
- modules := api.node.httpWhitelist
- if apis != nil {
- modules = nil
- for _, m := range strings.Split(*apis, ",") {
- modules = append(modules, strings.TrimSpace(m))
- }
- }
-
- if err := api.node.startHTTP(fmt.Sprintf("%s:%d", *host, *port), api.node.rpcAPIs, modules, allowedOrigins, allowedVHosts, api.node.config.HTTPTimeouts, api.node.config.WSOrigins); err != nil {
- return false, err
- }
- return true, nil
-}
-
-// StopRPC terminates an already running HTTP RPC API endpoint.
-func (api *PrivateAdminAPI) StopRPC() (bool, error) {
- api.node.lock.Lock()
- defer api.node.lock.Unlock()
-
- if api.node.httpHandler == nil {
- return false, fmt.Errorf("HTTP RPC not running")
- }
- api.node.stopHTTP()
- return true, nil
-}
-
-// StartWS starts the websocket RPC API server.
-func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *string, apis *string) (bool, error) {
- api.node.lock.Lock()
- defer api.node.lock.Unlock()
-
- if api.node.wsHandler != nil {
- return false, fmt.Errorf("WebSocket RPC already running on %s", api.node.wsEndpoint)
- }
-
- if host == nil {
- h := DefaultWSHost
- if api.node.config.WSHost != "" {
- h = api.node.config.WSHost
- }
- host = &h
- }
- if port == nil {
- port = &api.node.config.WSPort
- }
-
- origins := api.node.config.WSOrigins
- if allowedOrigins != nil {
- origins = nil
- for _, origin := range strings.Split(*allowedOrigins, ",") {
- origins = append(origins, strings.TrimSpace(origin))
- }
- }
-
- modules := api.node.config.WSModules
- if apis != nil {
- modules = nil
- for _, m := range strings.Split(*apis, ",") {
- modules = append(modules, strings.TrimSpace(m))
- }
- }
-
- if err := api.node.startWS(fmt.Sprintf("%s:%d", *host, *port), api.node.rpcAPIs, modules, origins, api.node.config.WSExposeAll); err != nil {
- return false, err
- }
- return true, nil
-}
-
-// StopWS terminates an already running websocket RPC API endpoint.
-func (api *PrivateAdminAPI) StopWS() (bool, error) {
- api.node.lock.Lock()
- defer api.node.lock.Unlock()
-
- if api.node.wsHandler == nil {
- return false, fmt.Errorf("WebSocket RPC not running")
- }
- api.node.stopWS()
- return true, nil
-}
-
-// PublicAdminAPI is the collection of administrative API methods exposed over
-// both secure and unsecure RPC channels.
-type PublicAdminAPI struct {
- node *Node // Node interfaced by this API
-}
-
-// NewPublicAdminAPI creates a new API definition for the public admin methods
-// of the node itself.
-func NewPublicAdminAPI(node *Node) *PublicAdminAPI {
- return &PublicAdminAPI{node: node}
-}
-
-// Peers retrieves all the information we know about each individual peer at the
-// protocol granularity.
-func (api *PublicAdminAPI) Peers() ([]*p2p.PeerInfo, error) {
- server := api.node.Server()
- if server == nil {
- return nil, ErrNodeStopped
- }
- return server.PeersInfo(), nil
-}
-
-// NodeInfo retrieves all the information we know about the host node at the
-// protocol granularity.
-func (api *PublicAdminAPI) NodeInfo() (*p2p.NodeInfo, error) {
- server := api.node.Server()
- if server == nil {
- return nil, ErrNodeStopped
- }
- return server.NodeInfo(), nil
-}
-
-// Datadir retrieves the current data directory the node is using.
-func (api *PublicAdminAPI) Datadir() string {
- return api.node.DataDir()
-}
-
-// PublicWeb3API offers helper utils
-type PublicWeb3API struct {
- stack *Node
-}
-
-// NewPublicWeb3API creates a new Web3Service instance
-func NewPublicWeb3API(stack *Node) *PublicWeb3API {
- return &PublicWeb3API{stack}
-}
-
-// ClientVersion returns the node name
-func (s *PublicWeb3API) ClientVersion() string {
- return s.stack.Server().Name
-}
-
-// Sha3 applies the ethereum sha3 implementation on the input.
-// It assumes the input is hex encoded.
-func (s *PublicWeb3API) Sha3(input hexutil.Bytes) hexutil.Bytes {
- return crypto.Keccak256(input)
-}
diff --git a/node_2/config.go b/node_2/config.go
deleted file mode 100644
index 4a7814adeb70..000000000000
--- a/node_2/config.go
+++ /dev/null
@@ -1,545 +0,0 @@
-// Copyright 2014 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package node_2
-
-import (
- "crypto/ecdsa"
- "fmt"
- "io/ioutil"
- "os"
- "path/filepath"
- "runtime"
- "strings"
- "sync"
-
- "github.com/ethereum/go-ethereum/accounts"
- "github.com/ethereum/go-ethereum/accounts/external"
- "github.com/ethereum/go-ethereum/accounts/keystore"
- "github.com/ethereum/go-ethereum/accounts/scwallet"
- "github.com/ethereum/go-ethereum/accounts/usbwallet"
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/p2p"
- "github.com/ethereum/go-ethereum/p2p/enode"
- "github.com/ethereum/go-ethereum/rpc"
-)
-
-const (
- datadirPrivateKey = "nodekey" // Path within the datadir to the node's private key
- datadirDefaultKeyStore = "keystore" // Path within the datadir to the keystore
- datadirStaticNodes = "static-nodes.json" // Path within the datadir to the static node list
- datadirTrustedNodes = "trusted-nodes.json" // Path within the datadir to the trusted node list
- datadirNodeDatabase = "nodes" // Path within the datadir to store the node infos
-)
-
-// Config represents a small collection of configuration values to fine tune the
-// P2P network layer of a protocol stack. These values can be further extended by
-// all registered services.
-type Config struct {
- // Name sets the instance name of the node. It must not contain the / character and is
- // used in the devp2p node identifier. The instance name of geth is "geth". If no
- // value is specified, the basename of the current executable is used.
- Name string `toml:"-"`
-
- // UserIdent, if set, is used as an additional component in the devp2p node identifier.
- UserIdent string `toml:",omitempty"`
-
- // Version should be set to the version number of the program. It is used
- // in the devp2p node identifier.
- Version string `toml:"-"`
-
- // DataDir is the file system folder the node should use for any data storage
- // requirements. The configured data directory will not be directly shared with
- // registered services, instead those can use utility methods to create/access
- // databases or flat files. This enables ephemeral nodes which can fully reside
- // in memory.
- DataDir string
-
- // Configuration of peer-to-peer networking.
- P2P p2p.Config
-
- // KeyStoreDir is the file system folder that contains private keys. The directory can
- // be specified as a relative path, in which case it is resolved relative to the
- // current directory.
- //
- // If KeyStoreDir is empty, the default location is the "keystore" subdirectory of
- // DataDir. If DataDir is unspecified and KeyStoreDir is empty, an ephemeral directory
- // is created by New and destroyed when the node is stopped.
- KeyStoreDir string `toml:",omitempty"`
-
- // ExternalSigner specifies an external URI for a clef-type signer
- ExternalSigner string `toml:"omitempty"`
-
- // UseLightweightKDF lowers the memory and CPU requirements of the key store
- // scrypt KDF at the expense of security.
- UseLightweightKDF bool `toml:",omitempty"`
-
- // InsecureUnlockAllowed allows user to unlock accounts in unsafe http environment.
- InsecureUnlockAllowed bool `toml:",omitempty"`
-
- // NoUSB disables hardware wallet monitoring and connectivity.
- NoUSB bool `toml:",omitempty"`
-
- // SmartCardDaemonPath is the path to the smartcard daemon's socket
- SmartCardDaemonPath string `toml:",omitempty"`
-
- // IPCPath is the requested location to place the IPC endpoint. If the path is
- // a simple file name, it is placed inside the data directory (or on the root
- // pipe path on Windows), whereas if it's a resolvable path name (absolute or
- // relative), then that specific path is enforced. An empty path disables IPC.
- IPCPath string `toml:",omitempty"`
-
- // HTTPHost is the host interface on which to start the HTTP RPC server. If this
- // field is empty, no HTTP API endpoint will be started.
- HTTPHost string `toml:",omitempty"`
-
- // HTTPPort is the TCP port number on which to start the HTTP RPC server. The
- // default zero value is/ valid and will pick a port number randomly (useful
- // for ephemeral nodes).
- HTTPPort int `toml:",omitempty"`
-
- // HTTPCors is the Cross-Origin Resource Sharing header to send to requesting
- // clients. Please be aware that CORS is a browser enforced security, it's fully
- // useless for custom HTTP clients.
- HTTPCors []string `toml:",omitempty"`
-
- // HTTPVirtualHosts is the list of virtual hostnames which are allowed on incoming requests.
- // This is by default {'localhost'}. Using this prevents attacks like
- // DNS rebinding, which bypasses SOP by simply masquerading as being within the same
- // origin. These attacks do not utilize CORS, since they are not cross-domain.
- // By explicitly checking the Host-header, the server will not allow requests
- // made against the server with a malicious host domain.
- // Requests using ip address directly are not affected
- HTTPVirtualHosts []string `toml:",omitempty"`
-
- // HTTPModules is a list of API modules to expose via the HTTP RPC interface.
- // If the module list is empty, all RPC API endpoints designated public will be
- // exposed.
- HTTPModules []string `toml:",omitempty"`
-
- // HTTPTimeouts allows for customization of the timeout values used by the HTTP RPC
- // interface.
- HTTPTimeouts rpc.HTTPTimeouts
-
- // WSHost is the host interface on which to start the websocket RPC server. If
- // this field is empty, no websocket API endpoint will be started.
- WSHost string `toml:",omitempty"`
-
- // WSPort is the TCP port number on which to start the websocket RPC server. The
- // default zero value is/ valid and will pick a port number randomly (useful for
- // ephemeral nodes).
- WSPort int `toml:",omitempty"`
-
- // WSOrigins is the list of domain to accept websocket requests from. Please be
- // aware that the server can only act upon the HTTP request the client sends and
- // cannot verify the validity of the request header.
- WSOrigins []string `toml:",omitempty"`
-
- // WSModules is a list of API modules to expose via the websocket RPC interface.
- // If the module list is empty, all RPC API endpoints designated public will be
- // exposed.
- WSModules []string `toml:",omitempty"`
-
- // WSExposeAll exposes all API modules via the WebSocket RPC interface rather
- // than just the public ones.
- //
- // *WARNING* Only set this if the node is running in a trusted network, exposing
- // private APIs to untrusted users is a major security risk.
- WSExposeAll bool `toml:",omitempty"`
-
- // GraphQLHost is the host interface on which to start the GraphQL server. If this
- // field is empty, no GraphQL API endpoint will be started.
- GraphQLHost string `toml:",omitempty"`
-
- // GraphQLPort is the TCP port number on which to start the GraphQL server. The
- // default zero value is/ valid and will pick a port number randomly (useful
- // for ephemeral nodes).
- GraphQLPort int `toml:",omitempty"`
-
- // GraphQLCors is the Cross-Origin Resource Sharing header to send to requesting
- // clients. Please be aware that CORS is a browser enforced security, it's fully
- // useless for custom HTTP clients.
- GraphQLCors []string `toml:",omitempty"`
-
- // GraphQLVirtualHosts is the list of virtual hostnames which are allowed on incoming requests.
- // This is by default {'localhost'}. Using this prevents attacks like
- // DNS rebinding, which bypasses SOP by simply masquerading as being within the same
- // origin. These attacks do not utilize CORS, since they are not cross-domain.
- // By explicitly checking the Host-header, the server will not allow requests
- // made against the server with a malicious host domain.
- // Requests using ip address directly are not affected
- GraphQLVirtualHosts []string `toml:",omitempty"`
-
- // Logger is a custom logger to use with the p2p.Server.
- Logger log.Logger `toml:",omitempty"`
-
- staticNodesWarning bool
- trustedNodesWarning bool
- oldGethResourceWarning bool
-}
-
-// IPCEndpoint resolves an IPC endpoint based on a configured value, taking into
-// account the set data folders as well as the designated platform we're currently
-// running on.
-func (c *Config) IPCEndpoint() string {
- // Short circuit if IPC has not been enabled
- if c.IPCPath == "" {
- return ""
- }
- // On windows we can only use plain top-level pipes
- if runtime.GOOS == "windows" {
- if strings.HasPrefix(c.IPCPath, `\\.\pipe\`) {
- return c.IPCPath
- }
- return `\\.\pipe\` + c.IPCPath
- }
- // Resolve names into the data directory full paths otherwise
- if filepath.Base(c.IPCPath) == c.IPCPath {
- if c.DataDir == "" {
- return filepath.Join(os.TempDir(), c.IPCPath)
- }
- return filepath.Join(c.DataDir, c.IPCPath)
- }
- return c.IPCPath
-}
-
-// NodeDB returns the path to the discovery node database.
-func (c *Config) NodeDB() string {
- if c.DataDir == "" {
- return "" // ephemeral
- }
- return c.ResolvePath(datadirNodeDatabase)
-}
-
-// DefaultIPCEndpoint returns the IPC path used by default.
-func DefaultIPCEndpoint(clientIdentifier string) string {
- if clientIdentifier == "" {
- clientIdentifier = strings.TrimSuffix(filepath.Base(os.Args[0]), ".exe")
- if clientIdentifier == "" {
- panic("empty executable name")
- }
- }
- config := &Config{DataDir: DefaultDataDir(), IPCPath: clientIdentifier + ".ipc"}
- return config.IPCEndpoint()
-}
-
-// HTTPEndpoint resolves an HTTP endpoint based on the configured host interface
-// and port parameters.
-func (c *Config) HTTPEndpoint() string {
- if c.HTTPHost == "" {
- return ""
- }
- return fmt.Sprintf("%s:%d", c.HTTPHost, c.HTTPPort)
-}
-
-// GraphQLEndpoint resolves a GraphQL endpoint based on the configured host interface
-// and port parameters.
-func (c *Config) GraphQLEndpoint() string {
- if c.GraphQLHost == "" {
- return ""
- }
- return fmt.Sprintf("%s:%d", c.GraphQLHost, c.GraphQLPort)
-}
-
-// DefaultHTTPEndpoint returns the HTTP endpoint used by default.
-func DefaultHTTPEndpoint() string {
- config := &Config{HTTPHost: DefaultHTTPHost, HTTPPort: DefaultHTTPPort}
- return config.HTTPEndpoint()
-}
-
-// WSEndpoint resolves a websocket endpoint based on the configured host interface
-// and port parameters.
-func (c *Config) WSEndpoint() string {
- if c.WSHost == "" {
- return ""
- }
- return fmt.Sprintf("%s:%d", c.WSHost, c.WSPort)
-}
-
-// DefaultWSEndpoint returns the websocket endpoint used by default.
-func DefaultWSEndpoint() string {
- config := &Config{WSHost: DefaultWSHost, WSPort: DefaultWSPort}
- return config.WSEndpoint()
-}
-
-// ExtRPCEnabled returns the indicator whether node enables the external
-// RPC(http, ws or graphql).
-func (c *Config) ExtRPCEnabled() bool {
- return c.HTTPHost != "" || c.WSHost != "" || c.GraphQLHost != ""
-}
-
-// NodeName returns the devp2p node identifier.
-func (c *Config) NodeName() string {
- name := c.name()
- // Backwards compatibility: previous versions used title-cased "Geth", keep that.
- if name == "geth" || name == "geth-testnet" {
- name = "Geth"
- }
- if c.UserIdent != "" {
- name += "/" + c.UserIdent
- }
- if c.Version != "" {
- name += "/v" + c.Version
- }
- name += "/" + runtime.GOOS + "-" + runtime.GOARCH
- name += "/" + runtime.Version()
- return name
-}
-
-func (c *Config) name() string {
- if c.Name == "" {
- progname := strings.TrimSuffix(filepath.Base(os.Args[0]), ".exe")
- if progname == "" {
- panic("empty executable name, set Config.Name")
- }
- return progname
- }
- return c.Name
-}
-
-// These resources are resolved differently for "geth" instances.
-var isOldGethResource = map[string]bool{
- "chaindata": true,
- "nodes": true,
- "nodekey": true,
- "static-nodes.json": false, // no warning for these because they have their
- "trusted-nodes.json": false, // own separate warning.
-}
-
-// ResolvePath resolves path in the instance directory.
-func (c *Config) ResolvePath(path string) string {
- if filepath.IsAbs(path) {
- return path
- }
- if c.DataDir == "" {
- return ""
- }
- // Backwards-compatibility: ensure that data directory files created
- // by geth 1.4 are used if they exist.
- if warn, isOld := isOldGethResource[path]; isOld {
- oldpath := ""
- if c.name() == "geth" {
- oldpath = filepath.Join(c.DataDir, path)
- }
- if oldpath != "" && common.FileExist(oldpath) {
- if warn {
- c.warnOnce(&c.oldGethResourceWarning, "Using deprecated resource file %s, please move this file to the 'geth' subdirectory of datadir.", oldpath)
- }
- return oldpath
- }
- }
- return filepath.Join(c.instanceDir(), path)
-}
-
-func (c *Config) instanceDir() string {
- if c.DataDir == "" {
- return ""
- }
- return filepath.Join(c.DataDir, c.name())
-}
-
-// NodeKey retrieves the currently configured private key of the node, checking
-// first any manually set key, falling back to the one found in the configured
-// data folder. If no key can be found, a new one is generated.
-func (c *Config) NodeKey() *ecdsa.PrivateKey {
- // Use any specifically configured key.
- if c.P2P.PrivateKey != nil {
- return c.P2P.PrivateKey
- }
- // Generate ephemeral key if no datadir is being used.
- if c.DataDir == "" {
- key, err := crypto.GenerateKey()
- if err != nil {
- log.Crit(fmt.Sprintf("Failed to generate ephemeral node key: %v", err))
- }
- return key
- }
-
- keyfile := c.ResolvePath(datadirPrivateKey)
- if key, err := crypto.LoadECDSA(keyfile); err == nil {
- return key
- }
- // No persistent key found, generate and store a new one.
- key, err := crypto.GenerateKey()
- if err != nil {
- log.Crit(fmt.Sprintf("Failed to generate node key: %v", err))
- }
- instanceDir := filepath.Join(c.DataDir, c.name())
- if err := os.MkdirAll(instanceDir, 0700); err != nil {
- log.Error(fmt.Sprintf("Failed to persist node key: %v", err))
- return key
- }
- keyfile = filepath.Join(instanceDir, datadirPrivateKey)
- if err := crypto.SaveECDSA(keyfile, key); err != nil {
- log.Error(fmt.Sprintf("Failed to persist node key: %v", err))
- }
- return key
-}
-
-// StaticNodes returns a list of node enode URLs configured as static nodes.
-func (c *Config) StaticNodes() []*enode.Node {
- return c.parsePersistentNodes(&c.staticNodesWarning, c.ResolvePath(datadirStaticNodes))
-}
-
-// TrustedNodes returns a list of node enode URLs configured as trusted nodes.
-func (c *Config) TrustedNodes() []*enode.Node {
- return c.parsePersistentNodes(&c.trustedNodesWarning, c.ResolvePath(datadirTrustedNodes))
-}
-
-// parsePersistentNodes parses a list of discovery node URLs loaded from a .json
-// file from within the data directory.
-func (c *Config) parsePersistentNodes(w *bool, path string) []*enode.Node {
- // Short circuit if no node config is present
- if c.DataDir == "" {
- return nil
- }
- if _, err := os.Stat(path); err != nil {
- return nil
- }
- c.warnOnce(w, "Found deprecated node list file %s, please use the TOML config file instead.", path)
-
- // Load the nodes from the config file.
- var nodelist []string
- if err := common.LoadJSON(path, &nodelist); err != nil {
- log.Error(fmt.Sprintf("Can't load node list file: %v", err))
- return nil
- }
- // Interpret the list as a discovery node array
- var nodes []*enode.Node
- for _, url := range nodelist {
- if url == "" {
- continue
- }
- node, err := enode.Parse(enode.ValidSchemes, url)
- if err != nil {
- log.Error(fmt.Sprintf("Node URL %s: %v\n", url, err))
- continue
- }
- nodes = append(nodes, node)
- }
- return nodes
-}
-
-// AccountConfig determines the settings for scrypt and keydirectory
-func (c *Config) AccountConfig() (int, int, string, error) {
- scryptN := keystore.StandardScryptN
- scryptP := keystore.StandardScryptP
- if c.UseLightweightKDF {
- scryptN = keystore.LightScryptN
- scryptP = keystore.LightScryptP
- }
-
- var (
- keydir string
- err error
- )
- switch {
- case filepath.IsAbs(c.KeyStoreDir):
- keydir = c.KeyStoreDir
- case c.DataDir != "":
- if c.KeyStoreDir == "" {
- keydir = filepath.Join(c.DataDir, datadirDefaultKeyStore)
- } else {
- keydir, err = filepath.Abs(c.KeyStoreDir)
- }
- case c.KeyStoreDir != "":
- keydir, err = filepath.Abs(c.KeyStoreDir)
- }
- return scryptN, scryptP, keydir, err
-}
-
-func makeAccountManager(conf *Config) (*accounts.Manager, string, error) {
- scryptN, scryptP, keydir, err := conf.AccountConfig()
- var ephemeral string
- if keydir == "" {
- // There is no datadir.
- keydir, err = ioutil.TempDir("", "go-ethereum-keystore")
- ephemeral = keydir
- }
-
- if err != nil {
- return nil, "", err
- }
- if err := os.MkdirAll(keydir, 0700); err != nil {
- return nil, "", err
- }
- // Assemble the account manager and supported backends
- var backends []accounts.Backend
- if len(conf.ExternalSigner) > 0 {
- log.Info("Using external signer", "url", conf.ExternalSigner)
- if extapi, err := external.NewExternalBackend(conf.ExternalSigner); err == nil {
- backends = append(backends, extapi)
- } else {
- return nil, "", fmt.Errorf("error connecting to external signer: %v", err)
- }
- }
- if len(backends) == 0 {
- // For now, we're using EITHER external signer OR local signers.
- // If/when we implement some form of lockfile for USB and keystore wallets,
- // we can have both, but it's very confusing for the user to see the same
- // accounts in both externally and locally, plus very racey.
- backends = append(backends, keystore.NewKeyStore(keydir, scryptN, scryptP))
- if !conf.NoUSB {
- // Start a USB hub for Ledger hardware wallets
- if ledgerhub, err := usbwallet.NewLedgerHub(); err != nil {
- log.Warn(fmt.Sprintf("Failed to start Ledger hub, disabling: %v", err))
- } else {
- backends = append(backends, ledgerhub)
- }
- // Start a USB hub for Trezor hardware wallets (HID version)
- if trezorhub, err := usbwallet.NewTrezorHubWithHID(); err != nil {
- log.Warn(fmt.Sprintf("Failed to start HID Trezor hub, disabling: %v", err))
- } else {
- backends = append(backends, trezorhub)
- }
- // Start a USB hub for Trezor hardware wallets (WebUSB version)
- if trezorhub, err := usbwallet.NewTrezorHubWithWebUSB(); err != nil {
- log.Warn(fmt.Sprintf("Failed to start WebUSB Trezor hub, disabling: %v", err))
- } else {
- backends = append(backends, trezorhub)
- }
- }
- if len(conf.SmartCardDaemonPath) > 0 {
- // Start a smart card hub
- if schub, err := scwallet.NewHub(conf.SmartCardDaemonPath, scwallet.Scheme, keydir); err != nil {
- log.Warn(fmt.Sprintf("Failed to start smart card hub, disabling: %v", err))
- } else {
- backends = append(backends, schub)
- }
- }
- }
-
- return accounts.NewManager(&accounts.Config{InsecureUnlockAllowed: conf.InsecureUnlockAllowed}, backends...), ephemeral, nil
-}
-
-var warnLock sync.Mutex
-
-func (c *Config) warnOnce(w *bool, format string, args ...interface{}) {
- warnLock.Lock()
- defer warnLock.Unlock()
-
- if *w {
- return
- }
- l := c.Logger
- if l == nil {
- l = log.Root()
- }
- l.Warn(fmt.Sprintf(format, args...))
- *w = true
-}
diff --git a/node_2/defaults.go b/node_2/defaults.go
deleted file mode 100644
index 9951aaa0265e..000000000000
--- a/node_2/defaults.go
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright 2016 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package node_2
-
-import (
- "os"
- "os/user"
- "path/filepath"
- "runtime"
-
- "github.com/ethereum/go-ethereum/p2p"
- "github.com/ethereum/go-ethereum/p2p/nat"
- "github.com/ethereum/go-ethereum/rpc"
-)
-
-const (
- DefaultHTTPHost = "localhost" // Default host interface for the HTTP RPC server
- DefaultHTTPPort = 8545 // Default TCP port for the HTTP RPC server
- DefaultWSHost = "localhost" // Default host interface for the websocket RPC server
- DefaultWSPort = 8546 // Default TCP port for the websocket RPC server
- DefaultGraphQLHost = "localhost" // Default host interface for the GraphQL server
- DefaultGraphQLPort = 8547 // Default TCP port for the GraphQL server
-)
-
-// DefaultConfig contains reasonable default settings.
-var DefaultConfig = Config{
- DataDir: DefaultDataDir(),
- HTTPPort: DefaultHTTPPort,
- HTTPModules: []string{"net", "web3"},
- HTTPVirtualHosts: []string{"localhost"},
- HTTPTimeouts: rpc.DefaultHTTPTimeouts,
- WSPort: DefaultWSPort,
- WSModules: []string{"net", "web3"},
- GraphQLPort: DefaultGraphQLPort,
- GraphQLVirtualHosts: []string{"localhost"},
- P2P: p2p.Config{
- ListenAddr: ":30303",
- MaxPeers: 50,
- NAT: nat.Any(),
- },
-}
-
-// DefaultDataDir is the default data directory to use for the databases and other
-// persistence requirements.
-func DefaultDataDir() string {
- // Try to place the data folder in the user's home dir
- home := homeDir()
- if home != "" {
- switch runtime.GOOS {
- case "darwin":
- return filepath.Join(home, "Library", "Ethereum")
- case "windows":
- // We used to put everything in %HOME%\AppData\Roaming, but this caused
- // problems with non-typical setups. If this fallback location exists and
- // is non-empty, use it, otherwise DTRT and check %LOCALAPPDATA%.
- fallback := filepath.Join(home, "AppData", "Roaming", "Ethereum")
- appdata := windowsAppData()
- if appdata == "" || isNonEmptyDir(fallback) {
- return fallback
- }
- return filepath.Join(appdata, "Ethereum")
- default:
- return filepath.Join(home, ".ethereum")
- }
- }
- // As we cannot guess a stable location, return empty and handle later
- return ""
-}
-
-func windowsAppData() string {
- v := os.Getenv("LOCALAPPDATA")
- if v == "" {
- // Windows XP and below don't have LocalAppData. Crash here because
- // we don't support Windows XP and undefining the variable will cause
- // other issues.
- panic("environment variable LocalAppData is undefined")
- }
- return v
-}
-
-func isNonEmptyDir(dir string) bool {
- f, err := os.Open(dir)
- if err != nil {
- return false
- }
- names, _ := f.Readdir(1)
- f.Close()
- return len(names) > 0
-}
-
-func homeDir() string {
- if home := os.Getenv("HOME"); home != "" {
- return home
- }
- if usr, err := user.Current(); err == nil {
- return usr.HomeDir
- }
- return ""
-}
diff --git a/node_2/endpoints.go b/node_2/endpoints.go
deleted file mode 100644
index 0dce7b5acfe3..000000000000
--- a/node_2/endpoints.go
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright 2018 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package node_2
-
-import (
- "net"
- "net/http"
- "time"
-
- "github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/rpc"
-)
-
-// StartHTTPEndpoint starts the HTTP RPC endpoint.
-func StartHTTPEndpoint(endpoint string, timeouts rpc.HTTPTimeouts, handler http.Handler) (net.Listener, error) {
- // start the HTTP listener
- var (
- listener net.Listener
- err error
- )
- if listener, err = net.Listen("tcp", endpoint); err != nil {
- return nil, err
- }
- // make sure timeout values are meaningful
- CheckTimeouts(&timeouts)
- // Bundle and start the HTTP server
- httpSrv := &http.Server{
- Handler: handler,
- ReadTimeout: timeouts.ReadTimeout,
- WriteTimeout: timeouts.WriteTimeout,
- IdleTimeout: timeouts.IdleTimeout,
- }
- go httpSrv.Serve(listener)
- return listener, err
-}
-
-// startWSEndpoint starts a websocket endpoint.
-func startWSEndpoint(endpoint string, handler http.Handler) (net.Listener, error) {
- // start the HTTP listener
- var (
- listener net.Listener
- err error
- )
- if listener, err = net.Listen("tcp", endpoint); err != nil {
- return nil, err
- }
- wsSrv := &http.Server{Handler: handler}
- go wsSrv.Serve(listener)
- return listener, err
-}
-
-// checkModuleAvailability checks that all names given in modules are actually
-// available API services. It assumes that the MetadataApi module ("rpc") is always available;
-// the registration of this "rpc" module happens in NewServer() and is thus common to all endpoints.
-func checkModuleAvailability(modules []string, apis []rpc.API) (bad, available []string) {
- availableSet := make(map[string]struct{})
- for _, api := range apis {
- if _, ok := availableSet[api.Namespace]; !ok {
- availableSet[api.Namespace] = struct{}{}
- available = append(available, api.Namespace)
- }
- }
- for _, name := range modules {
- if _, ok := availableSet[name]; !ok && name != rpc.MetadataApi {
- bad = append(bad, name)
- }
- }
- return bad, available
-}
-
-// CheckTimeouts ensures that timeout values are meaningful
-func CheckTimeouts(timeouts *rpc.HTTPTimeouts) {
- if timeouts.ReadTimeout < time.Second {
- log.Warn("Sanitizing invalid HTTP read timeout", "provided", timeouts.ReadTimeout, "updated", rpc.DefaultHTTPTimeouts.ReadTimeout)
- timeouts.ReadTimeout = rpc.DefaultHTTPTimeouts.ReadTimeout
- }
- if timeouts.WriteTimeout < time.Second {
- log.Warn("Sanitizing invalid HTTP write timeout", "provided", timeouts.WriteTimeout, "updated", rpc.DefaultHTTPTimeouts.WriteTimeout)
- timeouts.WriteTimeout = rpc.DefaultHTTPTimeouts.WriteTimeout
- }
- if timeouts.IdleTimeout < time.Second {
- log.Warn("Sanitizing invalid HTTP idle timeout", "provided", timeouts.IdleTimeout, "updated", rpc.DefaultHTTPTimeouts.IdleTimeout)
- timeouts.IdleTimeout = rpc.DefaultHTTPTimeouts.IdleTimeout
- }
-}
diff --git a/node_2/errors.go b/node_2/errors.go
deleted file mode 100644
index 7ae4440208cc..000000000000
--- a/node_2/errors.go
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2015 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package node_2
-
-import (
- "errors"
- "fmt"
- "reflect"
- "syscall"
-)
-
-var (
- ErrDatadirUsed = errors.New("datadir already used by another process")
- ErrNodeStopped = errors.New("node not started")
- ErrNodeRunning = errors.New("node already running")
- ErrServiceUnknown = errors.New("unknown service")
-
- datadirInUseErrnos = map[uint]bool{11: true, 32: true, 35: true}
-)
-
-func convertFileLockError(err error) error {
- if errno, ok := err.(syscall.Errno); ok && datadirInUseErrnos[uint(errno)] {
- return ErrDatadirUsed
- }
- return err
-}
-
-// DuplicateServiceError is returned during Node startup if a registered service
-// constructor returns a service of the same type that was already started.
-type DuplicateServiceError struct {
- Kind reflect.Type
-}
-
-// Error generates a textual representation of the duplicate service error.
-func (e *DuplicateServiceError) Error() string {
- return fmt.Sprintf("duplicate service: %v", e.Kind)
-}
-
-// StopError is returned if a Node fails to stop either any of its registered
-// services or itself.
-type StopError struct {
- Server error
- Services map[reflect.Type]error
-}
-
-// Error generates a textual representation of the stop error.
-func (e *StopError) Error() string {
- return fmt.Sprintf("server: %v, services: %v", e.Server, e.Services)
-}
diff --git a/node_2/node.go b/node_2/node.go
deleted file mode 100644
index 9668fee80f81..000000000000
--- a/node_2/node.go
+++ /dev/null
@@ -1,737 +0,0 @@
-// Copyright 2015 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package node_2
-
-import (
- "errors"
- "fmt"
- "os"
- "path/filepath"
- "reflect"
- "strings"
- "sync"
-
- "github.com/ethereum/go-ethereum/accounts"
- "github.com/ethereum/go-ethereum/core/rawdb"
- "github.com/ethereum/go-ethereum/ethdb"
- "github.com/ethereum/go-ethereum/event"
- "github.com/ethereum/go-ethereum/internal/debug"
- "github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/p2p"
- "github.com/ethereum/go-ethereum/rpc"
- "github.com/prometheus/tsdb/fileutil"
-)
-
-// Node is a container on which services can be registered.
-type Node struct {
- eventmux *event.TypeMux // Event multiplexer used between the services of a stack
- config *Config
- accman *accounts.Manager
-
- ephemeralKeystore string // if non-empty, the key directory that will be removed by Stop
- instanceDirLock fileutil.Releaser // prevents concurrent use of instance directory
-
- server *p2p.Server // Currently running P2P networking layer
-
- backends map[reflect.Type]Backend // TODO
- services map[reflect.Type]Service // Currently running services
- auxServices map[reflect.Type]AuxiliaryService // TODO
-
- rpcAPIs []rpc.API // List of APIs currently provided by the node
- inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
-
- ipcHandler *httpServer // TODO
- httpHandler *httpServer // TODO
- wsHandler *httpServer // TODO
-
- stop chan struct{} // Channel to wait for termination notifications
- lock sync.RWMutex
-
- log log.Logger
-}
-
-// New creates a new P2P node, ready for protocol registration.
-func New(conf *Config) (*Node, error) {
- // Copy config and resolve the datadir so future changes to the current
- // working directory don't affect the node.
- confCopy := *conf
- conf = &confCopy
- if conf.DataDir != "" {
- absdatadir, err := filepath.Abs(conf.DataDir)
- if err != nil {
- return nil, err
- }
- conf.DataDir = absdatadir
- }
- // Ensure that the instance name doesn't cause weird conflicts with
- // other files in the data directory.
- if strings.ContainsAny(conf.Name, `/\`) {
- return nil, errors.New(`Config.Name must not contain '/' or '\'`)
- }
- if conf.Name == datadirDefaultKeyStore {
- return nil, errors.New(`Config.Name cannot be "` + datadirDefaultKeyStore + `"`)
- }
- if strings.HasSuffix(conf.Name, ".ipc") {
- return nil, errors.New(`Config.Name cannot end in ".ipc"`)
- }
- // Ensure that the AccountManager method works before the node has started.
- // We rely on this in cmd/geth.
- am, ephemeralKeystore, err := makeAccountManager(conf)
- if err != nil {
- return nil, err
- }
- if conf.Logger == nil {
- conf.Logger = log.New()
- }
- // Note: any interaction with Config that would create/touch files
- // in the data directory or instance directory is delayed until Start.
- return &Node{
- accman: am,
- ephemeralKeystore: ephemeralKeystore,
- config: conf,
- ipcHandler: &httpServer{
- endpoint: endpoint{
- endpoint: conf.IPCEndpoint(),
- },
- },
- httpHandler: &httpServer{
- endpoint: endpoint{
- endpoint: conf.HTTPEndpoint(),
- host: conf.HTTPHost,
- port: conf.HTTPPort,
- },
- CorsAllowedOrigins: conf.HTTPCors,
- Vhosts: conf.HTTPVirtualHosts,
- Timeouts: conf.HTTPTimeouts,
- WsOrigins: conf.WSOrigins, // TODO do i already add this?
- RPCAllowed: true,
-
- },
- wsHandler: &httpServer{
- endpoint: endpoint{
- endpoint: conf.WSEndpoint(),
- host: conf.WSHost,
- port: conf.WSPort,
- },
- WsOrigins: conf.WSOrigins,
- WSAllowed: true,
- },
- eventmux: new(event.TypeMux),
- log: conf.Logger,
- }, nil
-}
-
-// Close stops the Node and releases resources acquired in
-// Node constructor New.
-func (n *Node) Close() error {
- var errs []error
-
- // Terminate all subsystems and collect any errors
- if err := n.Stop(); err != nil && err != ErrNodeStopped {
- errs = append(errs, err)
- }
- if err := n.accman.Close(); err != nil {
- errs = append(errs, err)
- }
- // Report any errors that might have occurred
- switch len(errs) {
- case 0:
- return nil
- case 1:
- return errs[0]
- default:
- return fmt.Errorf("%v", errs)
- }
-}
-
-// Register injects a new service into the node's stack. The service created by
-// the passed constructor must be unique in its type with regard to sibling ones.
-func (n *Node) Register(constructor ServiceConstructor) error {
- n.lock.Lock()
- defer n.lock.Unlock()
-
- // TODO this should create the service and add it to the maps already
-
- //if n.server != nil {
- // return ErrNodeRunning
- //}
- //n.serviceFuncs = append(n.serviceFuncs, constructor)
- return nil
-}
-
-// Start creates a live P2P node and starts running it.
-func (n *Node) Start() error {
- n.lock.Lock()
- defer n.lock.Unlock()
-
- // Short circuit if the node's already running
- if n.server != nil {
- return ErrNodeRunning
- }
- if err := n.openDataDir(); err != nil {
- return err
- }
-
- // Initialize the p2p server. This creates the node key and
- // discovery databases.
- running := &p2p.Server{}
-
- running.PrivateKey = n.config.NodeKey()
- running.Name = n.config.NodeName()
- running.Logger = n.log
- if running.StaticNodes == nil {
- running.StaticNodes = n.config.StaticNodes()
- }
- if running.TrustedNodes == nil {
- running.TrustedNodes = n.config.TrustedNodes()
- }
- if running.NodeDatabase == "" {
- running.NodeDatabase = n.config.NodeDB()
- }
- n.log.Info("Starting peer-to-peer node", "instance", running.Name)
-
- // TODO document
- backends := make(map[reflect.Type]Backend)
- services := make(map[reflect.Type]Service)
- auxServices := make(map[reflect.Type]AuxiliaryService)
-
- // Gather the protocols and start the freshly assembled P2P server
- for _, backend := range backends {
- running.Protocols = append(running.Protocols, backend.Protocols()...)
- }
- if err := running.Start(); err != nil {
- return convertFileLockError(err)
- }
-
- //TODO instead of constructor, make it actually construct the backends, services and aux services?
-
- // TODO this should just check for duplicates, and then start the backends, services, and auxServices
-
- var started []reflect.Type
-
- // Start each of the backends
- for kind, backend := range backends {
- if err := backend.Start(); err != nil {
- for _, kind := range started {
- services[kind].Stop()
- }
- running.Stop()
-
- return err
- }
- // Mark the service started for potential cleanup
- started = append(started, kind)
- }
-
- // Start each of the services
- for kind, service := range services {
- // Start the next service, stopping all previous upon failure
- if err := service.Start(); err != nil {
- for _, kind := range started {
- services[kind].Stop()
- }
- running.Stop()
-
- return err
- }
- // Mark the service started for potential cleanup
- started = append(started, kind)
- }
-
- // Gather all the possible APIs to surface
- apis := n.apis()
- for _, backend := range backends {
- apis = append(apis, backend.APIs()...)
- }
- for _, service := range services {
- apis = append(apis, service.APIs()...)
- }
-
- // Lastly, start the configured RPC interfaces
- if err := n.startRPC(apis); err != nil {
- for _, service := range services {
- service.Stop()
- }
- running.Stop()
- return err
- }
-
- // Finish initializing the startup
- n.backends = backends
- n.services = services
- n.auxServices = auxServices
- n.server = running
- n.stop = make(chan struct{})
- return nil
-}
-
-// Config returns the configuration of node.
-func (n *Node) Config() *Config {
- return n.config
-}
-
-func (n *Node) openDataDir() error {
- if n.config.DataDir == "" {
- return nil // ephemeral
- }
-
- instdir := filepath.Join(n.config.DataDir, n.config.name())
- if err := os.MkdirAll(instdir, 0700); err != nil {
- return err
- }
- // Lock the instance directory to prevent concurrent use by another instance as well as
- // accidental use of the instance directory as a database.
- release, _, err := fileutil.Flock(filepath.Join(instdir, "LOCK"))
- if err != nil {
- return convertFileLockError(err)
- }
- n.instanceDirLock = release
- return nil
-}
-
-// startRPC is a helper method to start all the various RPC endpoints during node
-// startup. It's not meant to be called at any time afterwards as it makes certain
-// assumptions about the state of the node.
-func (n *Node) startRPC(apis []rpc.API) error {
- // Start the various API endpoints, terminating all in case of errors
- if err := n.startInProc(apis); err != nil {
- return err
- }
- if err := n.startIPC(apis); err != nil {
- n.stopInProc()
- return err
- }
- if err := n.startHTTP(n.httpEndpoint, apis, n.config.HTTPModules, n.config.HTTPCors, n.config.HTTPVirtualHosts, n.config.HTTPTimeouts, n.config.WSOrigins); err != nil {
- n.stopIPC()
- n.stopInProc()
- return err
- }
- // if endpoints are not the same, start separate servers
- if n.httpEndpoint != n.wsEndpoint {
- if err := n.startWS(n.wsEndpoint, apis, n.config.WSModules, n.config.WSOrigins, n.config.WSExposeAll); err != nil {
- n.stopHTTP()
- n.stopIPC()
- n.stopInProc()
- return err
- }
- }
-
- // All API endpoints started successfully
- n.rpcAPIs = apis
- return nil
-}
-
-// startInProc initializes an in-process RPC endpoint.
-func (n *Node) startInProc(apis []rpc.API) error {
- // Register all the APIs exposed by the services
- handler := rpc.NewServer()
- for _, api := range apis {
- if err := handler.RegisterName(api.Namespace, api.Service); err != nil {
- return err
- }
- n.log.Debug("InProc registered", "namespace", api.Namespace)
- }
- n.inprocHandler = handler
- return nil
-}
-
-// stopInProc terminates the in-process RPC endpoint.
-func (n *Node) stopInProc() {
- if n.inprocHandler != nil {
- n.inprocHandler.Stop()
- n.inprocHandler = nil
- }
-}
-
-// startIPC initializes and starts the IPC RPC endpoint.
-func (n *Node) startIPC(apis []rpc.API) error {
- if n.ipcEndpoint == "" {
- return nil // IPC disabled.
- }
- listener, handler, err := rpc.StartIPCEndpoint(n.ipcEndpoint, apis)
- if err != nil {
- return err
- }
- n.ipcListener = listener
- n.ipcHandler = handler
- n.log.Info("IPC endpoint opened", "url", n.ipcEndpoint)
- return nil
-}
-
-// stopIPC terminates the IPC RPC endpoint.
-func (n *Node) stopIPC() {
- if n.ipcListener != nil {
- n.ipcListener.Close()
- n.ipcListener = nil
-
- n.log.Info("IPC endpoint closed", "url", n.ipcEndpoint)
- }
- if n.ipcHandler != nil {
- n.ipcHandler.Stop()
- n.ipcHandler = nil
- }
-}
-
-// startHTTP initializes and starts the HTTP RPC endpoint.
-func (n *Node) startHTTP(endpoint string, apis []rpc.API, modules []string, cors []string, vhosts []string, timeouts rpc.HTTPTimeouts, wsOrigins []string) error {
- // Short circuit if the HTTP endpoint isn't being exposed
- if endpoint == "" {
- return nil
- }
- // register apis and create handler stack
- srv := rpc.NewServer()
- err := RegisterApisFromWhitelist(apis, modules, srv, false)
- if err != nil {
- return err
- }
- handler := NewHTTPHandlerStack(srv, cors, vhosts)
- // wrap handler in websocket handler only if websocket port is the same as http rpc
- if n.httpEndpoint == n.wsEndpoint {
- handler = NewWebsocketUpgradeHandler(handler, srv.WebsocketHandler(wsOrigins))
- }
- listener, err := StartHTTPEndpoint(endpoint, timeouts, handler)
- if err != nil {
- return err
- }
- n.log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%v/", listener.Addr()),
- "cors", strings.Join(cors, ","),
- "vhosts", strings.Join(vhosts, ","))
- if n.httpEndpoint == n.wsEndpoint {
- n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", listener.Addr()))
- }
- // All listeners booted successfully
- n.httpEndpoint = endpoint
- n.httpListener = listener
- n.httpHandler = srv
-
- return nil
-}
-
-// stopHTTP terminates the HTTP RPC endpoint.
-func (n *Node) stopHTTP() {
- if n.httpListener != nil {
- url := fmt.Sprintf("http://%v/", n.httpListener.Addr())
- n.httpListener.Close()
- n.httpListener = nil
- n.log.Info("HTTP endpoint closed", "url", url)
- }
- if n.httpHandler != nil {
- n.httpHandler.Stop()
- n.httpHandler = nil
- }
-}
-
-// startWS initializes and starts the websocket RPC endpoint.
-func (n *Node) startWS(endpoint string, apis []rpc.API, modules []string, wsOrigins []string, exposeAll bool) error {
- // Short circuit if the WS endpoint isn't being exposed
- if endpoint == "" {
- return nil
- }
-
- srv := rpc.NewServer()
- handler := srv.WebsocketHandler(wsOrigins)
- err := RegisterApisFromWhitelist(apis, modules, srv, exposeAll)
- if err != nil {
- return err
- }
- listener, err := startWSEndpoint(endpoint, handler)
- if err != nil {
- return err
- }
- n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%s", listener.Addr()))
- // All listeners booted successfully
- n.wsEndpoint = endpoint
- n.wsListener = listener
- n.wsHandler = srv
-
- return nil
-}
-
-// stopWS terminates the websocket RPC endpoint.
-func (n *Node) stopWS() {
- if n.wsListener != nil {
- n.wsListener.Close()
- n.wsListener = nil
-
- n.log.Info("WebSocket endpoint closed", "url", fmt.Sprintf("ws://%s", n.wsEndpoint))
- }
- if n.wsHandler != nil {
- n.wsHandler.Stop()
- n.wsHandler = nil
- }
-}
-
-// Stop terminates a running node along with all it's services. In the node was
-// not started, an error is returned.
-func (n *Node) Stop() error {
- n.lock.Lock()
- defer n.lock.Unlock()
-
- // Short circuit if the node's not running
- if n.server == nil {
- return ErrNodeStopped
- }
-
- // Terminate the API, services and the p2p server.
- n.stopWS()
- n.stopHTTP()
- n.stopIPC()
- n.rpcAPIs = nil
- failure := &StopError{
- Services: make(map[reflect.Type]error),
- }
- for kind, service := range n.services {
- if err := service.Stop(); err != nil {
- failure.Services[kind] = err
- }
- }
- n.server.Stop()
- n.services = nil
- n.server = nil
-
- // Release instance directory lock.
- if n.instanceDirLock != nil {
- if err := n.instanceDirLock.Release(); err != nil {
- n.log.Error("Can't release datadir lock", "err", err)
- }
- n.instanceDirLock = nil
- }
-
- // unblock n.Wait
- close(n.stop)
-
- // Remove the keystore if it was created ephemerally.
- var keystoreErr error
- if n.ephemeralKeystore != "" {
- keystoreErr = os.RemoveAll(n.ephemeralKeystore)
- }
-
- if len(failure.Services) > 0 {
- return failure
- }
- if keystoreErr != nil {
- return keystoreErr
- }
- return nil
-}
-
-// Wait blocks the thread until the node is stopped. If the node is not running
-// at the time of invocation, the method immediately returns.
-func (n *Node) Wait() {
- n.lock.RLock()
- if n.server == nil {
- n.lock.RUnlock()
- return
- }
- stop := n.stop
- n.lock.RUnlock()
-
- <-stop
-}
-
-// Restart terminates a running node and boots up a new one in its place. If the
-// node isn't running, an error is returned.
-func (n *Node) Restart() error {
- if err := n.Stop(); err != nil {
- return err
- }
- if err := n.Start(); err != nil {
- return err
- }
- return nil
-}
-
-// Attach creates an RPC client attached to an in-process API handler.
-func (n *Node) Attach() (*rpc.Client, error) {
- n.lock.RLock()
- defer n.lock.RUnlock()
-
- if n.server == nil {
- return nil, ErrNodeStopped
- }
- return rpc.DialInProc(n.inprocHandler), nil
-}
-
-// RPCHandler returns the in-process RPC request handler.
-func (n *Node) RPCHandler() (*rpc.Server, error) {
- n.lock.RLock()
- defer n.lock.RUnlock()
-
- if n.inprocHandler == nil {
- return nil, ErrNodeStopped
- }
- return n.inprocHandler, nil
-}
-
-// Server retrieves the currently running P2P network layer. This method is meant
-// only to inspect fields of the currently running server, life cycle management
-// should be left to this Node entity.
-func (n *Node) Server() *p2p.Server {
- n.lock.RLock()
- defer n.lock.RUnlock()
-
- return n.server
-}
-
-// Service retrieves a currently running service registered of a specific type.
-func (n *Node) Service(service interface{}) error {
- n.lock.RLock()
- defer n.lock.RUnlock()
-
- // Short circuit if the node's not running
- if n.server == nil {
- return ErrNodeStopped
- }
- // Otherwise try to find the service to return
- element := reflect.ValueOf(service).Elem()
- if running, ok := n.services[element.Type()]; ok {
- element.Set(reflect.ValueOf(running))
- return nil
- }
- return ErrServiceUnknown
-}
-
-// DataDir retrieves the current datadir used by the protocol stack.
-// Deprecated: No files should be stored in this directory, use InstanceDir instead.
-func (n *Node) DataDir() string {
- return n.config.DataDir
-}
-
-// InstanceDir retrieves the instance directory used by the protocol stack.
-func (n *Node) InstanceDir() string {
- return n.config.instanceDir()
-}
-
-// AccountManager retrieves the account manager used by the protocol stack.
-func (n *Node) AccountManager() *accounts.Manager {
- return n.accman
-}
-
-// IPCEndpoint retrieves the current IPC endpoint used by the protocol stack.
-func (n *Node) IPCEndpoint() string {
- return n.ipcEndpoint
-}
-
-// HTTPEndpoint retrieves the current HTTP endpoint used by the protocol stack.
-func (n *Node) HTTPEndpoint() string {
- n.lock.Lock()
- defer n.lock.Unlock()
-
- if n.httpListener != nil {
- return n.httpListener.Addr().String()
- }
- return n.httpEndpoint
-}
-
-// WSEndpoint retrieves the current WS endpoint used by the protocol stack.
-func (n *Node) WSEndpoint() string {
- n.lock.Lock()
- defer n.lock.Unlock()
-
- if n.wsListener != nil {
- return n.wsListener.Addr().String()
- }
- return n.wsEndpoint
-}
-
-// EventMux retrieves the event multiplexer used by all the network services in
-// the current protocol stack.
-func (n *Node) EventMux() *event.TypeMux {
- return n.eventmux
-}
-
-// OpenDatabase opens an existing database with the given name (or creates one if no
-// previous can be found) from within the node's instance directory. If the node is
-// ephemeral, a memory database is returned.
-func (n *Node) OpenDatabase(name string, cache, handles int, namespace string) (ethdb.Database, error) {
- if n.config.DataDir == "" {
- return rawdb.NewMemoryDatabase(), nil
- }
- return rawdb.NewLevelDBDatabase(n.config.ResolvePath(name), cache, handles, namespace)
-}
-
-// OpenDatabaseWithFreezer opens an existing database with the given name (or
-// creates one if no previous can be found) from within the node's data directory,
-// also attaching a chain freezer to it that moves ancient chain data from the
-// database to immutable append-only files. If the node is an ephemeral one, a
-// memory database is returned.
-func (n *Node) OpenDatabaseWithFreezer(name string, cache, handles int, freezer, namespace string) (ethdb.Database, error) {
- if n.config.DataDir == "" {
- return rawdb.NewMemoryDatabase(), nil
- }
- root := n.config.ResolvePath(name)
-
- switch {
- case freezer == "":
- freezer = filepath.Join(root, "ancient")
- case !filepath.IsAbs(freezer):
- freezer = n.config.ResolvePath(freezer)
- }
- return rawdb.NewLevelDBDatabaseWithFreezer(root, cache, handles, freezer, namespace)
-}
-
-// ResolvePath returns the absolute path of a resource in the instance directory.
-func (n *Node) ResolvePath(x string) string {
- return n.config.ResolvePath(x)
-}
-
-// apis returns the collection of RPC descriptors this node offers.
-func (n *Node) apis() []rpc.API {
- return []rpc.API{
- {
- Namespace: "admin",
- Version: "1.0",
- Service: NewPrivateAdminAPI(n),
- }, {
- Namespace: "admin",
- Version: "1.0",
- Service: NewPublicAdminAPI(n),
- Public: true,
- }, {
- Namespace: "debug",
- Version: "1.0",
- Service: debug.Handler,
- }, {
- Namespace: "web3",
- Version: "1.0",
- Service: NewPublicWeb3API(n),
- Public: true,
- },
- }
-}
-
-// RegisterApisFromWhitelist checks the given modules' availability, generates a whitelist based on the allowed modules,
-// and then registers all of the APIs exposed by the services.
-func RegisterApisFromWhitelist(apis []rpc.API, modules []string, srv *rpc.Server, exposeAll bool) error {
- if bad, available := checkModuleAvailability(modules, apis); len(bad) > 0 {
- log.Error("Unavailable modules in HTTP API list", "unavailable", bad, "available", available)
- }
- // Generate the whitelist based on the allowed modules
- whitelist := make(map[string]bool)
- for _, module := range modules {
- whitelist[module] = true
- }
- // Register all the APIs exposed by the services
- for _, api := range apis {
- if exposeAll || whitelist[api.Namespace] || (len(whitelist) == 0 && api.Public) {
- if err := srv.RegisterName(api.Namespace, api.Service); err != nil {
- return err
- }
- }
- }
- return nil
-}
diff --git a/node_2/rpcstack.go b/node_2/rpcstack.go
deleted file mode 100644
index eb3928655782..000000000000
--- a/node_2/rpcstack.go
+++ /dev/null
@@ -1,185 +0,0 @@
-// Copyright 2020 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package node_2
-
-import (
- "compress/gzip"
- "github.com/ethereum/go-ethereum/rpc"
- "io"
- "io/ioutil"
- "net"
- "net/http"
- "strings"
- "sync"
-
- "github.com/ethereum/go-ethereum/log"
- "github.com/rs/cors"
-)
-
-type httpServer struct {
- handler http.Handler
- Srv *rpc.Server
-
- endpoint endpoint
-
- Whitelist []string
-
- CorsAllowedOrigins []string
- Vhosts []string
- WsOrigins []string
- Timeouts rpc.HTTPTimeouts
-
- Listener net.Listener
-
- RPCAllowed bool
- WSAllowed bool
-}
-
-type endpoint struct {
- endpoint string
- host string
- port int
-}
-
-// NewHTTPHandlerStack returns wrapped http-related handlers
-func NewHTTPHandlerStack(srv http.Handler, cors []string, vhosts []string) http.Handler {
- // Wrap the CORS-handler within a host-handler
- handler := newCorsHandler(srv, cors)
- handler = newVHostHandler(vhosts, handler)
- return newGzipHandler(handler)
-}
-
-func newCorsHandler(srv http.Handler, allowedOrigins []string) http.Handler {
- // disable CORS support if user has not specified a custom CORS configuration
- if len(allowedOrigins) == 0 {
- return srv
- }
- c := cors.New(cors.Options{
- AllowedOrigins: allowedOrigins,
- AllowedMethods: []string{http.MethodPost, http.MethodGet},
- MaxAge: 600,
- AllowedHeaders: []string{"*"},
- })
- return c.Handler(srv)
-}
-
-// virtualHostHandler is a handler which validates the Host-header of incoming requests.
-// Using virtual hosts can help prevent DNS rebinding attacks, where a 'random' domain name points to
-// the service ip address (but without CORS headers). By verifying the targeted virtual host, we can
-// ensure that it's a destination that the node operator has defined.
-type virtualHostHandler struct {
- vhosts map[string]struct{}
- next http.Handler
-}
-
-func newVHostHandler(vhosts []string, next http.Handler) http.Handler {
- vhostMap := make(map[string]struct{})
- for _, allowedHost := range vhosts {
- vhostMap[strings.ToLower(allowedHost)] = struct{}{}
- }
- return &virtualHostHandler{vhostMap, next}
-}
-
-// ServeHTTP serves JSON-RPC requests over HTTP, implements http.Handler
-func (h *virtualHostHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
- // if r.Host is not set, we can continue serving since a browser would set the Host header
- if r.Host == "" {
- h.next.ServeHTTP(w, r)
- return
- }
- host, _, err := net.SplitHostPort(r.Host)
- if err != nil {
- // Either invalid (too many colons) or no port specified
- host = r.Host
- }
- if ipAddr := net.ParseIP(host); ipAddr != nil {
- // It's an IP address, we can serve that
- h.next.ServeHTTP(w, r)
- return
-
- }
- // Not an IP address, but a hostname. Need to validate
- if _, exist := h.vhosts["*"]; exist {
- h.next.ServeHTTP(w, r)
- return
- }
- if _, exist := h.vhosts[host]; exist {
- h.next.ServeHTTP(w, r)
- return
- }
- http.Error(w, "invalid host specified", http.StatusForbidden)
-}
-
-var gzPool = sync.Pool{
- New: func() interface{} {
- w := gzip.NewWriter(ioutil.Discard)
- return w
- },
-}
-
-type gzipResponseWriter struct {
- io.Writer
- http.ResponseWriter
-}
-
-func (w *gzipResponseWriter) WriteHeader(status int) {
- w.Header().Del("Content-Length")
- w.ResponseWriter.WriteHeader(status)
-}
-
-func (w *gzipResponseWriter) Write(b []byte) (int, error) {
- return w.Writer.Write(b)
-}
-
-func newGzipHandler(next http.Handler) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
- next.ServeHTTP(w, r)
- return
- }
-
- w.Header().Set("Content-Encoding", "gzip")
-
- gz := gzPool.Get().(*gzip.Writer)
- defer gzPool.Put(gz)
-
- gz.Reset(w)
- defer gz.Close()
-
- next.ServeHTTP(&gzipResponseWriter{ResponseWriter: w, Writer: gz}, r)
- })
-}
-
-// NewWebsocketUpgradeHandler returns a websocket handler that serves an incoming request only if it contains an upgrade
-// request to the websocket protocol. If not, serves the the request with the http handler.
-func NewWebsocketUpgradeHandler(h http.Handler, ws http.Handler) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- if isWebsocket(r) {
- ws.ServeHTTP(w, r)
- log.Debug("serving websocket request")
- return
- }
-
- h.ServeHTTP(w, r)
- })
-}
-
-// isWebsocket checks the header of an http request for a websocket upgrade request.
-func isWebsocket(r *http.Request) bool {
- return strings.ToLower(r.Header.Get("Upgrade")) == "websocket" &&
- strings.ToLower(r.Header.Get("Connection")) == "upgrade"
-}
diff --git a/node_2/service.go b/node_2/service.go
deleted file mode 100644
index aabafa0737b9..000000000000
--- a/node_2/service.go
+++ /dev/null
@@ -1,133 +0,0 @@
-// Copyright 2015 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package node_2
-
-import (
- "path/filepath"
- "reflect"
-
- "github.com/ethereum/go-ethereum/accounts"
- "github.com/ethereum/go-ethereum/core/rawdb"
- "github.com/ethereum/go-ethereum/ethdb"
- "github.com/ethereum/go-ethereum/event"
- "github.com/ethereum/go-ethereum/p2p"
- "github.com/ethereum/go-ethereum/rpc"
-)
-
-// ServiceContext is a collection of service independent options inherited from
-// the protocol stack, that is passed to all constructors to be optionally used;
-// as well as utility methods to operate on the service environment.
-type ServiceContext struct {
- services map[reflect.Type]Service // Index of the already constructed services
- Config Config
- EventMux *event.TypeMux // Event multiplexer used for decoupled notifications
- AccountManager *accounts.Manager // Account manager created by the node.
-}
-
-// OpenDatabase opens an existing database with the given name (or creates one
-// if no previous can be found) from within the node's data directory. If the
-// node is an ephemeral one, a memory database is returned.
-func (ctx *ServiceContext) OpenDatabase(name string, cache int, handles int, namespace string) (ethdb.Database, error) {
- if ctx.Config.DataDir == "" {
- return rawdb.NewMemoryDatabase(), nil
- }
- return rawdb.NewLevelDBDatabase(ctx.Config.ResolvePath(name), cache, handles, namespace)
-}
-
-// OpenDatabaseWithFreezer opens an existing database with the given name (or
-// creates one if no previous can be found) from within the node's data directory,
-// also attaching a chain freezer to it that moves ancient chain data from the
-// database to immutable append-only files. If the node is an ephemeral one, a
-// memory database is returned.
-func (ctx *ServiceContext) OpenDatabaseWithFreezer(name string, cache int, handles int, freezer string, namespace string) (ethdb.Database, error) {
- if ctx.Config.DataDir == "" {
- return rawdb.NewMemoryDatabase(), nil
- }
- root := ctx.Config.ResolvePath(name)
-
- switch {
- case freezer == "":
- freezer = filepath.Join(root, "ancient")
- case !filepath.IsAbs(freezer):
- freezer = ctx.Config.ResolvePath(freezer)
- }
- return rawdb.NewLevelDBDatabaseWithFreezer(root, cache, handles, freezer, namespace)
-}
-
-// ResolvePath resolves a user path into the data directory if that was relative
-// and if the user actually uses persistent storage. It will return an empty string
-// for emphemeral storage and the user's own input for absolute paths.
-func (ctx *ServiceContext) ResolvePath(path string) string {
- return ctx.Config.ResolvePath(path)
-}
-
-// Service retrieves a currently running service registered of a specific type.
-func (ctx *ServiceContext) Service(service interface{}) error {
- element := reflect.ValueOf(service).Elem()
- if running, ok := ctx.services[element.Type()]; ok {
- element.Set(reflect.ValueOf(running))
- return nil
- }
- return ErrServiceUnknown
-}
-
-// ExtRPCEnabled returns the indicator whether node enables the external
-// RPC(http, ws or graphql).
-func (ctx *ServiceContext) ExtRPCEnabled() bool {
- return ctx.Config.ExtRPCEnabled()
-}
-
-// ServiceConstructor is the function signature of the constructors needed to be
-// registered for service instantiation.
-type ServiceConstructor func(ctx *ServiceContext) (Service, error)
-
-// Backend is an individual protocol that can be registered into a node.
-//
-// Notes:
-//
-// • Backend service life-cycle management is delegated to the node. The backend service is allowed to
-// initialize itself upon creation, but no goroutines should be spun up outside of the
-// Start method.
-type Backend interface {
- // Protocols retrieves the P2P protocols the service wishes to start.
- Protocols() []p2p.Protocol
-
- Service
-}
-
-// TODO document
-type Service interface {
- // APIs retrieves the list of RPC descriptors the service provides
- APIs() []rpc.API
-
- // Start is called after all services have been constructed and the networking
- // layer was also initialized to spawn any goroutines required by the service.
- Start() error
-
- // Stop terminates all goroutines belonging to the service, blocking until they
- // are all terminated.
- Stop() error
-}
-
-// TODO document
-type AuxiliaryService interface {
- Start() error
-
- Stop() error
-}
-
-
From 7f36098628b46c69985a95e57cae775de2a0e2bf Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Thu, 23 Apr 2020 15:51:51 +0200
Subject: [PATCH 004/160] committing progress, eth.ethereum + les.lightethereum
impl backend
---
cmd/faucet/faucet.go | 4 ++--
cmd/utils/flags.go | 4 ++--
eth/backend.go | 23 ++++++++++++---------
ethstats/ethstats.go | 48 ++++++++++++++++++++++++++------------------
les/client.go | 10 +++++++--
miner/miner.go | 2 +-
node/node.go | 9 ++++++++-
7 files changed, 64 insertions(+), 36 deletions(-)
diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go
index 475430e7f95a..a6daaa5dbd38 100644
--- a/cmd/faucet/faucet.go
+++ b/cmd/faucet/faucet.go
@@ -241,7 +241,7 @@ func newFaucet(genesis *core.Genesis, port int, enodes []*discv5.Node, network u
cfg.SyncMode = downloader.LightSync
cfg.NetworkId = network
cfg.Genesis = genesis
- return les.New(ctx, &cfg)
+ return les.New(stack.ServiceContext, &cfg)
}); err != nil {
return nil, err
}
@@ -249,7 +249,7 @@ func newFaucet(genesis *core.Genesis, port int, enodes []*discv5.Node, network u
if stats != "" {
if err := stack.RegisterAuxServiceLifecycle(func(stack *node.Node) (node.AuxiliaryService, error) {
var serv *les.LightEthereum
- return ethstats.New(stack, stats, nil, serv)
+ return ethstats.New(stack, stats, serv)
}); err != nil {
return nil, err
}
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index e179cb9669c9..e256f7747c81 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -1699,8 +1699,8 @@ func RegisterEthService(stack *node.Node, cfg *eth.Config) {
return les.New(ctx, cfg)
})
} else {
- err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
- fullNode, err := eth.New(ctx, cfg)
+ err = stack.RegisterBackendLifecycle(func(node *node.Node) (node.Backend, error) {
+ fullNode, err := eth.New(node.ServiceContext, cfg, node.Server())
if fullNode != nil && cfg.LightServ > 0 {
ls, _ := les.NewLesServer(fullNode, cfg)
fullNode.AddLesServer(ls)
diff --git a/eth/backend.go b/eth/backend.go
index dfdd1f7bdb06..30a57314749f 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -65,6 +65,8 @@ type LesServer interface {
// Ethereum implements the Ethereum full node service.
type Ethereum struct {
+ // TODO needs a p2pServer
+
config *Config
// Handlers
@@ -94,6 +96,8 @@ type Ethereum struct {
networkID uint64
netRPCService *ethapi.PublicNetAPI
+ p2pServer *p2p.Server
+
lock sync.RWMutex // Protects the variadic fields (e.g. gas price and etherbase)
}
@@ -112,7 +116,7 @@ func (s *Ethereum) SetContractBackend(backend bind.ContractBackend) {
// New creates a new Ethereum object (including the
// initialisation of the common Ethereum object)
-func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
+func New(ctx *node.ServiceContext, config *Config, p2pServer *p2p.Server) (*Ethereum, error) {
// Ensure configuration values are compatible and sane
if config.SyncMode == downloader.LightSync {
return nil, errors.New("can't run eth.Ethereum in light sync mode, use les.LightEthereum")
@@ -158,6 +162,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
etherbase: config.Miner.Etherbase,
bloomRequests: make(chan chan *bloombits.Retrieval),
bloomIndexer: NewBloomIndexer(chainDb, params.BloomBitsBlocks, params.BloomConfirms),
+ p2pServer: p2pServer,
}
bcVersion := rawdb.ReadDatabaseVersion(chainDb)
@@ -221,7 +226,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
eth.miner = miner.New(eth, &config.Miner, chainConfig, eth.EventMux(), eth.engine, eth.isLocalBlock)
eth.miner.SetExtra(makeExtraData(config.Miner.ExtraData))
- eth.APIBackend = &EthAPIBackend{ctx.ExtRPCEnabled(), eth, nil}
+ eth.APIBackend = &EthAPIBackend{node.ServiceContext.ExtRPCEnabled(), eth, nil}
gpoParams := config.GPO
if gpoParams.Default == nil {
gpoParams.Default = config.Miner.GasPrice
@@ -535,27 +540,27 @@ func (s *Ethereum) Protocols() []p2p.Protocol {
// Start implements node.Service, starting all internal goroutines needed by the
// Ethereum protocol implementation.
-func (s *Ethereum) Start(srvr *p2p.Server) error {
- s.startEthEntryUpdate(srvr.LocalNode())
+func (s *Ethereum) Start() error {
+ s.startEthEntryUpdate(s.p2pServer.LocalNode())
// Start the bloom bits servicing goroutines
s.startBloomHandlers(params.BloomBitsBlocks)
// Start the RPC service
- s.netRPCService = ethapi.NewPublicNetAPI(srvr, s.NetVersion())
+ s.netRPCService = ethapi.NewPublicNetAPI(s.p2pServer, s.NetVersion())
// Figure out a max peers count based on the server limits
- maxPeers := srvr.MaxPeers
+ maxPeers := s.p2pServer.MaxPeers
if s.config.LightServ > 0 {
- if s.config.LightPeers >= srvr.MaxPeers {
- return fmt.Errorf("invalid peer config: light peer count (%d) >= total peer count (%d)", s.config.LightPeers, srvr.MaxPeers)
+ if s.config.LightPeers >= s.p2pServer.MaxPeers {
+ return fmt.Errorf("invalid peer config: light peer count (%d) >= total peer count (%d)", s.config.LightPeers, s.p2pServer.MaxPeers)
}
maxPeers -= s.config.LightPeers
}
// Start the networking layer and the light server if requested
s.protocolManager.Start(maxPeers)
if s.lesServer != nil {
- s.lesServer.Start(srvr)
+ s.lesServer.Start(s.p2pServer)
}
return nil
}
diff --git a/ethstats/ethstats.go b/ethstats/ethstats.go
index 7d630f7b9cf7..5847406d1b3e 100644
--- a/ethstats/ethstats.go
+++ b/ethstats/ethstats.go
@@ -83,31 +83,41 @@ type Service struct {
}
// New returns a monitoring service ready for stats reporting.
-func New(node *node.Node, url string, ethServ *eth.Ethereum, lesServ *les.LightEthereum) (node.AuxiliaryService, error) {
+func New(node *node.Node, url string, backend node.Backend) (node.AuxiliaryService, error) {
// Parse the netstats connection url
re := regexp.MustCompile("([^:@]*)(:([^@]*))?@(.+)")
parts := re.FindStringSubmatch(url)
if len(parts) != 5 {
return nil, fmt.Errorf("invalid netstats url: \"%s\", should be nodename:secret@host:port", url)
}
- // Assemble and return the stats service
- var engine consensus.Engine
- if ethServ != nil {
- engine = ethServ.Engine()
- } else {
- engine = lesServ.Engine()
- }
- return &Service{
- server: node.Server(),
- eth: ethServ,
- les: lesServ,
- engine: engine,
- node: parts[1],
- pass: parts[3],
- host: parts[4],
- pongCh: make(chan struct{}),
- histCh: make(chan []uint64, 1),
- }, nil
+
+ // fetch type of Backend
+ if ethBackend, ok := backend.(*eth.Ethereum); ok {
+ return &Service{
+ server: node.Server(),
+ eth: ethBackend,
+ les: nil, // TODO is this okay?
+ engine: ethBackend.Engine(),
+ node: parts[1],
+ pass: parts[3],
+ host: parts[4],
+ pongCh: make(chan struct{}),
+ histCh: make(chan []uint64, 1),
+ }, nil
+ } else if lesBackend, ok := backend.(*les.LightEthereum); ok {
+ return &Service{
+ server: node.Server(),
+ eth: nil, // TODO is this okay?
+ les: lesBackend,
+ engine: lesBackend.Engine(),
+ node: parts[1],
+ pass: parts[3],
+ host: parts[4],
+ pongCh: make(chan struct{}),
+ histCh: make(chan []uint64, 1),
+ }, nil
+ }
+ return nil, errors.New("ethstats backend is of unidentified type") // TODO is this okay to return?
}
// Start implements node.Service, starting up the monitoring and reporting daemon.
diff --git a/les/client.go b/les/client.go
index a3ae647517c8..430e37d56c82 100644
--- a/les/client.go
+++ b/les/client.go
@@ -72,6 +72,8 @@ type LightEthereum struct {
engine consensus.Engine
accountManager *accounts.Manager
netRPCService *ethapi.PublicNetAPI
+
+ p2pServer *p2p.Server
}
func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
@@ -278,7 +280,7 @@ func (s *LightEthereum) Protocols() []p2p.Protocol {
// Start implements node.Service, starting all internal goroutines needed by the
// light ethereum protocol implementation.
-func (s *LightEthereum) Start(srvr *p2p.Server) error {
+func (s *LightEthereum) Start() error {
log.Warn("Light client mode is an experimental feature")
s.serverPool.start()
@@ -287,7 +289,11 @@ func (s *LightEthereum) Start(srvr *p2p.Server) error {
s.startBloomHandlers(params.BloomBitsBlocksClient)
s.handler.start()
- s.netRPCService = ethapi.NewPublicNetAPI(srvr, s.config.NetworkId)
+ s.netRPCService = ethapi.NewPublicNetAPI(s.p2pServer, s.config.NetworkId)
+
+ // clients are searching for the first advertised protocol in the list
+ protocolVersion := AdvertiseProtocolVersions[0]
+ s.serverPool.start(s.p2pServer, lesTopic(s.blockchain.Genesis().Hash(), protocolVersion))
return nil
}
diff --git a/miner/miner.go b/miner/miner.go
index 5249118cae14..d7d5872dba2f 100644
--- a/miner/miner.go
+++ b/miner/miner.go
@@ -36,7 +36,7 @@ import (
)
// Backend wraps all methods required for mining.
-type Backend interface {
+type Backend interface {
BlockChain() *core.BlockChain
TxPool() *core.TxPool
}
diff --git a/node/node.go b/node/node.go
index 14bc99b726bc..5732319455ce 100644
--- a/node/node.go
+++ b/node/node.go
@@ -49,8 +49,10 @@ type Node struct {
// TODO: removed p2pConfig b/c p2pServer already contains p2pConfig (is there a reason for it to be duplicated?
server *p2p.Server // Currently running P2P networking layer
+ ServiceContext *ServiceContext
+
serviceConstructors []ServiceConstructor // Service constructors (in dependency order)
- auxServiceConstructors []AuxiliarServiceConstructor // AuxiliaryService constructors
+ auxServiceConstructors []AuxiliaryServiceConstructor // AuxiliaryService constructors
backend Backend // The registered Backend of the node
services map[reflect.Type]Service // Currently running services
@@ -106,6 +108,9 @@ func New(conf *Config) (*Node, error) {
// Note: any interaction with Config that would create/touch files
// in the data directory or instance directory is delayed until Start.
return &Node{
+ ServiceContext: &ServiceContext{
+ Config: *conf,
+ },
accman: am,
ephemeralKeystore: ephemeralKeystore,
config: conf,
@@ -221,6 +226,8 @@ func (n *Node) Start() error {
return err
}
+ // TODO make sure to fill out servicecontext as you go
+
// Initialize the p2p server. This creates the node key and
// discovery databases.
n.serverConfig = n.config.P2P
From bc838a297d485c12ff46a919ad81b5fd9fbc2eee Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Thu, 23 Apr 2020 17:32:43 +0200
Subject: [PATCH 005/160] not working yet, but committing progress
---
eth/backend.go | 2 +-
ethstats/ethstats.go | 4 +-
graphql/service.go | 66 +++++-----
node/api.go | 10 +-
node/config.go | 14 +-
node/config_test.go | 2 +-
node/doc.go | 6 +-
node/endpoints.go | 8 +-
node/node.go | 301 +++++++++++++++++++++++--------------------
node/node_test.go | 2 +-
node/rpcstack.go | 23 +++-
node/service.go | 6 +-
12 files changed, 241 insertions(+), 203 deletions(-)
diff --git a/eth/backend.go b/eth/backend.go
index 30a57314749f..7d46485ee220 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -226,7 +226,7 @@ func New(ctx *node.ServiceContext, config *Config, p2pServer *p2p.Server) (*Ethe
eth.miner = miner.New(eth, &config.Miner, chainConfig, eth.EventMux(), eth.engine, eth.isLocalBlock)
eth.miner.SetExtra(makeExtraData(config.Miner.ExtraData))
- eth.APIBackend = &EthAPIBackend{node.ServiceContext.ExtRPCEnabled(), eth, nil}
+ eth.APIBackend = &EthAPIBackend{ctx.ExtRPCEnabled(), eth, nil}
gpoParams := config.GPO
if gpoParams.Default == nil {
gpoParams.Default = config.Miner.GasPrice
diff --git a/ethstats/ethstats.go b/ethstats/ethstats.go
index 5847406d1b3e..17857d5492dc 100644
--- a/ethstats/ethstats.go
+++ b/ethstats/ethstats.go
@@ -134,9 +134,7 @@ func (s *Service) Stop() error {
return nil
}
-func (s *Service) Server() (*node.HttpServer, error) {
- return nil, nil
-}
+func (s *Service) Server() *node.HttpServer { return nil }
// loop keeps trying to connect to the netstats server, reporting chain events
// until termination.
diff --git a/graphql/service.go b/graphql/service.go
index a20605302497..1f4d31356f27 100644
--- a/graphql/service.go
+++ b/graphql/service.go
@@ -24,7 +24,6 @@ import (
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
- "github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/rpc"
"github.com/graph-gophers/graphql-go"
"github.com/graph-gophers/graphql-go/relay"
@@ -32,56 +31,53 @@ import (
// Service encapsulates a GraphQL service.
type Service struct {
- endpoint string // The host:port endpoint for this service.
- cors []string // Allowed CORS domains
- vhosts []string // Recognised vhosts
- timeouts rpc.HTTPTimeouts // Timeout settings for HTTP requests.
backend ethapi.Backend // The backend that queries will operate on.
- handler http.Handler // The `http.Handler` used to answer queries.
- listener net.Listener // The listening socket.
+ graphqlServer *node.HttpServer
}
// New constructs a new GraphQL service instance.
func New(backend ethapi.Backend, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) (*Service, error) {
- return &Service{
- endpoint: endpoint,
- cors: cors,
- vhosts: vhosts,
- timeouts: timeouts,
+ service := &Service{
backend: backend,
- }, nil
+ graphqlServer: &node.HttpServer{
+ Timeouts: timeouts,
+ Vhosts: vhosts,
+ CorsAllowedOrigins: cors,
+ },
+ }
+ service.graphqlServer.SetEndpoint(endpoint)
+ return service, nil
}
-// Protocols returns the list of protocols exported by this service.
-func (s *Service) Protocols() []p2p.Protocol { return nil }
-
-// APIs returns the list of APIs exported by this service.
-func (s *Service) APIs() []rpc.API { return nil }
-
// Start is called after all services have been constructed and the networking
// layer was also initialized to spawn any goroutines required by the service.
-func (s *Service) Start(server *p2p.Server) error {
+func (s *Service) Start() error {
var err error
- s.handler, err = newHandler(s.backend)
+ handler, err := newHandler(s.backend)
if err != nil {
return err
}
- if s.listener, err = net.Listen("tcp", s.endpoint); err != nil {
+
+ listener, err := net.Listen("tcp", s.graphqlServer.Endpoint())
+ if err != nil {
return err
}
// create handler stack and wrap the graphql handler
- handler := node.NewHTTPHandlerStack(s.handler, s.cors, s.vhosts)
+ handler = node.NewHTTPHandlerStack(handler, s.graphqlServer.CorsAllowedOrigins, s.graphqlServer.Vhosts)
// make sure timeout values are meaningful
- node.CheckTimeouts(&s.timeouts)
+ node.CheckTimeouts(&s.graphqlServer.Timeouts)
// create http server
httpSrv := &http.Server{
Handler: handler,
- ReadTimeout: s.timeouts.ReadTimeout,
- WriteTimeout: s.timeouts.WriteTimeout,
- IdleTimeout: s.timeouts.IdleTimeout,
+ ReadTimeout: s.graphqlServer.Timeouts.ReadTimeout,
+ WriteTimeout: s.graphqlServer.Timeouts.WriteTimeout,
+ IdleTimeout: s.graphqlServer.Timeouts.IdleTimeout,
}
- go httpSrv.Serve(s.listener)
- log.Info("GraphQL endpoint opened", "url", fmt.Sprintf("http://%s", s.endpoint))
+ go httpSrv.Serve(listener)
+ log.Info("GraphQL endpoint opened", "url", fmt.Sprintf("http://%s", s.graphqlServer.Endpoint))
+ // add information to graphql http server
+ s.graphqlServer.Listener = listener
+ s.graphqlServer.SetHandler(handler)
return nil
}
@@ -106,10 +102,14 @@ func newHandler(backend ethapi.Backend) (http.Handler, error) {
// Stop terminates all goroutines belonging to the service, blocking until they
// are all terminated.
func (s *Service) Stop() error {
- if s.listener != nil {
- s.listener.Close()
- s.listener = nil
- log.Info("GraphQL endpoint closed", "url", fmt.Sprintf("http://%s", s.endpoint))
+ if s.graphqlServer.Listener != nil {
+ s.graphqlServer.Listener.Close()
+ s.graphqlServer.Listener = nil
+ log.Info("GraphQL endpoint closed", "url", fmt.Sprintf("http://%s", s.graphqlServer.Endpoint))
}
return nil
}
+
+func (s *Service) Server() *node.HttpServer {
+ return s.graphqlServer
+}
diff --git a/node/api.go b/node/api.go
index 1a73d1321db5..df2b2cd69405 100644
--- a/node/api.go
+++ b/node/api.go
@@ -148,7 +148,7 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
defer api.node.lock.Unlock()
if api.node.httpHandler != nil {
- return false, fmt.Errorf("HTTP RPC already running on %s", api.node.httpEndpoint)
+ return false, fmt.Errorf("HTTP RPC already running on %s", api.node.httpHandler.Endpoint)
}
if host == nil {
@@ -178,7 +178,7 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
}
}
- modules := api.node.httpWhitelist
+ modules := api.node.httpHandler.Whitelist
if apis != nil {
modules = nil
for _, m := range strings.Split(*apis, ",") {
@@ -192,7 +192,7 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
return true, nil
}
-// StopRPC terminates an already running HTTP RPC API endpoint.
+// StopRPC terminates an already running HTTP RPC API Endpoint.
func (api *PrivateAdminAPI) StopRPC() (bool, error) {
api.node.lock.Lock()
defer api.node.lock.Unlock()
@@ -210,7 +210,7 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
defer api.node.lock.Unlock()
if api.node.wsHandler != nil {
- return false, fmt.Errorf("WebSocket RPC already running on %s", api.node.wsEndpoint)
+ return false, fmt.Errorf("WebSocket RPC already running on %s", api.node.wsHandler.Endpoint)
}
if host == nil {
@@ -246,7 +246,7 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
return true, nil
}
-// StopWS terminates an already running websocket RPC API endpoint.
+// StopWS terminates an already running websocket RPC API Endpoint.
func (api *PrivateAdminAPI) StopWS() (bool, error) {
api.node.lock.Lock()
defer api.node.lock.Unlock()
diff --git a/node/config.go b/node/config.go
index 61566b7bee9b..d0c25c125b55 100644
--- a/node/config.go
+++ b/node/config.go
@@ -98,7 +98,7 @@ type Config struct {
// SmartCardDaemonPath is the path to the smartcard daemon's socket
SmartCardDaemonPath string `toml:",omitempty"`
- // IPCPath is the requested location to place the IPC endpoint. If the path is
+ // IPCPath is the requested location to place the IPC Endpoint. If the path is
// a simple file name, it is placed inside the data directory (or on the root
// pipe path on Windows), whereas if it's a resolvable path name (absolute or
// relative), then that specific path is enforced. An empty path disables IPC.
@@ -193,7 +193,7 @@ type Config struct {
oldGethResourceWarning bool
}
-// IPCEndpoint resolves an IPC endpoint based on a configured value, taking into
+// IPCEndpoint resolves an IPC Endpoint based on a configured value, taking into
// account the set data folders as well as the designated platform we're currently
// running on.
func (c *Config) IPCEndpoint() string {
@@ -238,7 +238,7 @@ func DefaultIPCEndpoint(clientIdentifier string) string {
return config.IPCEndpoint()
}
-// HTTPEndpoint resolves an HTTP endpoint based on the configured host interface
+// HTTPEndpoint resolves an HTTP Endpoint based on the configured host interface
// and port parameters.
func (c *Config) HTTPEndpoint() string {
if c.HTTPHost == "" {
@@ -247,7 +247,7 @@ func (c *Config) HTTPEndpoint() string {
return fmt.Sprintf("%s:%d", c.HTTPHost, c.HTTPPort)
}
-// GraphQLEndpoint resolves a GraphQL endpoint based on the configured host interface
+// GraphQLEndpoint resolves a GraphQL Endpoint based on the configured host interface
// and port parameters.
func (c *Config) GraphQLEndpoint() string {
if c.GraphQLHost == "" {
@@ -256,13 +256,13 @@ func (c *Config) GraphQLEndpoint() string {
return fmt.Sprintf("%s:%d", c.GraphQLHost, c.GraphQLPort)
}
-// DefaultHTTPEndpoint returns the HTTP endpoint used by default.
+// DefaultHTTPEndpoint returns the HTTP Endpoint used by default.
func DefaultHTTPEndpoint() string {
config := &Config{HTTPHost: DefaultHTTPHost, HTTPPort: DefaultHTTPPort}
return config.HTTPEndpoint()
}
-// WSEndpoint resolves a websocket endpoint based on the configured host interface
+// WSEndpoint resolves a websocket Endpoint based on the configured host interface
// and port parameters.
func (c *Config) WSEndpoint() string {
if c.WSHost == "" {
@@ -271,7 +271,7 @@ func (c *Config) WSEndpoint() string {
return fmt.Sprintf("%s:%d", c.WSHost, c.WSPort)
}
-// DefaultWSEndpoint returns the websocket endpoint used by default.
+// DefaultWSEndpoint returns the websocket Endpoint used by default.
func DefaultWSEndpoint() string {
config := &Config{WSHost: DefaultWSHost, WSPort: DefaultWSPort}
return config.WSEndpoint()
diff --git a/node/config_test.go b/node/config_test.go
index 00c24a239123..17c473f655d2 100644
--- a/node/config_test.go
+++ b/node/config_test.go
@@ -99,7 +99,7 @@ func TestIPCPathResolution(t *testing.T) {
// Only run when platform/test match
if (runtime.GOOS == "windows") == test.Windows {
if endpoint := (&Config{DataDir: test.DataDir, IPCPath: test.IPCPath}).IPCEndpoint(); endpoint != test.Endpoint {
- t.Errorf("test %d: IPC endpoint mismatch: have %s, want %s", i, endpoint, test.Endpoint)
+ t.Errorf("test %d: IPC Endpoint mismatch: have %s, want %s", i, endpoint, test.Endpoint)
}
}
}
diff --git a/node/doc.go b/node/doc.go
index e3cc58e5f49c..3c6b696b3218 100644
--- a/node/doc.go
+++ b/node/doc.go
@@ -36,7 +36,7 @@ about other hosts is persisted.
JSON-RPC servers which run HTTP, WebSocket or IPC can be started on a Node. RPC modules
offered by registered services will be offered on those endpoints. Users can restrict any
-endpoint to a subset of RPC modules. Node itself offers the "debug", "admin" and "web3"
+Endpoint to a subset of RPC modules. Node itself offers the "debug", "admin" and "web3"
modules.
Service implementations can open LevelDB databases through the service context. Package
@@ -77,14 +77,14 @@ directory. Node instance A opens the database "db", node instance B opens the da
nodekey -- devp2p node key of instance A
nodes/ -- devp2p discovery knowledge database of instance A
db/ -- LevelDB content for "db"
- A.ipc -- JSON-RPC UNIX domain socket endpoint of instance A
+ A.ipc -- JSON-RPC UNIX domain socket Endpoint of instance A
B/
nodekey -- devp2p node key of node B
nodes/ -- devp2p discovery knowledge database of instance B
static-nodes.json -- devp2p static node list of instance B
db/ -- LevelDB content for "db"
db-2/ -- LevelDB content for "db-2"
- B.ipc -- JSON-RPC UNIX domain socket endpoint of instance B
+ B.ipc -- JSON-RPC UNIX domain socket Endpoint of instance B
keystore/ -- account key store, used by both instances
*/
package node
diff --git a/node/endpoints.go b/node/endpoints.go
index 1baa1b5c417f..13479b88a191 100644
--- a/node/endpoints.go
+++ b/node/endpoints.go
@@ -25,8 +25,8 @@ import (
"github.com/ethereum/go-ethereum/rpc"
)
-// StartHTTPEndpoint starts the HTTP RPC endpoint.
-func StartHTTPEndpoint(endpoint string, timeouts rpc.HTTPTimeouts, handler http.Handler) (*http.Server, net.Addr, error) {
+// StartHTTPEndpoint starts the HTTP RPC Endpoint.
+func StartHTTPEndpoint(endpoint string, timeouts rpc.HTTPTimeouts, handler http.Handler) (net.Listener, error) {
// start the HTTP listener
var (
listener net.Listener
@@ -48,8 +48,8 @@ func StartHTTPEndpoint(endpoint string, timeouts rpc.HTTPTimeouts, handler http.
return httpSrv, listener.Addr(), err
}
-// startWSEndpoint starts a websocket endpoint.
-func startWSEndpoint(endpoint string, handler http.Handler) (*http.Server, net.Addr, error) {
+// startWSEndpoint starts a websocket Endpoint.
+func startWSEndpoint(endpoint string, handler http.Handler) (net.Listener, error) {
// start the HTTP listener
var (
listener net.Listener
diff --git a/node/node.go b/node/node.go
index 5732319455ce..e65b0dc63b56 100644
--- a/node/node.go
+++ b/node/node.go
@@ -47,15 +47,12 @@ type Node struct {
instanceDirLock fileutil.Releaser // prevents concurrent use of instance directory
// TODO: removed p2pConfig b/c p2pServer already contains p2pConfig (is there a reason for it to be duplicated?
- server *p2p.Server // Currently running P2P networking layer
+ server *p2p.Server // Currently running P2P networking layer
ServiceContext *ServiceContext
- serviceConstructors []ServiceConstructor // Service constructors (in dependency order)
- auxServiceConstructors []AuxiliaryServiceConstructor // AuxiliaryService constructors
-
- backend Backend // The registered Backend of the node
- services map[reflect.Type]Service // Currently running services
+ backend Backend // The registered Backend of the node
+ services map[reflect.Type]Service // Currently running services
auxServices map[reflect.Type]AuxiliaryService // Currently running auxiliary services
rpcAPIs []rpc.API // List of APIs currently provided by the node
@@ -108,18 +105,25 @@ func New(conf *Config) (*Node, error) {
// Note: any interaction with Config that would create/touch files
// in the data directory or instance directory is delayed until Start.
return &Node{
- ServiceContext: &ServiceContext{
- Config: *conf,
- },
accman: am,
ephemeralKeystore: ephemeralKeystore,
config: conf,
- serviceFuncs: []ServiceConstructor{},
- ipcEndpoint: conf.IPCEndpoint(),
- httpEndpoint: conf.HTTPEndpoint(),
- wsEndpoint: conf.WSEndpoint(),
- eventmux: new(event.TypeMux),
- log: conf.Logger,
+ ServiceContext: &ServiceContext{
+ Config: *conf,
+ },
+ services: make(map[reflect.Type]Service),
+ auxServices: make(map[reflect.Type]AuxiliaryService),
+ ipcHandler: &HttpServer{
+ endpoint: conf.IPCEndpoint(),
+ },
+ httpHandler: &HttpServer{
+ endpoint: conf.HTTPEndpoint(),
+ },
+ wsHandler: &HttpServer{
+ endpoint: conf.WSEndpoint(),
+ },
+ eventmux: new(event.TypeMux),
+ log: conf.Logger,
}, nil
}
@@ -147,7 +151,7 @@ func (n *Node) Close() error {
}
// TODO document
-func (n * Node) RegisterBackendLifecycle(constructor BackendConstructor) error {
+func (n *Node) RegisterBackendLifecycle(constructor BackendConstructor) error {
n.lock.Lock()
defer n.lock.Unlock()
@@ -226,87 +230,89 @@ func (n *Node) Start() error {
return err
}
- // TODO make sure to fill out servicecontext as you go
-
// Initialize the p2p server. This creates the node key and
// discovery databases.
- n.serverConfig = n.config.P2P
- n.serverConfig.PrivateKey = n.config.NodeKey()
- n.serverConfig.Name = n.config.NodeName()
- n.serverConfig.Logger = n.log
- if n.serverConfig.StaticNodes == nil {
- n.serverConfig.StaticNodes = n.config.StaticNodes()
- }
- if n.serverConfig.TrustedNodes == nil {
- n.serverConfig.TrustedNodes = n.config.TrustedNodes()
- }
- if n.serverConfig.NodeDatabase == "" {
- n.serverConfig.NodeDatabase = n.config.NodeDB()
- }
- running := &p2p.Server{Config: n.serverConfig}
- n.log.Info("Starting peer-to-peer node", "instance", n.serverConfig.Name)
-
- // Otherwise copy and specialize the P2P configuration
- services := make(map[reflect.Type]Service)
- //for _, constructor := range n.serviceFuncs {
- // // Create a new context for the particular service
- // ctx := &ServiceContext{
- // Config: *n.config,
- // services: make(map[reflect.Type]Service),
- // EventMux: n.eventmux,
- // AccountManager: n.accman,
- // }
- // for kind, s := range services { // copy needed for threaded access
- // ctx.services[kind] = s
- // }
- // // Construct and save the service
- // service, err := constructor(ctx)
- // if err != nil {
- // return err
- // }
- // kind := reflect.TypeOf(service)
- // if _, exists := services[kind]; exists {
- // return &DuplicateServiceError{Kind: kind}
- // }
- // services[kind] = service
- //}
- // Gather the protocols and start the freshly assembled P2P server
- for _, service := range services {
- running.Protocols = append(running.Protocols, service.Protocols()...)
+ n.server.Config = n.config.P2P
+ n.server.PrivateKey = n.config.NodeKey()
+ n.server.Name = n.config.NodeName()
+ n.server.Logger = n.log
+ if n.server.StaticNodes == nil {
+ n.server.StaticNodes = n.config.StaticNodes()
+ }
+ if n.server.TrustedNodes == nil {
+ n.server.TrustedNodes = n.config.TrustedNodes()
+ }
+ if n.server.NodeDatabase == "" {
+ n.server.NodeDatabase = n.config.NodeDB()
}
+ running := &p2p.Server{Config: n.server.Config}
+ n.log.Info("Starting peer-to-peer node", "instance", n.server.Name)
+
+ // add backend's protocols to the o2o server
+ running.Protocols = append(running.Protocols, n.backend.Protocols()...)
if err := running.Start(); err != nil {
return convertFileLockError(err)
}
+ // Start the backend
+ if err := n.backend.Start(); err != nil {
+ running.Stop()
+ return err
+ }
// Start each of the services
- var started []reflect.Type
- for kind, service := range services {
+ var startedServices []reflect.Type
+ for kind, service := range n.services {
// Start the next service, stopping all previous upon failure
- if err := service.Start(running); err != nil {
- for _, kind := range started {
- services[kind].Stop()
- }
+ if err := service.Start(); err != nil {
+ n.stopAllStartedServices(startedServices, nil) // TODO safe to pass nil here?
+ running.Stop()
+
+ return err
+ }
+ // Mark the service started for potential cleanup
+ startedServices = append(startedServices, kind)
+ }
+ // Start each of the auxiliary services
+ var startedAuxServices []reflect.Type
+ for kind, auxService := range n.auxServices {
+ // Start the next auxiliary service, stopping all previous upon failure
+ if err := auxService.Start(); err != nil {
+ n.stopAllStartedServices(startedServices, startedAuxServices)
running.Stop()
return err
}
// Mark the service started for potential cleanup
- started = append(started, kind)
+ startedAuxServices = append(startedAuxServices, kind)
}
// Lastly, start the configured RPC interfaces
- if err := n.startRPC(services); err != nil {
- for _, service := range services {
- service.Stop()
- }
+ if err := n.startRPC(); err != nil {
+ n.stopAllStartedServices(startedServices, startedAuxServices)
running.Stop()
return err
}
+ // Finish initializing the service context
+ n.ServiceContext.backend = n.backend
+ n.ServiceContext.AccountManager = n.accman
+ n.ServiceContext.EventMux = n.eventmux
+ n.ServiceContext.services = n.services
+ n.ServiceContext.auxServices = n.auxServices
+
// Finish initializing the startup
- n.services = services
n.server = running
n.stop = make(chan struct{})
return nil
}
+func (n *Node) stopAllStartedServices(startedServices []reflect.Type, startedAuxServices []reflect.Type) {
+ n.backend.Stop()
+ for _, kind := range startedServices {
+ n.services[kind].Stop()
+ }
+ for _, kind := range startedAuxServices {
+ n.auxServices[kind].Stop()
+ }
+}
+
// Config returns the configuration of node.
func (n *Node) Config() *Config {
return n.config
@@ -334,10 +340,11 @@ func (n *Node) openDataDir() error {
// startRPC is a helper method to start all the various RPC endpoints during node
// startup. It's not meant to be called at any time afterwards as it makes certain
// assumptions about the state of the node.
-func (n *Node) startRPC(services map[reflect.Type]Service) error {
+func (n *Node) startRPC() error {
// Gather all the possible APIs to surface
apis := n.apis()
- for _, service := range services {
+ apis = append(apis, n.backend.APIs()...)
+ for _, service := range n.services {
apis = append(apis, service.APIs()...)
}
// Start the various API endpoints, terminating all in case of errors
@@ -348,14 +355,14 @@ func (n *Node) startRPC(services map[reflect.Type]Service) error {
n.stopInProc()
return err
}
- if err := n.startHTTP(n.httpEndpoint, apis, n.config.HTTPModules, n.config.HTTPCors, n.config.HTTPVirtualHosts, n.config.HTTPTimeouts, n.config.WSOrigins); err != nil {
+ if err := n.startHTTP(n.httpHandler.Endpoint(), apis, n.config.HTTPModules, n.config.HTTPCors, n.config.HTTPVirtualHosts, n.config.HTTPTimeouts, n.config.WSOrigins); err != nil {
n.stopIPC()
n.stopInProc()
return err
}
// if endpoints are not the same, start separate servers
- if n.httpEndpoint != n.wsEndpoint {
- if err := n.startWS(n.wsEndpoint, apis, n.config.WSModules, n.config.WSOrigins, n.config.WSExposeAll); err != nil {
+ if n.httpHandler.Endpoint() != n.wsHandler.Endpoint() {
+ if err := n.startWS(n.wsHandler.Endpoint(), apis, n.config.WSModules, n.config.WSOrigins, n.config.WSExposeAll); err != nil {
n.stopHTTP()
n.stopIPC()
n.stopInProc()
@@ -368,7 +375,7 @@ func (n *Node) startRPC(services map[reflect.Type]Service) error {
return nil
}
-// startInProc initializes an in-process RPC endpoint.
+// startInProc initializes an in-process RPC Endpoint.
func (n *Node) startInProc(apis []rpc.API) error {
// Register all the APIs exposed by the services
handler := rpc.NewServer()
@@ -382,7 +389,7 @@ func (n *Node) startInProc(apis []rpc.API) error {
return nil
}
-// stopInProc terminates the in-process RPC endpoint.
+// stopInProc terminates the in-process RPC Endpoint.
func (n *Node) stopInProc() {
if n.inprocHandler != nil {
n.inprocHandler.Stop()
@@ -390,38 +397,38 @@ func (n *Node) stopInProc() {
}
}
-// startIPC initializes and starts the IPC RPC endpoint.
+// startIPC initializes and starts the IPC RPC Endpoint.
func (n *Node) startIPC(apis []rpc.API) error {
- if n.ipcEndpoint == "" {
+ if n.ipcHandler.Endpoint() == "" {
return nil // IPC disabled.
}
- listener, handler, err := rpc.StartIPCEndpoint(n.ipcEndpoint, apis)
+ listener, handler, err := rpc.StartIPCEndpoint(n.ipcHandler.Endpoint(), apis)
if err != nil {
return err
}
- n.ipcListener = listener
- n.ipcHandler = handler
- n.log.Info("IPC endpoint opened", "url", n.ipcEndpoint)
+ n.ipcHandler.Listener = listener
+ n.ipcHandler.handler = handler
+ n.log.Info("IPC Endpoint opened", "url", n.ipcHandler.Endpoint())
return nil
}
-// stopIPC terminates the IPC RPC endpoint.
+// stopIPC terminates the IPC RPC Endpoint.
func (n *Node) stopIPC() {
- if n.ipcListener != nil {
- n.ipcListener.Close()
- n.ipcListener = nil
+ if n.ipcHandler.Listener != nil {
+ n.ipcHandler.Listener.Close()
+ n.ipcHandler.Listener = nil
- n.log.Info("IPC endpoint closed", "url", n.ipcEndpoint)
+ n.log.Info("IPC Endpoint closed", "url", n.ipcHandler.Endpoint())
}
- if n.ipcHandler != nil {
- n.ipcHandler.Stop()
- n.ipcHandler = nil
+ if n.ipcHandler.Srv != nil {
+ n.ipcHandler.Srv.Stop()
+ n.ipcHandler.Srv = nil
}
}
-// startHTTP initializes and starts the HTTP RPC endpoint.
+// startHTTP initializes and starts the HTTP RPC Endpoint.
func (n *Node) startHTTP(endpoint string, apis []rpc.API, modules []string, cors []string, vhosts []string, timeouts rpc.HTTPTimeouts, wsOrigins []string) error {
- // Short circuit if the HTTP endpoint isn't being exposed
+ // Short circuit if the HTTP Endpoint isn't being exposed
if endpoint == "" {
return nil
}
@@ -432,45 +439,45 @@ func (n *Node) startHTTP(endpoint string, apis []rpc.API, modules []string, cors
return err
}
handler := NewHTTPHandlerStack(srv, cors, vhosts)
- // wrap handler in WebSocket handler only if WebSocket port is the same as http rpc
- if n.httpEndpoint == n.wsEndpoint {
+ // wrap handler in websocket handler only if websocket port is the same as http rpc
+ if n.httpHandler.Endpoint() == n.wsHandler.Endpoint() {
handler = NewWebsocketUpgradeHandler(handler, srv.WebsocketHandler(wsOrigins))
}
httpServer, addr, err := StartHTTPEndpoint(endpoint, timeouts, handler)
if err != nil {
return err
}
- n.log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%v/", addr),
+ n.log.Info("HTTP Endpoint opened", "url", fmt.Sprintf("http://%v/", listener.Addr()),
"cors", strings.Join(cors, ","),
"vhosts", strings.Join(vhosts, ","))
- if n.httpEndpoint == n.wsEndpoint {
- n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", addr))
+ if n.httpHandler.Endpoint() == n.wsHandler.Endpoint() {
+ n.log.Info("WebSocket Endpoint opened", "url", fmt.Sprintf("ws://%v", listener.Addr()))
}
// All listeners booted successfully
- n.httpEndpoint = endpoint
- n.httpListenerAddr = addr
- n.httpServer = httpServer
- n.httpHandler = srv
+ n.httpHandler.endpoint = endpoint
+ n.httpHandler.Listener = listener
+ n.httpHandler.Srv = srv
return nil
}
-// stopHTTP terminates the HTTP RPC endpoint.
+// stopHTTP terminates the HTTP RPC Endpoint.
func (n *Node) stopHTTP() {
- if n.httpServer != nil {
- // Don't bother imposing a timeout here.
- n.httpServer.Shutdown(context.Background())
- n.log.Info("HTTP endpoint closed", "url", fmt.Sprintf("http://%v/", n.httpListenerAddr))
+ if n.httpHandler.Listener != nil {
+ url := fmt.Sprintf("http://%v/", n.httpHandler.Listener.Addr())
+ n.httpHandler.Listener.Close()
+ n.httpHandler.Listener = nil
+ n.log.Info("HTTP Endpoint closed", "url", url)
}
- if n.httpHandler != nil {
- n.httpHandler.Stop()
- n.httpHandler = nil
+ if n.httpHandler.Srv != nil {
+ n.httpHandler.Srv.Stop()
+ n.httpHandler.Srv = nil
}
}
-// startWS initializes and starts the WebSocket RPC endpoint.
+// startWS initializes and starts the websocket RPC Endpoint.
func (n *Node) startWS(endpoint string, apis []rpc.API, modules []string, wsOrigins []string, exposeAll bool) error {
- // Short circuit if the WS endpoint isn't being exposed
+ // Short circuit if the WS Endpoint isn't being exposed
if endpoint == "" {
return nil
}
@@ -485,26 +492,26 @@ func (n *Node) startWS(endpoint string, apis []rpc.API, modules []string, wsOrig
if err != nil {
return err
}
- n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", addr))
+ n.log.Info("WebSocket Endpoint opened", "url", fmt.Sprintf("ws://%s", listener.Addr()))
// All listeners booted successfully
- n.wsEndpoint = endpoint
- n.wsListenerAddr = addr
- n.wsHTTPServer = httpServer
- n.wsHandler = srv
+ n.wsHandler.endpoint = endpoint
+ n.wsHandler.Listener = listener
+ n.wsHandler.Srv = srv
return nil
}
-// stopWS terminates the WebSocket RPC endpoint.
+// stopWS terminates the websocket RPC Endpoint.
func (n *Node) stopWS() {
- if n.wsHTTPServer != nil {
- // Don't bother imposing a timeout here.
- n.wsHTTPServer.Shutdown(context.Background())
- n.log.Info("WebSocket endpoint closed", "url", fmt.Sprintf("ws://%v", n.wsListenerAddr))
+ if n.wsHandler.Listener != nil {
+ n.wsHandler.Listener.Close()
+ n.wsHandler.Listener = nil
+
+ n.log.Info("WebSocket Endpoint closed", "url", fmt.Sprintf("ws://%s", n.wsHandler.Endpoint))
}
- if n.wsHandler != nil {
- n.wsHandler.Stop()
- n.wsHandler = nil
+ if n.wsHandler.Srv != nil {
+ n.wsHandler.Srv.Stop()
+ n.wsHandler.Srv = nil
}
}
@@ -638,6 +645,24 @@ func (n *Node) Service(service interface{}) error {
return ErrServiceUnknown
}
+// Service retrieves a currently running service registered of a specific type.
+func (n *Node) AuxService(auxService interface{}) error {
+ n.lock.RLock()
+ defer n.lock.RUnlock()
+
+ // Short circuit if the node's not running
+ if n.server == nil {
+ return ErrNodeStopped
+ }
+ // Otherwise try to find the service to return
+ element := reflect.ValueOf(auxService).Elem()
+ if running, ok := n.auxServices[element.Type()]; ok {
+ element.Set(reflect.ValueOf(running))
+ return nil
+ }
+ return ErrServiceUnknown
+}
+
// DataDir retrieves the current datadir used by the protocol stack.
// Deprecated: No files should be stored in this directory, use InstanceDir instead.
func (n *Node) DataDir() string {
@@ -654,31 +679,31 @@ func (n *Node) AccountManager() *accounts.Manager {
return n.accman
}
-// IPCEndpoint retrieves the current IPC endpoint used by the protocol stack.
+// IPCEndpoint retrieves the current IPC Endpoint used by the protocol stack.
func (n *Node) IPCEndpoint() string {
- return n.ipcEndpoint
+ return n.ipcHandler.Endpoint()
}
-// HTTPEndpoint retrieves the current HTTP endpoint used by the protocol stack.
+// HTTPEndpoint retrieves the current HTTP Endpoint used by the protocol stack.
func (n *Node) HTTPEndpoint() string {
n.lock.Lock()
defer n.lock.Unlock()
- if n.httpListenerAddr != nil {
- return n.httpListenerAddr.String()
+ if n.httpHandler.Listener != nil {
+ return n.httpHandler.Listener.Addr().String()
}
- return n.httpEndpoint
+ return n.httpHandler.Endpoint()
}
-// WSEndpoint retrieves the current WS endpoint used by the protocol stack.
+// WSEndpoint retrieves the current WS Endpoint used by the protocol stack.
func (n *Node) WSEndpoint() string {
n.lock.Lock()
defer n.lock.Unlock()
- if n.wsListenerAddr != nil {
- return n.wsListenerAddr.String()
+ if n.wsHandler.Listener != nil {
+ return n.wsHandler.Listener.Addr().String()
}
- return n.wsEndpoint
+ return n.wsHandler.Endpoint()
}
// EventMux retrieves the event multiplexer used by all the network services in
diff --git a/node/node_test.go b/node/node_test.go
index d62194a87681..501d3a8a5d1e 100644
--- a/node/node_test.go
+++ b/node/node_test.go
@@ -651,7 +651,7 @@ func doHTTPRequest(t *testing.T, req *http.Request) *http.Response {
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
- t.Error("could not issue a GET request to the given endpoint", err)
+ t.Error("could not issue a GET request to the given Endpoint", err)
}
return resp
}
diff --git a/node/rpcstack.go b/node/rpcstack.go
index 86c7b6fd683e..3cf8a9c46c08 100644
--- a/node/rpcstack.go
+++ b/node/rpcstack.go
@@ -18,6 +18,7 @@ package node
import (
"compress/gzip"
+ "fmt"
"github.com/ethereum/go-ethereum/rpc"
"io"
"io/ioutil"
@@ -35,7 +36,9 @@ type HttpServer struct {
Srv *rpc.Server
Listener net.Listener
- endpoint endpoint
+ endpoint string
+ host string
+ port int
Whitelist []string
@@ -48,10 +51,20 @@ type HttpServer struct {
WSAllowed bool
}
-type endpoint struct {
- endpoint string
- host string
- port int
+func (h *HttpServer) Handler() http.Handler {
+ return h.handler
+}
+
+func (h *HttpServer) SetHandler(handler http.Handler) {
+ h.handler = handler
+}
+
+func (h *HttpServer) Endpoint() string {
+ return fmt.Sprintf("%s:%d", h.host, h.port)
+}
+
+func (h *HttpServer) SetEndpoint(endpoint string) {
+ h.endpoint = endpoint
}
// NewHTTPHandlerStack returns wrapped http-related handlers
diff --git a/node/service.go b/node/service.go
index 94bb012c699e..57bbe0c729a8 100644
--- a/node/service.go
+++ b/node/service.go
@@ -32,7 +32,9 @@ import (
// the protocol stack, that is passed to all constructors to be optionally used;
// as well as utility methods to operate on the service environment.
type ServiceContext struct {
- services map[reflect.Type]Service // Index of the already constructed services
+ backend Backend // Copy of the already constructed Backend // TODO update this comment
+ services map[reflect.Type]Service // Index of the already constructed services
+ auxServices map[reflect.Type]AuxiliaryService // Index of the already constructed auxiliary services
Config Config
EventMux *event.TypeMux // Event multiplexer used for decoupled notifications
AccountManager *accounts.Manager // Account manager created by the node.
@@ -130,7 +132,7 @@ type Service interface {
// TODO document
type AuxiliaryService interface {
// TODO document
- Server() (*HttpServer, error)
+ Server() *HttpServer
// AuxiliaryService also implements Lifecycle
Lifecycle
From a607196fa891f105906e80b729e7e177d23d5f12 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Thu, 23 Apr 2020 17:45:22 +0200
Subject: [PATCH 006/160] fixed some registration for services
---
cmd/utils/flags.go | 28 +++++++++-------------------
ethstats/ethstats.go | 2 +-
node/node.go | 4 ++++
whisper/whisperv6/whisper.go | 2 +-
4 files changed, 15 insertions(+), 21 deletions(-)
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index e256f7747c81..cd6d54ff05bb 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -1695,8 +1695,8 @@ func setDNSDiscoveryDefaults(cfg *eth.Config, genesis common.Hash) {
func RegisterEthService(stack *node.Node, cfg *eth.Config) {
var err error
if cfg.SyncMode == downloader.LightSync {
- err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
- return les.New(ctx, cfg)
+ err = stack.RegisterBackendLifecycle(func(stack *node.Node) (node.Backend, error) {
+ return les.New(stack.ServiceContext, cfg)
})
} else {
err = stack.RegisterBackendLifecycle(func(node *node.Node) (node.Backend, error) {
@@ -1715,7 +1715,7 @@ func RegisterEthService(stack *node.Node, cfg *eth.Config) {
// RegisterShhService configures Whisper and adds it to the given node.
func RegisterShhService(stack *node.Node, cfg *whisper.Config) {
- if err := stack.Register(func(n *node.ServiceContext) (node.Service, error) {
+ if err := stack.RegisterServiceLifecycle(func(stack *node.Node) (node.Service, error) {
return whisper.New(cfg), nil
}); err != nil {
Fatalf("Failed to register the Whisper service: %v", err)
@@ -1725,16 +1725,8 @@ func RegisterShhService(stack *node.Node, cfg *whisper.Config) {
// RegisterEthStatsService configures the Ethereum Stats daemon and adds it to
// the given node.
func RegisterEthStatsService(stack *node.Node, url string) {
- if err := stack.Register(func(stack *node.Node) (node.AuxiliaryService, error) {
- // Retrieve both eth and les services
- var ethServ *eth.Ethereum
- ctx.Service(ðServ)
-
- var lesServ *les.LightEthereum
- ctx.Service(&lesServ)
-
- // Let ethstats use whichever is not nil
- return ethstats.New(url, ethServ, lesServ)
+ if err := stack.RegisterAuxServiceLifecycle(func(stack *node.Node) (node.AuxiliaryService, error) {
+ return ethstats.New(stack, url, stack.Backend())
}); err != nil {
Fatalf("Failed to register the Ethereum Stats service: %v", err)
}
@@ -1744,14 +1736,12 @@ func RegisterEthStatsService(stack *node.Node, url string) {
func RegisterGraphQLService(stack *node.Node, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) {
if err := stack.RegisterAuxServiceLifecycle(func(stack *node.Node) (node.AuxiliaryService, error) {
// Try to construct the GraphQL service backed by a full node
- var ethServ *eth.Ethereum
- if err := ctx.Service(ðServ); err == nil {
- return graphql.New(ethServ.APIBackend, endpoint, cors, vhosts, timeouts)
+ if ethBackend, ok := stack.Backend().(*eth.Ethereum); ok {
+ return graphql.New(ethBackend.APIBackend, endpoint, cors, vhosts, timeouts)
}
// Try to construct the GraphQL service backed by a light node
- var lesServ *les.LightEthereum
- if err := ctx.Service(&lesServ); err == nil {
- return graphql.New(lesServ.ApiBackend, endpoint, cors, vhosts, timeouts)
+ if lesBackend, ok := stack.Backend().(*les.LightEthereum); ok {
+ return graphql.New(lesBackend.ApiBackend, endpoint, cors, vhosts, timeouts)
}
// Well, this should not have happened, bail out
return nil, errors.New("no Ethereum service")
diff --git a/ethstats/ethstats.go b/ethstats/ethstats.go
index 17857d5492dc..81283370c8ce 100644
--- a/ethstats/ethstats.go
+++ b/ethstats/ethstats.go
@@ -117,7 +117,7 @@ func New(node *node.Node, url string, backend node.Backend) (node.AuxiliaryServi
histCh: make(chan []uint64, 1),
}, nil
}
- return nil, errors.New("ethstats backend is of unidentified type") // TODO is this okay to return?
+ return nil, errors.New("no Ethereum service") // TODO is this okay to return?
}
// Start implements node.Service, starting up the monitoring and reporting daemon.
diff --git a/node/node.go b/node/node.go
index e65b0dc63b56..6701dc34105b 100644
--- a/node/node.go
+++ b/node/node.go
@@ -617,6 +617,10 @@ func (n *Node) RPCHandler() (*rpc.Server, error) {
return n.inprocHandler, nil
}
+func (n *Node) Backend() Backend {
+ return n.backend
+}
+
// Server retrieves the currently running P2P network layer. This method is meant
// only to inspect fields of the currently running server, life cycle management
// should be left to this Node entity.
diff --git a/whisper/whisperv6/whisper.go b/whisper/whisperv6/whisper.go
index 8fe648a7a7f6..053c22b3cb7d 100644
--- a/whisper/whisperv6/whisper.go
+++ b/whisper/whisperv6/whisper.go
@@ -636,7 +636,7 @@ func (whisper *Whisper) Send(envelope *Envelope) error {
// Start implements node.Service, starting the background data propagation thread
// of the Whisper protocol.
-func (whisper *Whisper) Start(*p2p.Server) error {
+func (whisper *Whisper) Start() error {
log.Info("started whisper v." + ProtocolVersionStr)
whisper.wg.Add(1)
go whisper.update()
From c842bf8f4d9901a5eba15734d6ef9f55abd3c465 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Mon, 27 Apr 2020 16:16:41 +0200
Subject: [PATCH 007/160] semi-functional impl
---
cmd/geth/main.go | 1 +
cmd/utils/flags.go | 2 +-
eth/backend.go | 14 +++++++++++---
les/client.go | 10 ++++++++++
node/node.go | 42 ++++++++++++++++++++++++++++--------------
node/service.go | 3 +++
6 files changed, 54 insertions(+), 18 deletions(-)
diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index 62aa44e26476..df9de41f00af 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -354,6 +354,7 @@ func geth(ctx *cli.Context) error {
node := makeFullNode(ctx)
defer node.Close()
startNode(ctx, node)
+
node.Wait()
return nil
}
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index cd6d54ff05bb..4cbaed5f0324 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -1700,7 +1700,7 @@ func RegisterEthService(stack *node.Node, cfg *eth.Config) {
})
} else {
err = stack.RegisterBackendLifecycle(func(node *node.Node) (node.Backend, error) {
- fullNode, err := eth.New(node.ServiceContext, cfg, node.Server())
+ fullNode, err := eth.New(node.ServiceContext, cfg)
if fullNode != nil && cfg.LightServ > 0 {
ls, _ := les.NewLesServer(fullNode, cfg)
fullNode.AddLesServer(ls)
diff --git a/eth/backend.go b/eth/backend.go
index 7d46485ee220..a7ef070caa9a 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -116,7 +116,7 @@ func (s *Ethereum) SetContractBackend(backend bind.ContractBackend) {
// New creates a new Ethereum object (including the
// initialisation of the common Ethereum object)
-func New(ctx *node.ServiceContext, config *Config, p2pServer *p2p.Server) (*Ethereum, error) {
+func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
// Ensure configuration values are compatible and sane
if config.SyncMode == downloader.LightSync {
return nil, errors.New("can't run eth.Ethereum in light sync mode, use les.LightEthereum")
@@ -162,7 +162,6 @@ func New(ctx *node.ServiceContext, config *Config, p2pServer *p2p.Server) (*Ethe
etherbase: config.Miner.Etherbase,
bloomRequests: make(chan chan *bloombits.Retrieval),
bloomIndexer: NewBloomIndexer(chainDb, params.BloomBitsBlocks, params.BloomConfirms),
- p2pServer: p2pServer,
}
bcVersion := rawdb.ReadDatabaseVersion(chainDb)
@@ -523,7 +522,7 @@ func (s *Ethereum) Downloader() *downloader.Downloader { return s.protocolManage
func (s *Ethereum) Synced() bool { return atomic.LoadUint32(&s.protocolManager.acceptTxs) == 1 }
func (s *Ethereum) ArchiveMode() bool { return s.config.NoPruning }
-// Protocols implements node.Service, returning all the currently configured
+// Protocols implements node.Backend, returning all the currently configured
// network protocols to start.
func (s *Ethereum) Protocols() []p2p.Protocol {
protos := make([]p2p.Protocol, len(ProtocolVersions))
@@ -538,6 +537,15 @@ func (s *Ethereum) Protocols() []p2p.Protocol {
return protos
}
+// P2PServer implements node.Backend, registering the node's running p2p server with the Backend.
+func (s *Ethereum) P2PServer(server *p2p.Server) error {
+ if server == nil {
+ return errors.New("p2p server is not running, cannot register with eth backend") // TODO is this error message okay?
+ }
+ s.p2pServer = server
+ return nil
+}
+
// Start implements node.Service, starting all internal goroutines needed by the
// Ethereum protocol implementation.
func (s *Ethereum) Start() error {
diff --git a/les/client.go b/les/client.go
index 430e37d56c82..ae81c79db430 100644
--- a/les/client.go
+++ b/les/client.go
@@ -18,6 +18,7 @@
package les
import (
+ "errors"
"fmt"
"time"
@@ -278,6 +279,15 @@ func (s *LightEthereum) Protocols() []p2p.Protocol {
}, s.dialCandidates)
}
+// P2PServer implements node.Backend, registering the node's running p2p server with the Backend.
+func (s *LightEthereum) P2PServer(server *p2p.Server) error {
+ if server == nil {
+ return errors.New("p2p server is not running, cannot register with les backend") // TODO is this error message okay?
+ }
+ s.p2pServer = server
+ return nil
+}
+
// Start implements node.Service, starting all internal goroutines needed by the
// light ethereum protocol implementation.
func (s *LightEthereum) Start() error {
diff --git a/node/node.go b/node/node.go
index 6701dc34105b..7f6b71afeb39 100644
--- a/node/node.go
+++ b/node/node.go
@@ -104,7 +104,7 @@ func New(conf *Config) (*Node, error) {
}
// Note: any interaction with Config that would create/touch files
// in the data directory or instance directory is delayed until Start.
- return &Node{
+ node := &Node{
accman: am,
ephemeralKeystore: ephemeralKeystore,
config: conf,
@@ -124,7 +124,10 @@ func New(conf *Config) (*Node, error) {
},
eventmux: new(event.TypeMux),
log: conf.Logger,
- }, nil
+ }
+ node.ServiceContext.EventMux = node.eventmux
+ node.ServiceContext.AccountManager = node.accman
+ return node, nil
}
// Close stops the Node and releases resources acquired in
@@ -232,32 +235,40 @@ func (n *Node) Start() error {
// Initialize the p2p server. This creates the node key and
// discovery databases.
- n.server.Config = n.config.P2P
- n.server.PrivateKey = n.config.NodeKey()
- n.server.Name = n.config.NodeName()
- n.server.Logger = n.log
- if n.server.StaticNodes == nil {
- n.server.StaticNodes = n.config.StaticNodes()
+ running := &p2p.Server{Config: n.config.P2P}
+
+ running.Config.PrivateKey = n.config.NodeKey()
+ running.Config.Name = n.config.NodeName()
+ running.Config.Logger = n.log
+ if running.Config.StaticNodes == nil {
+ running.Config.StaticNodes = n.config.StaticNodes()
}
- if n.server.TrustedNodes == nil {
- n.server.TrustedNodes = n.config.TrustedNodes()
+ if running.Config.TrustedNodes == nil {
+ running.Config.TrustedNodes = n.config.TrustedNodes()
}
- if n.server.NodeDatabase == "" {
- n.server.NodeDatabase = n.config.NodeDB()
+ if running.Config.NodeDatabase == "" {
+ running.Config.NodeDatabase = n.config.NodeDB()
}
- running := &p2p.Server{Config: n.server.Config}
- n.log.Info("Starting peer-to-peer node", "instance", n.server.Name)
+ n.log.Info("Starting peer-to-peer node", "instance", running.Name)
// add backend's protocols to the o2o server
running.Protocols = append(running.Protocols, n.backend.Protocols()...)
if err := running.Start(); err != nil {
return convertFileLockError(err)
}
+
+ // Register the running p2p server with the Backend
+ if err := n.backend.P2PServer(running); err != nil {
+ running.Stop()
+ return err
+ }
+
// Start the backend
if err := n.backend.Start(); err != nil {
running.Stop()
return err
}
+
// Start each of the services
var startedServices []reflect.Type
for kind, service := range n.services {
@@ -271,6 +282,7 @@ func (n *Node) Start() error {
// Mark the service started for potential cleanup
startedServices = append(startedServices, kind)
}
+
// Start each of the auxiliary services
var startedAuxServices []reflect.Type
for kind, auxService := range n.auxServices {
@@ -284,6 +296,7 @@ func (n *Node) Start() error {
// Mark the service started for potential cleanup
startedAuxServices = append(startedAuxServices, kind)
}
+
// Lastly, start the configured RPC interfaces
if err := n.startRPC(); err != nil {
n.stopAllStartedServices(startedServices, startedAuxServices)
@@ -300,6 +313,7 @@ func (n *Node) Start() error {
// Finish initializing the startup
n.server = running
n.stop = make(chan struct{})
+ log.Error("HERE")
return nil
}
diff --git a/node/service.go b/node/service.go
index 57bbe0c729a8..cd035c863b30 100644
--- a/node/service.go
+++ b/node/service.go
@@ -107,6 +107,9 @@ type Backend interface {
// Protocols retrieves the P2P protocols the service wishes to start.
Protocols() []p2p.Protocol
+ // Backend can register a P2P Server
+ P2PServer(server *p2p.Server) error
+
// Backend also implements the Service interface.
Service
}
From 8dbba6008fe95b9715f2b350ef3436126d192b8b Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Mon, 27 Apr 2020 16:47:50 +0200
Subject: [PATCH 008/160] fixed dev mode start-up, should be working fine now
---
cmd/geth/main.go | 10 +++++++---
node/node.go | 3 +--
2 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index df9de41f00af..bb39c512cf49 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -464,9 +464,13 @@ func startNode(ctx *cli.Context, stack *node.Node) {
if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" {
utils.Fatalf("Light clients do not support mining")
}
- var ethereum *eth.Ethereum
- if err := stack.Service(ðereum); err != nil {
- utils.Fatalf("Ethereum service not running: %v", err)
+ // Check if node's backend is eth and that it exists // TODO fix this section up -- not sure if it's doing what it's supposed to.
+ ethereum, ok := stack.Backend().(*eth.Ethereum)
+ if !ok {
+ if stack.Backend() == nil {
+ utils.Fatalf("Ethereum service not running: backend is nil")
+ }
+ utils.Fatalf("Ethereum service not running: backend is not an eth backend")
}
// Set the gas price to the limits from the CLI and start mining
gasprice := utils.GlobalBig(ctx, utils.MinerGasPriceFlag.Name)
diff --git a/node/node.go b/node/node.go
index 7f6b71afeb39..3b1d88002a1b 100644
--- a/node/node.go
+++ b/node/node.go
@@ -296,7 +296,7 @@ func (n *Node) Start() error {
// Mark the service started for potential cleanup
startedAuxServices = append(startedAuxServices, kind)
}
-
+
// Lastly, start the configured RPC interfaces
if err := n.startRPC(); err != nil {
n.stopAllStartedServices(startedServices, startedAuxServices)
@@ -313,7 +313,6 @@ func (n *Node) Start() error {
// Finish initializing the startup
n.server = running
n.stop = make(chan struct{})
- log.Error("HERE")
return nil
}
From 2b67abf426ed51ac9e7994e3c50edac793c85d9b Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Tue, 28 Apr 2020 13:36:07 +0200
Subject: [PATCH 009/160] registerrpc and regiterprotocols
---
node/api.go | 4 +-
node/node.go | 102 +++++++++++++++++++++++++++++----------------------
2 files changed, 60 insertions(+), 46 deletions(-)
diff --git a/node/api.go b/node/api.go
index df2b2cd69405..4b2a0f99718c 100644
--- a/node/api.go
+++ b/node/api.go
@@ -186,7 +186,7 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
}
}
- if err := api.node.startHTTP(fmt.Sprintf("%s:%d", *host, *port), api.node.rpcAPIs, modules, allowedOrigins, allowedVHosts, api.node.config.HTTPTimeouts, api.node.config.WSOrigins); err != nil {
+ if err := api.node.startHTTP(fmt.Sprintf("%s:%d", *host, *port), modules, allowedOrigins, allowedVHosts, api.node.config.HTTPTimeouts, api.node.config.WSOrigins); err != nil {
return false, err
}
return true, nil
@@ -240,7 +240,7 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
}
}
- if err := api.node.startWS(fmt.Sprintf("%s:%d", *host, *port), api.node.rpcAPIs, modules, origins, api.node.config.WSExposeAll); err != nil {
+ if err := api.node.startWS(fmt.Sprintf("%s:%d", *host, *port), modules, origins, api.node.config.WSExposeAll); err != nil {
return false, err
}
return true, nil
diff --git a/node/node.go b/node/node.go
index 3b1d88002a1b..f813189b01f5 100644
--- a/node/node.go
+++ b/node/node.go
@@ -215,6 +215,24 @@ func (n *Node) RegisterAuxServiceLifecycle(constructor AuxiliaryServiceConstruct
return nil
}
+func (n *Node) RegisterProtocols(protocols []p2p.Protocol) error {
+ if !n.running() {
+ return ErrNodeStopped
+ }
+ // add backend's protocols to the o2o server
+ n.server.Protocols = append(n.server.Protocols, protocols...)
+ return nil
+}
+
+func (n *Node) RegisterRPC(apis []rpc.API) {
+ // Gather all the possible APIs to surface
+ apis = append(apis, n.backend.APIs()...)
+ for _, service := range n.services {
+ apis = append(apis, service.APIs()...)
+ }
+ n.rpcAPIs = apis
+}
+
// running returns true if the node's p2p server is already running
func (n *Node) running() bool {
return n.server != nil
@@ -226,7 +244,7 @@ func (n *Node) Start() error {
defer n.lock.Unlock()
// Short circuit if the node's already running
- if n.server != nil {
+ if n.running() {
return ErrNodeRunning
}
if err := n.openDataDir(); err != nil {
@@ -235,37 +253,39 @@ func (n *Node) Start() error {
// Initialize the p2p server. This creates the node key and
// discovery databases.
- running := &p2p.Server{Config: n.config.P2P}
-
- running.Config.PrivateKey = n.config.NodeKey()
- running.Config.Name = n.config.NodeName()
- running.Config.Logger = n.log
- if running.Config.StaticNodes == nil {
- running.Config.StaticNodes = n.config.StaticNodes()
+ n.server = &p2p.Server{Config: n.config.P2P}
+ n.server.Config.PrivateKey = n.config.NodeKey()
+ n.server.Config.Name = n.config.NodeName()
+ n.server.Config.Logger = n.log
+ if n.server.Config.StaticNodes == nil {
+ n.server.Config.StaticNodes = n.config.StaticNodes()
}
- if running.Config.TrustedNodes == nil {
- running.Config.TrustedNodes = n.config.TrustedNodes()
+ if n.server.Config.TrustedNodes == nil {
+ n.server.Config.TrustedNodes = n.config.TrustedNodes()
}
- if running.Config.NodeDatabase == "" {
- running.Config.NodeDatabase = n.config.NodeDB()
+ if n.server.Config.NodeDatabase == "" {
+ n.server.Config.NodeDatabase = n.config.NodeDB()
}
- n.log.Info("Starting peer-to-peer node", "instance", running.Name)
- // add backend's protocols to the o2o server
- running.Protocols = append(running.Protocols, n.backend.Protocols()...)
- if err := running.Start(); err != nil {
+ // Start the p2p node
+ if err := n.server.Start(); err != nil {
return convertFileLockError(err)
}
+ n.log.Info("Starting peer-to-peer node", "instance", n.server.Name)
// Register the running p2p server with the Backend
- if err := n.backend.P2PServer(running); err != nil {
- running.Stop()
+ if err := n.backend.P2PServer(n.server); err != nil {
+ n.server.Stop()
+ return err
+ }
+ // Register the Backend's protocols with the p2p server
+ if err := n.RegisterProtocols(n.backend.Protocols()); err != nil {
+ n.server.Stop()
return err
}
-
// Start the backend
if err := n.backend.Start(); err != nil {
- running.Stop()
+ n.server.Stop()
return err
}
@@ -275,7 +295,7 @@ func (n *Node) Start() error {
// Start the next service, stopping all previous upon failure
if err := service.Start(); err != nil {
n.stopAllStartedServices(startedServices, nil) // TODO safe to pass nil here?
- running.Stop()
+ n.server.Stop()
return err
}
@@ -289,7 +309,7 @@ func (n *Node) Start() error {
// Start the next auxiliary service, stopping all previous upon failure
if err := auxService.Start(); err != nil {
n.stopAllStartedServices(startedServices, startedAuxServices)
- running.Stop()
+ n.server.Stop()
return err
}
@@ -300,7 +320,7 @@ func (n *Node) Start() error {
// Lastly, start the configured RPC interfaces
if err := n.startRPC(); err != nil {
n.stopAllStartedServices(startedServices, startedAuxServices)
- running.Stop()
+ n.server.Stop()
return err
}
// Finish initializing the service context
@@ -311,7 +331,6 @@ func (n *Node) Start() error {
n.ServiceContext.auxServices = n.auxServices
// Finish initializing the startup
- n.server = running
n.stop = make(chan struct{})
return nil
}
@@ -354,28 +373,24 @@ func (n *Node) openDataDir() error {
// startup. It's not meant to be called at any time afterwards as it makes certain
// assumptions about the state of the node.
func (n *Node) startRPC() error {
- // Gather all the possible APIs to surface
- apis := n.apis()
- apis = append(apis, n.backend.APIs()...)
- for _, service := range n.services {
- apis = append(apis, service.APIs()...)
- }
+ n.RegisterRPC(n.apis())
+
// Start the various API endpoints, terminating all in case of errors
- if err := n.startInProc(apis); err != nil {
+ if err := n.startInProc(); err != nil {
return err
}
- if err := n.startIPC(apis); err != nil {
+ if err := n.startIPC(); err != nil {
n.stopInProc()
return err
}
- if err := n.startHTTP(n.httpHandler.Endpoint(), apis, n.config.HTTPModules, n.config.HTTPCors, n.config.HTTPVirtualHosts, n.config.HTTPTimeouts, n.config.WSOrigins); err != nil {
+ if err := n.startHTTP(n.httpHandler.Endpoint(), n.config.HTTPModules, n.config.HTTPCors, n.config.HTTPVirtualHosts, n.config.HTTPTimeouts, n.config.WSOrigins); err != nil {
n.stopIPC()
n.stopInProc()
return err
}
// if endpoints are not the same, start separate servers
if n.httpHandler.Endpoint() != n.wsHandler.Endpoint() {
- if err := n.startWS(n.wsHandler.Endpoint(), apis, n.config.WSModules, n.config.WSOrigins, n.config.WSExposeAll); err != nil {
+ if err := n.startWS(n.wsHandler.Endpoint(), n.config.WSModules, n.config.WSOrigins, n.config.WSExposeAll); err != nil {
n.stopHTTP()
n.stopIPC()
n.stopInProc()
@@ -384,15 +399,14 @@ func (n *Node) startRPC() error {
}
// All API endpoints started successfully
- n.rpcAPIs = apis
return nil
}
// startInProc initializes an in-process RPC Endpoint.
-func (n *Node) startInProc(apis []rpc.API) error {
+func (n *Node) startInProc() error {
// Register all the APIs exposed by the services
handler := rpc.NewServer()
- for _, api := range apis {
+ for _, api := range n.rpcAPIs {
if err := handler.RegisterName(api.Namespace, api.Service); err != nil {
return err
}
@@ -411,11 +425,11 @@ func (n *Node) stopInProc() {
}
// startIPC initializes and starts the IPC RPC Endpoint.
-func (n *Node) startIPC(apis []rpc.API) error {
+func (n *Node) startIPC() error {
if n.ipcHandler.Endpoint() == "" {
return nil // IPC disabled.
}
- listener, handler, err := rpc.StartIPCEndpoint(n.ipcHandler.Endpoint(), apis)
+ listener, handler, err := rpc.StartIPCEndpoint(n.ipcHandler.Endpoint(), n.rpcAPIs)
if err != nil {
return err
}
@@ -440,14 +454,14 @@ func (n *Node) stopIPC() {
}
// startHTTP initializes and starts the HTTP RPC Endpoint.
-func (n *Node) startHTTP(endpoint string, apis []rpc.API, modules []string, cors []string, vhosts []string, timeouts rpc.HTTPTimeouts, wsOrigins []string) error {
+func (n *Node) startHTTP(endpoint string, modules []string, cors []string, vhosts []string, timeouts rpc.HTTPTimeouts, wsOrigins []string) error {
// Short circuit if the HTTP Endpoint isn't being exposed
if endpoint == "" {
return nil
}
// register apis and create handler stack
srv := rpc.NewServer()
- err := RegisterApisFromWhitelist(apis, modules, srv, false)
+ err := RegisterApisFromWhitelist(n.rpcAPIs, modules, srv, false)
if err != nil {
return err
}
@@ -489,7 +503,7 @@ func (n *Node) stopHTTP() {
}
// startWS initializes and starts the websocket RPC Endpoint.
-func (n *Node) startWS(endpoint string, apis []rpc.API, modules []string, wsOrigins []string, exposeAll bool) error {
+func (n *Node) startWS(endpoint string, modules []string, wsOrigins []string, exposeAll bool) error {
// Short circuit if the WS Endpoint isn't being exposed
if endpoint == "" {
return nil
@@ -497,7 +511,7 @@ func (n *Node) startWS(endpoint string, apis []rpc.API, modules []string, wsOrig
srv := rpc.NewServer()
handler := srv.WebsocketHandler(wsOrigins)
- err := RegisterApisFromWhitelist(apis, modules, srv, exposeAll)
+ err := RegisterApisFromWhitelist(n.rpcAPIs, modules, srv, exposeAll)
if err != nil {
return err
}
@@ -524,7 +538,7 @@ func (n *Node) stopWS() {
}
if n.wsHandler.Srv != nil {
n.wsHandler.Srv.Stop()
- n.wsHandler.Srv = nil
+ n.wsHandler.Srv = nil
}
}
From bf8a05b234615c55b32eaec11948e81b106c433e Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Tue, 28 Apr 2020 14:30:24 +0200
Subject: [PATCH 010/160] fixed RegisterLifecycle to be generic
---
cmd/faucet/faucet.go | 28 +++++++++------
cmd/utils/flags.go | 83 ++++++++++++++++++++++++++------------------
node/node.go | 83 ++++++++++++++------------------------------
node/service.go | 2 +-
4 files changed, 94 insertions(+), 102 deletions(-)
diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go
index a6daaa5dbd38..db2505b51cd3 100644
--- a/cmd/faucet/faucet.go
+++ b/cmd/faucet/faucet.go
@@ -235,24 +235,30 @@ func newFaucet(genesis *core.Genesis, port int, enodes []*discv5.Node, network u
if err != nil {
return nil, err
}
+
// Assemble the Ethereum light client protocol
- if err := stack.RegisterBackendLifecycle(func(stack *node.Node) (node.Backend, error) {
- cfg := eth.DefaultConfig
- cfg.SyncMode = downloader.LightSync
- cfg.NetworkId = network
- cfg.Genesis = genesis
- return les.New(stack.ServiceContext, &cfg)
- }); err != nil {
+ cfg := eth.DefaultConfig
+ cfg.SyncMode = downloader.LightSync
+ cfg.NetworkId = network
+ cfg.Genesis = genesis
+ lesBackend, err := les.New(stack.ServiceContext, &cfg)
+ // register the backend and lifecycle
+ if err := stack.RegisterBackend(lesBackend); err != nil {
return nil, err
}
+ stack.RegisterLifecycle(lesBackend)
+
// Assemble the ethstats monitoring and reporting service'
if stats != "" {
- if err := stack.RegisterAuxServiceLifecycle(func(stack *node.Node) (node.AuxiliaryService, error) {
- var serv *les.LightEthereum
- return ethstats.New(stack, stats, serv)
- }); err != nil {
+ var serv *les.LightEthereum
+ ethstatsAuxService, err := ethstats.New(stack, stats, serv)
+ if err != nil {
+ return nil, err
+ }
+ if err := stack.RegisterAuxService(ethstatsAuxService); err != nil {
return nil, err
}
+ stack.RegisterLifecycle(ethstatsAuxService)
}
// Boot up the client and ensure it connects to bootnodes
if err := stack.Start(); err != nil {
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index 4cbaed5f0324..f915566f9dc4 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -19,7 +19,6 @@ package utils
import (
"crypto/ecdsa"
- "errors"
"fmt"
"io"
"io/ioutil"
@@ -1693,61 +1692,79 @@ func setDNSDiscoveryDefaults(cfg *eth.Config, genesis common.Hash) {
// RegisterEthService adds an Ethereum client to the stack.
func RegisterEthService(stack *node.Node, cfg *eth.Config) {
- var err error
if cfg.SyncMode == downloader.LightSync {
- err = stack.RegisterBackendLifecycle(func(stack *node.Node) (node.Backend, error) {
- return les.New(stack.ServiceContext, cfg)
- })
+ lesBackend, err := les.New(stack.ServiceContext, cfg)
+ if err != nil {
+ Fatalf("Failed to register the Ethereum service: %v", err)
+ }
+ stack.RegisterLifecycle(lesBackend)
+ if err := stack.RegisterBackend(lesBackend); err != nil {
+ Fatalf("Failed to register the Ethereum service: %v", err)
+ }
} else {
- err = stack.RegisterBackendLifecycle(func(node *node.Node) (node.Backend, error) {
- fullNode, err := eth.New(node.ServiceContext, cfg)
- if fullNode != nil && cfg.LightServ > 0 {
- ls, _ := les.NewLesServer(fullNode, cfg)
- fullNode.AddLesServer(ls)
- }
- return fullNode, err
- })
- }
- if err != nil {
- Fatalf("Failed to register the Ethereum service: %v", err)
+ fullNode, err := eth.New(stack.ServiceContext, cfg)
+ if err != nil {
+ Fatalf("Failed to register the Ethereum service: %v", err)
+ }
+ if fullNode != nil && cfg.LightServ > 0 {
+ ls, _ := les.NewLesServer(fullNode, cfg)
+ fullNode.AddLesServer(ls)
+ }
+ if err := stack.RegisterBackend(fullNode); err != nil {
+ Fatalf("Failed to register the Ethereum service: %v", err)
+ }
+ stack.RegisterLifecycle(fullNode)
}
}
// RegisterShhService configures Whisper and adds it to the given node.
func RegisterShhService(stack *node.Node, cfg *whisper.Config) {
- if err := stack.RegisterServiceLifecycle(func(stack *node.Node) (node.Service, error) {
- return whisper.New(cfg), nil
- }); err != nil {
+ whisperService := whisper.New(cfg)
+ if err := stack.RegisterService(whisperService); err != nil {
Fatalf("Failed to register the Whisper service: %v", err)
}
+ stack.RegisterLifecycle(whisperService)
}
// RegisterEthStatsService configures the Ethereum Stats daemon and adds it to
// the given node.
func RegisterEthStatsService(stack *node.Node, url string) {
- if err := stack.RegisterAuxServiceLifecycle(func(stack *node.Node) (node.AuxiliaryService, error) {
- return ethstats.New(stack, url, stack.Backend())
- }); err != nil {
+ ethstatsAuxService, err := ethstats.New(stack, url, stack.Backend())
+ if err != nil {
Fatalf("Failed to register the Ethereum Stats service: %v", err)
}
+ if err := stack.RegisterAuxService(ethstatsAuxService); err != nil {
+ Fatalf("Failed to register the Ethereum Stats service: %v", err)
+ }
+ stack.RegisterLifecycle(ethstatsAuxService)
}
// RegisterGraphQLService is a utility function to construct a new service and register it against a node.
func RegisterGraphQLService(stack *node.Node, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) {
- if err := stack.RegisterAuxServiceLifecycle(func(stack *node.Node) (node.AuxiliaryService, error) {
- // Try to construct the GraphQL service backed by a full node
- if ethBackend, ok := stack.Backend().(*eth.Ethereum); ok {
- return graphql.New(ethBackend.APIBackend, endpoint, cors, vhosts, timeouts)
+ // Try to construct the GraphQL service backed by a full node
+ if ethBackend, ok := stack.Backend().(*eth.Ethereum); ok {
+ graphqlAuxService, err := graphql.New(ethBackend.APIBackend, endpoint, cors, vhosts, timeouts)
+ if err != nil {
+ Fatalf("Failed to register the GraphQL service: %v", err)
+ }
+ if err := stack.RegisterAuxService(graphqlAuxService); err != nil {
+ Fatalf("Failed to register the GraphQL service: %v", err)
+ }
+ stack.RegisterLifecycle(graphqlAuxService)
+ }
+ // Try to construct the GraphQL service backed by a light node
+ if lesBackend, ok := stack.Backend().(*les.LightEthereum); ok {
+ graphqlAuxService, err := graphql.New(lesBackend.ApiBackend, endpoint, cors, vhosts, timeouts)
+ if err != nil {
+ Fatalf("Failed to register the GraphQL service: %v", err)
}
- // Try to construct the GraphQL service backed by a light node
- if lesBackend, ok := stack.Backend().(*les.LightEthereum); ok {
- return graphql.New(lesBackend.ApiBackend, endpoint, cors, vhosts, timeouts)
+ if err := stack.RegisterAuxService(graphqlAuxService); err != nil {
+ Fatalf("Failed to register the GraphQL service: %v", err)
}
- // Well, this should not have happened, bail out
- return nil, errors.New("no Ethereum service")
- }); err != nil {
- Fatalf("Failed to register the GraphQL service: %v", err)
+ stack.RegisterLifecycle(graphqlAuxService)
}
+ // Well, this should not have happened, bail out
+ Fatalf("no Ethereum service")
}
func SetupMetrics(ctx *cli.Context) {
diff --git a/node/node.go b/node/node.go
index f813189b01f5..b4292775acdf 100644
--- a/node/node.go
+++ b/node/node.go
@@ -51,6 +51,8 @@ type Node struct {
ServiceContext *ServiceContext
+ lifecycles []Lifecycle // All registered backends, services, and auxiliary services that have a lifecycle
+
backend Backend // The registered Backend of the node
services map[reflect.Type]Service // Currently running services
auxServices map[reflect.Type]AuxiliaryService // Currently running auxiliary services
@@ -153,18 +155,21 @@ func (n *Node) Close() error {
}
}
+func (n *Node) RegisterLifecycle(lifecycle Lifecycle) {
+ n.lifecycles = append(n.lifecycles, lifecycle)
+}
+
// TODO document
-func (n *Node) RegisterBackendLifecycle(constructor BackendConstructor) error {
+func (n *Node) RegisterBackend(backend Backend) error {
n.lock.Lock()
defer n.lock.Unlock()
-
+ // check if p2p node is already running
if n.running() {
return ErrNodeRunning
}
-
- backend, err := constructor(n)
- if err != nil {
- return err
+ // check that there is not already a backend registered on the node
+ if n.backend != nil {
+ return errors.New("a backend has already been registered on the node") // TODO is this error okay?
}
n.backend = backend
return nil
@@ -172,7 +177,7 @@ func (n *Node) RegisterBackendLifecycle(constructor BackendConstructor) error {
// Register injects a new service into the node's stack. The service created by
// the passed constructor must be unique in its type with regard to sibling ones.
-func (n *Node) RegisterServiceLifecycle(constructor ServiceConstructor) error {
+func (n *Node) RegisterService(service Service) error {
n.lock.Lock()
defer n.lock.Unlock()
@@ -180,10 +185,6 @@ func (n *Node) RegisterServiceLifecycle(constructor ServiceConstructor) error {
return ErrNodeRunning
}
- service, err := constructor(n)
- if err != nil {
- return err
- }
kind := reflect.TypeOf(service)
if _, exists := n.services[kind]; exists {
return &DuplicateServiceError{Kind: kind}
@@ -194,23 +195,19 @@ func (n *Node) RegisterServiceLifecycle(constructor ServiceConstructor) error {
}
// TODO document
-func (n *Node) RegisterAuxServiceLifecycle(constructor AuxiliaryServiceConstructor) error {
+func (n *Node) RegisterAuxService(auxService AuxiliaryService) error {
n.lock.Lock()
defer n.lock.Unlock()
if n.running() {
return ErrNodeRunning
}
-
- service, err := constructor(n)
- if err != nil {
- return err
- }
- kind := reflect.TypeOf(service)
+ // make sure auxiliary service is not duplicated
+ kind := reflect.TypeOf(auxService)
if _, exists := n.auxServices[kind]; exists {
return &DuplicateServiceError{Kind: kind}
}
- n.auxServices[kind] = service
+ n.auxServices[kind] = auxService
return nil
}
@@ -283,43 +280,19 @@ func (n *Node) Start() error {
n.server.Stop()
return err
}
- // Start the backend
- if err := n.backend.Start(); err != nil {
- n.server.Stop()
- return err
- }
- // Start each of the services
- var startedServices []reflect.Type
- for kind, service := range n.services {
- // Start the next service, stopping all previous upon failure
- if err := service.Start(); err != nil {
- n.stopAllStartedServices(startedServices, nil) // TODO safe to pass nil here?
- n.server.Stop()
-
- return err
+ // Start all registered lifecycles
+ var started []Lifecycle
+ for _, lifecycle := range n.lifecycles {
+ if err := lifecycle.Start(); err != nil {
+ n.stopLifecycles(started)
}
- // Mark the service started for potential cleanup
- startedServices = append(startedServices, kind)
- }
-
- // Start each of the auxiliary services
- var startedAuxServices []reflect.Type
- for kind, auxService := range n.auxServices {
- // Start the next auxiliary service, stopping all previous upon failure
- if err := auxService.Start(); err != nil {
- n.stopAllStartedServices(startedServices, startedAuxServices)
- n.server.Stop()
-
- return err
- }
- // Mark the service started for potential cleanup
- startedAuxServices = append(startedAuxServices, kind)
+ started = append(started, lifecycle)
}
// Lastly, start the configured RPC interfaces
if err := n.startRPC(); err != nil {
- n.stopAllStartedServices(startedServices, startedAuxServices)
+ n.stopLifecycles(n.lifecycles)
n.server.Stop()
return err
}
@@ -335,13 +308,9 @@ func (n *Node) Start() error {
return nil
}
-func (n *Node) stopAllStartedServices(startedServices []reflect.Type, startedAuxServices []reflect.Type) {
- n.backend.Stop()
- for _, kind := range startedServices {
- n.services[kind].Stop()
- }
- for _, kind := range startedAuxServices {
- n.auxServices[kind].Stop()
+func (n *Node) stopLifecycles(started []Lifecycle) {
+ for _, lifecycle := range started {
+ lifecycle.Stop()
}
}
diff --git a/node/service.go b/node/service.go
index cd035c863b30..442d308afadc 100644
--- a/node/service.go
+++ b/node/service.go
@@ -141,7 +141,7 @@ type AuxiliaryService interface {
Lifecycle
}
-// TODO, this might be overkill
+// TODO document
type Lifecycle interface {
// Start is called after all services have been constructed and the networking
// layer was also initialized to spawn any goroutines required by the service.
From fc7bff86f5339a01ec9c07a0da9765c2fe1b738e Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Tue, 28 Apr 2020 14:40:23 +0200
Subject: [PATCH 011/160] reverted capitalization of endpoint -- accident
---
node/api.go | 4 ++--
node/config.go | 14 +++++++-------
node/config_test.go | 2 +-
node/doc.go | 6 +++---
node/endpoints.go | 4 ++--
node/node.go | 39 ++++++++++++++++++++-------------------
node/node_test.go | 2 +-
7 files changed, 36 insertions(+), 35 deletions(-)
diff --git a/node/api.go b/node/api.go
index 4b2a0f99718c..f29911c61818 100644
--- a/node/api.go
+++ b/node/api.go
@@ -192,7 +192,7 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
return true, nil
}
-// StopRPC terminates an already running HTTP RPC API Endpoint.
+// StopRPC terminates an already running HTTP RPC API endpoint.
func (api *PrivateAdminAPI) StopRPC() (bool, error) {
api.node.lock.Lock()
defer api.node.lock.Unlock()
@@ -246,7 +246,7 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
return true, nil
}
-// StopWS terminates an already running websocket RPC API Endpoint.
+// StopWS terminates an already running websocket RPC API endpoint.
func (api *PrivateAdminAPI) StopWS() (bool, error) {
api.node.lock.Lock()
defer api.node.lock.Unlock()
diff --git a/node/config.go b/node/config.go
index d0c25c125b55..61566b7bee9b 100644
--- a/node/config.go
+++ b/node/config.go
@@ -98,7 +98,7 @@ type Config struct {
// SmartCardDaemonPath is the path to the smartcard daemon's socket
SmartCardDaemonPath string `toml:",omitempty"`
- // IPCPath is the requested location to place the IPC Endpoint. If the path is
+ // IPCPath is the requested location to place the IPC endpoint. If the path is
// a simple file name, it is placed inside the data directory (or on the root
// pipe path on Windows), whereas if it's a resolvable path name (absolute or
// relative), then that specific path is enforced. An empty path disables IPC.
@@ -193,7 +193,7 @@ type Config struct {
oldGethResourceWarning bool
}
-// IPCEndpoint resolves an IPC Endpoint based on a configured value, taking into
+// IPCEndpoint resolves an IPC endpoint based on a configured value, taking into
// account the set data folders as well as the designated platform we're currently
// running on.
func (c *Config) IPCEndpoint() string {
@@ -238,7 +238,7 @@ func DefaultIPCEndpoint(clientIdentifier string) string {
return config.IPCEndpoint()
}
-// HTTPEndpoint resolves an HTTP Endpoint based on the configured host interface
+// HTTPEndpoint resolves an HTTP endpoint based on the configured host interface
// and port parameters.
func (c *Config) HTTPEndpoint() string {
if c.HTTPHost == "" {
@@ -247,7 +247,7 @@ func (c *Config) HTTPEndpoint() string {
return fmt.Sprintf("%s:%d", c.HTTPHost, c.HTTPPort)
}
-// GraphQLEndpoint resolves a GraphQL Endpoint based on the configured host interface
+// GraphQLEndpoint resolves a GraphQL endpoint based on the configured host interface
// and port parameters.
func (c *Config) GraphQLEndpoint() string {
if c.GraphQLHost == "" {
@@ -256,13 +256,13 @@ func (c *Config) GraphQLEndpoint() string {
return fmt.Sprintf("%s:%d", c.GraphQLHost, c.GraphQLPort)
}
-// DefaultHTTPEndpoint returns the HTTP Endpoint used by default.
+// DefaultHTTPEndpoint returns the HTTP endpoint used by default.
func DefaultHTTPEndpoint() string {
config := &Config{HTTPHost: DefaultHTTPHost, HTTPPort: DefaultHTTPPort}
return config.HTTPEndpoint()
}
-// WSEndpoint resolves a websocket Endpoint based on the configured host interface
+// WSEndpoint resolves a websocket endpoint based on the configured host interface
// and port parameters.
func (c *Config) WSEndpoint() string {
if c.WSHost == "" {
@@ -271,7 +271,7 @@ func (c *Config) WSEndpoint() string {
return fmt.Sprintf("%s:%d", c.WSHost, c.WSPort)
}
-// DefaultWSEndpoint returns the websocket Endpoint used by default.
+// DefaultWSEndpoint returns the websocket endpoint used by default.
func DefaultWSEndpoint() string {
config := &Config{WSHost: DefaultWSHost, WSPort: DefaultWSPort}
return config.WSEndpoint()
diff --git a/node/config_test.go b/node/config_test.go
index 17c473f655d2..00c24a239123 100644
--- a/node/config_test.go
+++ b/node/config_test.go
@@ -99,7 +99,7 @@ func TestIPCPathResolution(t *testing.T) {
// Only run when platform/test match
if (runtime.GOOS == "windows") == test.Windows {
if endpoint := (&Config{DataDir: test.DataDir, IPCPath: test.IPCPath}).IPCEndpoint(); endpoint != test.Endpoint {
- t.Errorf("test %d: IPC Endpoint mismatch: have %s, want %s", i, endpoint, test.Endpoint)
+ t.Errorf("test %d: IPC endpoint mismatch: have %s, want %s", i, endpoint, test.Endpoint)
}
}
}
diff --git a/node/doc.go b/node/doc.go
index 3c6b696b3218..e3cc58e5f49c 100644
--- a/node/doc.go
+++ b/node/doc.go
@@ -36,7 +36,7 @@ about other hosts is persisted.
JSON-RPC servers which run HTTP, WebSocket or IPC can be started on a Node. RPC modules
offered by registered services will be offered on those endpoints. Users can restrict any
-Endpoint to a subset of RPC modules. Node itself offers the "debug", "admin" and "web3"
+endpoint to a subset of RPC modules. Node itself offers the "debug", "admin" and "web3"
modules.
Service implementations can open LevelDB databases through the service context. Package
@@ -77,14 +77,14 @@ directory. Node instance A opens the database "db", node instance B opens the da
nodekey -- devp2p node key of instance A
nodes/ -- devp2p discovery knowledge database of instance A
db/ -- LevelDB content for "db"
- A.ipc -- JSON-RPC UNIX domain socket Endpoint of instance A
+ A.ipc -- JSON-RPC UNIX domain socket endpoint of instance A
B/
nodekey -- devp2p node key of node B
nodes/ -- devp2p discovery knowledge database of instance B
static-nodes.json -- devp2p static node list of instance B
db/ -- LevelDB content for "db"
db-2/ -- LevelDB content for "db-2"
- B.ipc -- JSON-RPC UNIX domain socket Endpoint of instance B
+ B.ipc -- JSON-RPC UNIX domain socket endpoint of instance B
keystore/ -- account key store, used by both instances
*/
package node
diff --git a/node/endpoints.go b/node/endpoints.go
index 13479b88a191..5c9eddd88638 100644
--- a/node/endpoints.go
+++ b/node/endpoints.go
@@ -25,7 +25,7 @@ import (
"github.com/ethereum/go-ethereum/rpc"
)
-// StartHTTPEndpoint starts the HTTP RPC Endpoint.
+// StartHTTPEndpoint starts the HTTP RPC endpoint.
func StartHTTPEndpoint(endpoint string, timeouts rpc.HTTPTimeouts, handler http.Handler) (net.Listener, error) {
// start the HTTP listener
var (
@@ -48,7 +48,7 @@ func StartHTTPEndpoint(endpoint string, timeouts rpc.HTTPTimeouts, handler http.
return httpSrv, listener.Addr(), err
}
-// startWSEndpoint starts a websocket Endpoint.
+// startWSEndpoint starts a websocket endpoint.
func startWSEndpoint(endpoint string, handler http.Handler) (net.Listener, error) {
// start the HTTP listener
var (
diff --git a/node/node.go b/node/node.go
index b4292775acdf..f487266dd833 100644
--- a/node/node.go
+++ b/node/node.go
@@ -371,7 +371,7 @@ func (n *Node) startRPC() error {
return nil
}
-// startInProc initializes an in-process RPC Endpoint.
+// startInProc initializes an in-process RPC endpoint.
func (n *Node) startInProc() error {
// Register all the APIs exposed by the services
handler := rpc.NewServer()
@@ -385,7 +385,7 @@ func (n *Node) startInProc() error {
return nil
}
-// stopInProc terminates the in-process RPC Endpoint.
+// stopInProc terminates the in-process RPC endpoint.
func (n *Node) stopInProc() {
if n.inprocHandler != nil {
n.inprocHandler.Stop()
@@ -393,7 +393,7 @@ func (n *Node) stopInProc() {
}
}
-// startIPC initializes and starts the IPC RPC Endpoint.
+// startIPC initializes and starts the IPC RPC endpoint.
func (n *Node) startIPC() error {
if n.ipcHandler.Endpoint() == "" {
return nil // IPC disabled.
@@ -404,17 +404,17 @@ func (n *Node) startIPC() error {
}
n.ipcHandler.Listener = listener
n.ipcHandler.handler = handler
- n.log.Info("IPC Endpoint opened", "url", n.ipcHandler.Endpoint())
+ n.log.Info("IPC endpoint opened", "url", n.ipcHandler.Endpoint())
return nil
}
-// stopIPC terminates the IPC RPC Endpoint.
+// stopIPC terminates the IPC RPC endpoint.
func (n *Node) stopIPC() {
if n.ipcHandler.Listener != nil {
n.ipcHandler.Listener.Close()
n.ipcHandler.Listener = nil
- n.log.Info("IPC Endpoint closed", "url", n.ipcHandler.Endpoint())
+ n.log.Info("IPC endpoint closed", "url", n.ipcHandler.Endpoint())
}
if n.ipcHandler.Srv != nil {
n.ipcHandler.Srv.Stop()
@@ -422,9 +422,9 @@ func (n *Node) stopIPC() {
}
}
-// startHTTP initializes and starts the HTTP RPC Endpoint.
+// startHTTP initializes and starts the HTTP RPC endpoint.
func (n *Node) startHTTP(endpoint string, modules []string, cors []string, vhosts []string, timeouts rpc.HTTPTimeouts, wsOrigins []string) error {
- // Short circuit if the HTTP Endpoint isn't being exposed
+ // Short circuit if the HTTP endpoint isn't being exposed
if endpoint == "" {
return nil
}
@@ -443,11 +443,11 @@ func (n *Node) startHTTP(endpoint string, modules []string, cors []string, vhost
if err != nil {
return err
}
- n.log.Info("HTTP Endpoint opened", "url", fmt.Sprintf("http://%v/", listener.Addr()),
+ n.log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%v/", listener.Addr()),
"cors", strings.Join(cors, ","),
"vhosts", strings.Join(vhosts, ","))
if n.httpHandler.Endpoint() == n.wsHandler.Endpoint() {
- n.log.Info("WebSocket Endpoint opened", "url", fmt.Sprintf("ws://%v", listener.Addr()))
+ n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", listener.Addr()))
}
// All listeners booted successfully
n.httpHandler.endpoint = endpoint
@@ -457,7 +457,7 @@ func (n *Node) startHTTP(endpoint string, modules []string, cors []string, vhost
return nil
}
-// stopHTTP terminates the HTTP RPC Endpoint.
+// stopHTTP terminates the HTTP RPC endpoint.
func (n *Node) stopHTTP() {
if n.httpHandler.Listener != nil {
url := fmt.Sprintf("http://%v/", n.httpHandler.Listener.Addr())
@@ -471,9 +471,9 @@ func (n *Node) stopHTTP() {
}
}
-// startWS initializes and starts the websocket RPC Endpoint.
+// startWS initializes and starts the websocket RPC endpoint.
func (n *Node) startWS(endpoint string, modules []string, wsOrigins []string, exposeAll bool) error {
- // Short circuit if the WS Endpoint isn't being exposed
+ // Short circuit if the WS endpoint isn't being exposed
if endpoint == "" {
return nil
}
@@ -488,7 +488,7 @@ func (n *Node) startWS(endpoint string, modules []string, wsOrigins []string, ex
if err != nil {
return err
}
- n.log.Info("WebSocket Endpoint opened", "url", fmt.Sprintf("ws://%s", listener.Addr()))
+ n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%s", listener.Addr()))
// All listeners booted successfully
n.wsHandler.endpoint = endpoint
n.wsHandler.Listener = listener
@@ -497,13 +497,13 @@ func (n *Node) startWS(endpoint string, modules []string, wsOrigins []string, ex
return nil
}
-// stopWS terminates the websocket RPC Endpoint.
+// stopWS terminates the websocket RPC endpoint.
func (n *Node) stopWS() {
if n.wsHandler.Listener != nil {
n.wsHandler.Listener.Close()
n.wsHandler.Listener = nil
- n.log.Info("WebSocket Endpoint closed", "url", fmt.Sprintf("ws://%s", n.wsHandler.Endpoint))
+ n.log.Info("WebSocket endpoint closed", "url", fmt.Sprintf("ws://%s", n.wsHandler.Endpoint))
}
if n.wsHandler.Srv != nil {
n.wsHandler.Srv.Stop()
@@ -679,12 +679,12 @@ func (n *Node) AccountManager() *accounts.Manager {
return n.accman
}
-// IPCEndpoint retrieves the current IPC Endpoint used by the protocol stack.
+// IPCEndpoint retrieves the current IPC endpoint used by the protocol stack.
func (n *Node) IPCEndpoint() string {
return n.ipcHandler.Endpoint()
}
-// HTTPEndpoint retrieves the current HTTP Endpoint used by the protocol stack.
+// HTTPEndpoint retrieves the current HTTP endpoint used by the protocol stack.
func (n *Node) HTTPEndpoint() string {
n.lock.Lock()
defer n.lock.Unlock()
@@ -695,7 +695,8 @@ func (n *Node) HTTPEndpoint() string {
return n.httpHandler.Endpoint()
}
-// WSEndpoint retrieves the current WS Endpoint used by the protocol stack.
+// WSEndpoint retrieves the current WS endpoint
+// used by the protocol stack.
func (n *Node) WSEndpoint() string {
n.lock.Lock()
defer n.lock.Unlock()
diff --git a/node/node_test.go b/node/node_test.go
index 501d3a8a5d1e..d62194a87681 100644
--- a/node/node_test.go
+++ b/node/node_test.go
@@ -651,7 +651,7 @@ func doHTTPRequest(t *testing.T, req *http.Request) *http.Response {
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
- t.Error("could not issue a GET request to the given Endpoint", err)
+ t.Error("could not issue a GET request to the given endpoint", err)
}
return resp
}
From ca32adfa2e2ce7e3100bf82a3d7c88a685fb1666 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Tue, 28 Apr 2020 14:45:33 +0200
Subject: [PATCH 012/160] removed TODO ;
---
eth/backend.go | 2 --
1 file changed, 2 deletions(-)
diff --git a/eth/backend.go b/eth/backend.go
index a7ef070caa9a..d0cf9f779878 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -65,8 +65,6 @@ type LesServer interface {
// Ethereum implements the Ethereum full node service.
type Ethereum struct {
- // TODO needs a p2pServer
-
config *Config
// Handlers
From 8290243a7f4600eb5e9c9efea04e74ea44da66b4 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Tue, 28 Apr 2020 15:23:28 +0200
Subject: [PATCH 013/160] remove unnecessary constructor types
---
node/service.go | 10 ----------
1 file changed, 10 deletions(-)
diff --git a/node/service.go b/node/service.go
index 442d308afadc..7a482161e1d9 100644
--- a/node/service.go
+++ b/node/service.go
@@ -93,16 +93,6 @@ func (ctx *ServiceContext) ExtRPCEnabled() bool {
return ctx.Config.ExtRPCEnabled()
}
-// TODO document
-type BackendConstructor func(node *Node) (Backend, error)
-
-// ServiceConstructor is the function signature of the constructors needed to be
-// registered for service instantiation.
-type ServiceConstructor func(node *Node) (Service, error)
-
-//TODO document
-type AuxiliaryServiceConstructor func(node *Node) (AuxiliaryService, error)
-
type Backend interface {
// Protocols retrieves the P2P protocols the service wishes to start.
Protocols() []p2p.Protocol
From 95bc2569ee19b4100539d132939156339ca7e0f5 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Wed, 29 Apr 2020 13:14:29 +0200
Subject: [PATCH 014/160] fixes http/ws servers not being able to be started on
given host/port
---
graphql/service.go | 11 +++--
node/api.go | 14 +++---
node/endpoints.go | 4 +-
node/node.go | 114 ++++++++++++++++++++++++---------------------
node/rpcstack.go | 5 +-
5 files changed, 79 insertions(+), 69 deletions(-)
diff --git a/graphql/service.go b/graphql/service.go
index 1f4d31356f27..99dd87ef88eb 100644
--- a/graphql/service.go
+++ b/graphql/service.go
@@ -17,6 +17,7 @@
package graphql
import (
+ "context"
"fmt"
"net"
"net/http"
@@ -76,7 +77,8 @@ func (s *Service) Start() error {
go httpSrv.Serve(listener)
log.Info("GraphQL endpoint opened", "url", fmt.Sprintf("http://%s", s.graphqlServer.Endpoint))
// add information to graphql http server
- s.graphqlServer.Listener = listener
+ s.graphqlServer.Server = httpSrv
+ s.graphqlServer.ListenerAddr = listener.Addr()
s.graphqlServer.SetHandler(handler)
return nil
}
@@ -102,10 +104,9 @@ func newHandler(backend ethapi.Backend) (http.Handler, error) {
// Stop terminates all goroutines belonging to the service, blocking until they
// are all terminated.
func (s *Service) Stop() error {
- if s.graphqlServer.Listener != nil {
- s.graphqlServer.Listener.Close()
- s.graphqlServer.Listener = nil
- log.Info("GraphQL endpoint closed", "url", fmt.Sprintf("http://%s", s.graphqlServer.Endpoint))
+ if s.graphqlServer.Server != nil {
+ s.graphqlServer.Server.Shutdown(context.Background())
+ log.Info("GraphQL endpoint closed", "url", fmt.Sprintf("http://%v", s.graphqlServer.ListenerAddr))
}
return nil
}
diff --git a/node/api.go b/node/api.go
index f29911c61818..01a206a6438f 100644
--- a/node/api.go
+++ b/node/api.go
@@ -147,8 +147,8 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
api.node.lock.Lock()
defer api.node.lock.Unlock()
- if api.node.httpHandler != nil {
- return false, fmt.Errorf("HTTP RPC already running on %s", api.node.httpHandler.Endpoint)
+ if api.node.http != nil {
+ return false, fmt.Errorf("HTTP RPC already running on %s", api.node.http.Endpoint)
}
if host == nil {
@@ -178,7 +178,7 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
}
}
- modules := api.node.httpHandler.Whitelist
+ modules := api.node.http.Whitelist
if apis != nil {
modules = nil
for _, m := range strings.Split(*apis, ",") {
@@ -197,7 +197,7 @@ func (api *PrivateAdminAPI) StopRPC() (bool, error) {
api.node.lock.Lock()
defer api.node.lock.Unlock()
- if api.node.httpHandler == nil {
+ if api.node.http == nil {
return false, fmt.Errorf("HTTP RPC not running")
}
api.node.stopHTTP()
@@ -209,8 +209,8 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
api.node.lock.Lock()
defer api.node.lock.Unlock()
- if api.node.wsHandler != nil {
- return false, fmt.Errorf("WebSocket RPC already running on %s", api.node.wsHandler.Endpoint)
+ if api.node.ws != nil {
+ return false, fmt.Errorf("WebSocket RPC already running on %s", api.node.ws.Endpoint)
}
if host == nil {
@@ -251,7 +251,7 @@ func (api *PrivateAdminAPI) StopWS() (bool, error) {
api.node.lock.Lock()
defer api.node.lock.Unlock()
- if api.node.wsHandler == nil {
+ if api.node.ws == nil {
return false, fmt.Errorf("WebSocket RPC not running")
}
api.node.stopWS()
diff --git a/node/endpoints.go b/node/endpoints.go
index 5c9eddd88638..1baa1b5c417f 100644
--- a/node/endpoints.go
+++ b/node/endpoints.go
@@ -26,7 +26,7 @@ import (
)
// StartHTTPEndpoint starts the HTTP RPC endpoint.
-func StartHTTPEndpoint(endpoint string, timeouts rpc.HTTPTimeouts, handler http.Handler) (net.Listener, error) {
+func StartHTTPEndpoint(endpoint string, timeouts rpc.HTTPTimeouts, handler http.Handler) (*http.Server, net.Addr, error) {
// start the HTTP listener
var (
listener net.Listener
@@ -49,7 +49,7 @@ func StartHTTPEndpoint(endpoint string, timeouts rpc.HTTPTimeouts, handler http.
}
// startWSEndpoint starts a websocket endpoint.
-func startWSEndpoint(endpoint string, handler http.Handler) (net.Listener, error) {
+func startWSEndpoint(endpoint string, handler http.Handler) (*http.Server, net.Addr, error) {
// start the HTTP listener
var (
listener net.Listener
diff --git a/node/node.go b/node/node.go
index f487266dd833..db6e3b22cfca 100644
--- a/node/node.go
+++ b/node/node.go
@@ -60,9 +60,9 @@ type Node struct {
rpcAPIs []rpc.API // List of APIs currently provided by the node
inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
- ipcHandler *HttpServer // TODO
- httpHandler *HttpServer // TODO
- wsHandler *HttpServer // TODO
+ ipc *HttpServer // TODO
+ http *HttpServer // TODO
+ ws *HttpServer // TODO
stop chan struct{} // Channel to wait for termination notifications
@@ -115,14 +115,18 @@ func New(conf *Config) (*Node, error) {
},
services: make(map[reflect.Type]Service),
auxServices: make(map[reflect.Type]AuxiliaryService),
- ipcHandler: &HttpServer{
+ ipc: &HttpServer{
endpoint: conf.IPCEndpoint(),
},
- httpHandler: &HttpServer{
+ http: &HttpServer{
endpoint: conf.HTTPEndpoint(),
+ host: conf.HTTPHost,
+ port: conf.HTTPPort,
},
- wsHandler: &HttpServer{
+ ws: &HttpServer{
endpoint: conf.WSEndpoint(),
+ host: conf.WSHost,
+ port: conf.WSPort,
},
eventmux: new(event.TypeMux),
log: conf.Logger,
@@ -352,14 +356,14 @@ func (n *Node) startRPC() error {
n.stopInProc()
return err
}
- if err := n.startHTTP(n.httpHandler.Endpoint(), n.config.HTTPModules, n.config.HTTPCors, n.config.HTTPVirtualHosts, n.config.HTTPTimeouts, n.config.WSOrigins); err != nil {
+ if err := n.startHTTP(n.http.Endpoint(), n.config.HTTPModules, n.config.HTTPCors, n.config.HTTPVirtualHosts, n.config.HTTPTimeouts, n.config.WSOrigins); err != nil {
n.stopIPC()
n.stopInProc()
return err
}
// if endpoints are not the same, start separate servers
- if n.httpHandler.Endpoint() != n.wsHandler.Endpoint() {
- if err := n.startWS(n.wsHandler.Endpoint(), n.config.WSModules, n.config.WSOrigins, n.config.WSExposeAll); err != nil {
+ if n.http.Endpoint() != n.ws.Endpoint() {
+ if err := n.startWS(n.ws.Endpoint(), n.config.WSModules, n.config.WSOrigins, n.config.WSExposeAll); err != nil {
n.stopHTTP()
n.stopIPC()
n.stopInProc()
@@ -395,30 +399,30 @@ func (n *Node) stopInProc() {
// startIPC initializes and starts the IPC RPC endpoint.
func (n *Node) startIPC() error {
- if n.ipcHandler.Endpoint() == "" {
+ if n.ipc.Endpoint() == "" {
return nil // IPC disabled.
}
- listener, handler, err := rpc.StartIPCEndpoint(n.ipcHandler.Endpoint(), n.rpcAPIs)
+ listener, handler, err := rpc.StartIPCEndpoint(n.ipc.Endpoint(), n.rpcAPIs)
if err != nil {
return err
}
- n.ipcHandler.Listener = listener
- n.ipcHandler.handler = handler
- n.log.Info("IPC endpoint opened", "url", n.ipcHandler.Endpoint())
+ n.ipc.Listener = listener
+ n.ipc.handler = handler
+ n.log.Info("IPC endpoint opened", "url", n.ipc.Endpoint())
return nil
}
// stopIPC terminates the IPC RPC endpoint.
func (n *Node) stopIPC() {
- if n.ipcHandler.Listener != nil {
- n.ipcHandler.Listener.Close()
- n.ipcHandler.Listener = nil
+ if n.ipc.Listener != nil {
+ n.ipc.Listener.Close()
+ n.ipc.Listener = nil
- n.log.Info("IPC endpoint closed", "url", n.ipcHandler.Endpoint())
+ n.log.Info("IPC endpoint closed", "url", n.ipc.Endpoint())
}
- if n.ipcHandler.Srv != nil {
- n.ipcHandler.Srv.Stop()
- n.ipcHandler.Srv = nil
+ if n.ipc.Srv != nil {
+ n.ipc.Srv.Stop()
+ n.ipc.Srv = nil
}
}
@@ -436,38 +440,39 @@ func (n *Node) startHTTP(endpoint string, modules []string, cors []string, vhost
}
handler := NewHTTPHandlerStack(srv, cors, vhosts)
// wrap handler in websocket handler only if websocket port is the same as http rpc
- if n.httpHandler.Endpoint() == n.wsHandler.Endpoint() {
+ if n.http.Endpoint() == n.ws.Endpoint() {
handler = NewWebsocketUpgradeHandler(handler, srv.WebsocketHandler(wsOrigins))
}
httpServer, addr, err := StartHTTPEndpoint(endpoint, timeouts, handler)
if err != nil {
return err
}
- n.log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%v/", listener.Addr()),
+ n.log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%v/", addr),
"cors", strings.Join(cors, ","),
"vhosts", strings.Join(vhosts, ","))
- if n.httpHandler.Endpoint() == n.wsHandler.Endpoint() {
- n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", listener.Addr()))
+ if n.http.Endpoint() == n.ws.Endpoint() {
+ n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", addr))
}
// All listeners booted successfully
- n.httpHandler.endpoint = endpoint
- n.httpHandler.Listener = listener
- n.httpHandler.Srv = srv
+ n.http.endpoint = endpoint
+ n.http.Server = httpServer
+ n.http.ListenerAddr = addr
+ n.http.Srv = srv
return nil
}
// stopHTTP terminates the HTTP RPC endpoint.
func (n *Node) stopHTTP() {
- if n.httpHandler.Listener != nil {
- url := fmt.Sprintf("http://%v/", n.httpHandler.Listener.Addr())
- n.httpHandler.Listener.Close()
- n.httpHandler.Listener = nil
+ if n.http.Server != nil {
+ url := fmt.Sprintf("http://%v/", n.http.ListenerAddr)
+ // Don't bother imposing a timeout here.
+ n.http.Server.Shutdown(context.Background())
n.log.Info("HTTP Endpoint closed", "url", url)
}
- if n.httpHandler.Srv != nil {
- n.httpHandler.Srv.Stop()
- n.httpHandler.Srv = nil
+ if n.http.Srv != nil {
+ n.http.Srv.Stop()
+ n.http.Srv = nil
}
}
@@ -488,26 +493,27 @@ func (n *Node) startWS(endpoint string, modules []string, wsOrigins []string, ex
if err != nil {
return err
}
- n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%s", listener.Addr()))
+ n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%s", addr))
// All listeners booted successfully
- n.wsHandler.endpoint = endpoint
- n.wsHandler.Listener = listener
- n.wsHandler.Srv = srv
+ n.ws.endpoint = endpoint
+ n.ws.ListenerAddr = addr
+ n.ws.Server = httpServer
+ n.ws.Srv = srv
return nil
}
// stopWS terminates the websocket RPC endpoint.
func (n *Node) stopWS() {
- if n.wsHandler.Listener != nil {
- n.wsHandler.Listener.Close()
- n.wsHandler.Listener = nil
-
- n.log.Info("WebSocket endpoint closed", "url", fmt.Sprintf("ws://%s", n.wsHandler.Endpoint))
+ if n.ws.Server != nil {
+ url := fmt.Sprintf("http://%v/", n.ws.ListenerAddr)
+ // Don't bother imposing a timeout here.
+ n.ws.Server.Shutdown(context.Background())
+ n.log.Info("HTTP Endpoint closed", "url", url)
}
- if n.wsHandler.Srv != nil {
- n.wsHandler.Srv.Stop()
- n.wsHandler.Srv = nil
+ if n.ws.Srv != nil {
+ n.ws.Srv.Stop()
+ n.ws.Srv = nil
}
}
@@ -681,7 +687,7 @@ func (n *Node) AccountManager() *accounts.Manager {
// IPCEndpoint retrieves the current IPC endpoint used by the protocol stack.
func (n *Node) IPCEndpoint() string {
- return n.ipcHandler.Endpoint()
+ return n.ipc.Endpoint()
}
// HTTPEndpoint retrieves the current HTTP endpoint used by the protocol stack.
@@ -689,10 +695,10 @@ func (n *Node) HTTPEndpoint() string {
n.lock.Lock()
defer n.lock.Unlock()
- if n.httpHandler.Listener != nil {
- return n.httpHandler.Listener.Addr().String()
+ if n.http.Server != nil {
+ return n.http.ListenerAddr.String()
}
- return n.httpHandler.Endpoint()
+ return n.http.Endpoint()
}
// WSEndpoint retrieves the current WS endpoint
@@ -701,10 +707,10 @@ func (n *Node) WSEndpoint() string {
n.lock.Lock()
defer n.lock.Unlock()
- if n.wsHandler.Listener != nil {
- return n.wsHandler.Listener.Addr().String()
+ if n.ws.Server != nil {
+ return n.ws.ListenerAddr.String()
}
- return n.wsHandler.Endpoint()
+ return n.ws.Endpoint()
}
// EventMux retrieves the event multiplexer used by all the network services in
diff --git a/node/rpcstack.go b/node/rpcstack.go
index 3cf8a9c46c08..fbb74cd7f97b 100644
--- a/node/rpcstack.go
+++ b/node/rpcstack.go
@@ -34,7 +34,10 @@ import (
type HttpServer struct {
handler http.Handler
Srv *rpc.Server
- Listener net.Listener
+ Server *http.Server
+
+ Listener net.Listener
+ ListenerAddr net.Addr
endpoint string
host string
From 0ba43ecfa19798a8a34f0f35972d9bf9aea91ecf Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Sun, 3 May 2020 20:41:35 +0200
Subject: [PATCH 015/160] registerHTTP but not w the signature felix suggested
---
ethstats/ethstats.go | 2 +-
graphql/service.go | 6 +--
node/node.go | 89 ++++++++++++++++++++++++++++++++++++--------
node/rpcstack.go | 34 ++++++++++++++---
node/service.go | 3 +-
5 files changed, 108 insertions(+), 26 deletions(-)
diff --git a/ethstats/ethstats.go b/ethstats/ethstats.go
index 81283370c8ce..c9f6343da56f 100644
--- a/ethstats/ethstats.go
+++ b/ethstats/ethstats.go
@@ -134,7 +134,7 @@ func (s *Service) Stop() error {
return nil
}
-func (s *Service) Server() *node.HttpServer { return nil }
+func (s *Service) Server() *node.HTTPServer { return nil }
// loop keeps trying to connect to the netstats server, reporting chain events
// until termination.
diff --git a/graphql/service.go b/graphql/service.go
index 99dd87ef88eb..b88e7109e561 100644
--- a/graphql/service.go
+++ b/graphql/service.go
@@ -33,14 +33,14 @@ import (
// Service encapsulates a GraphQL service.
type Service struct {
backend ethapi.Backend // The backend that queries will operate on.
- graphqlServer *node.HttpServer
+ graphqlServer *node.HTTPServer
}
// New constructs a new GraphQL service instance.
func New(backend ethapi.Backend, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) (*Service, error) {
service := &Service{
backend: backend,
- graphqlServer: &node.HttpServer{
+ graphqlServer: &node.HTTPServer{
Timeouts: timeouts,
Vhosts: vhosts,
CorsAllowedOrigins: cors,
@@ -111,6 +111,6 @@ func (s *Service) Stop() error {
return nil
}
-func (s *Service) Server() *node.HttpServer {
+func (s *Service) Server() *node.HTTPServer {
return s.graphqlServer
}
diff --git a/node/node.go b/node/node.go
index db6e3b22cfca..c9d639945eea 100644
--- a/node/node.go
+++ b/node/node.go
@@ -20,6 +20,8 @@ import (
"context"
"errors"
"fmt"
+ "net"
+ "net/http"
"os"
"path/filepath"
"reflect"
@@ -60,9 +62,9 @@ type Node struct {
rpcAPIs []rpc.API // List of APIs currently provided by the node
inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
- ipc *HttpServer // TODO
- http *HttpServer // TODO
- ws *HttpServer // TODO
+ ipc *HTTPServer // TODO
+ http *HTTPServer // TODO
+ ws *HTTPServer // TODO
stop chan struct{} // Channel to wait for termination notifications
@@ -115,15 +117,23 @@ func New(conf *Config) (*Node, error) {
},
services: make(map[reflect.Type]Service),
auxServices: make(map[reflect.Type]AuxiliaryService),
- ipc: &HttpServer{
+ ipc: &HTTPServer{
endpoint: conf.IPCEndpoint(),
},
- http: &HttpServer{
+ http: &HTTPServer{
+ CorsAllowedOrigins: conf.HTTPCors,
+ Vhosts: conf.HTTPVirtualHosts,
+ Whitelist: conf.HTTPModules,
+ Timeouts: conf.HTTPTimeouts,
+ Srv: rpc.NewServer(),
endpoint: conf.HTTPEndpoint(),
host: conf.HTTPHost,
port: conf.HTTPPort,
},
- ws: &HttpServer{
+ ws: &HTTPServer{
+ CorsAllowedOrigins: conf.WSOrigins,
+ Whitelist: conf.WSModules,
+ Srv: rpc.NewServer(),
endpoint: conf.WSEndpoint(),
host: conf.WSHost,
port: conf.WSPort,
@@ -159,6 +169,7 @@ func (n *Node) Close() error {
}
}
+// TODO document
func (n *Node) RegisterLifecycle(lifecycle Lifecycle) {
n.lifecycles = append(n.lifecycles, lifecycle)
}
@@ -234,6 +245,36 @@ func (n *Node) RegisterRPC(apis []rpc.API) {
n.rpcAPIs = apis
}
+// TODO what is the purpose of this function? Define it and document it.
+func (n *Node) RegisterHTTP(h *HTTPServer, exposeAll bool) error {
+ // register apis and create handler stack
+ err := RegisterApisFromWhitelist(n.rpcAPIs, h.Whitelist, h.Srv, exposeAll)
+ if err != nil {
+ return err
+ }
+
+ // start the HTTP listener
+ listener, err := net.Listen("tcp", h.endpoint)
+ if err != nil {
+ return err
+ }
+ // create the HTTP server
+ httpSrv := &http.Server{Handler: h.handler}
+ // check timeouts if they exist
+ if h.Timeouts != (rpc.HTTPTimeouts{}) {
+ CheckTimeouts(&h.Timeouts)
+ httpSrv.ReadTimeout = h.Timeouts.ReadTimeout
+ httpSrv.WriteTimeout = h.Timeouts.WriteTimeout
+ httpSrv.IdleTimeout = h.Timeouts.IdleTimeout
+ }
+ // complete the HTTPServer
+ h.Listener = listener
+ h.ListenerAddr = listener.Addr()
+ h.Server = httpSrv
+
+ return nil
+}
+
// running returns true if the node's p2p server is already running
func (n *Node) running() bool {
return n.server != nil
@@ -312,6 +353,7 @@ func (n *Node) Start() error {
return nil
}
+// TODO document
func (n *Node) stopLifecycles(started []Lifecycle) {
for _, lifecycle := range started {
lifecycle.Stop()
@@ -347,7 +389,6 @@ func (n *Node) openDataDir() error {
// assumptions about the state of the node.
func (n *Node) startRPC() error {
n.RegisterRPC(n.apis())
-
// Start the various API endpoints, terminating all in case of errors
if err := n.startInProc(); err != nil {
return err
@@ -356,21 +397,37 @@ func (n *Node) startRPC() error {
n.stopInProc()
return err
}
- if err := n.startHTTP(n.http.Endpoint(), n.config.HTTPModules, n.config.HTTPCors, n.config.HTTPVirtualHosts, n.config.HTTPTimeouts, n.config.WSOrigins); err != nil {
- n.stopIPC()
- n.stopInProc()
- return err
+ // create and start http server if the endpoint exists
+ if n.http.endpoint != "" {
+ // wrap handler in websocket handler only if websocket port is the same as http rpc
+ n.http.handler = NewHTTPHandlerStack(n.http.Srv, n.http.CorsAllowedOrigins, n.http.Vhosts)
+ if n.http.endpoint == n.ws.endpoint {
+ n.http.handler = NewWebsocketUpgradeHandler(n.http.handler, n.http.Srv.WebsocketHandler(n.ws.CorsAllowedOrigins))
+ }
+ if err := n.RegisterHTTP(n.http, false); err != nil {
+ n.stopIPC()
+ n.stopInProc()
+ return err
+ }
+ n.http.Start()
+ n.log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%v/", n.http.ListenerAddr),
+ "cors", strings.Join(n.http.CorsAllowedOrigins, ","),
+ "vhosts", strings.Join(n.http.Vhosts, ","))
+ if n.http.Endpoint() == n.ws.Endpoint() {
+ n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", n.http.ListenerAddr))
+ }
}
- // if endpoints are not the same, start separate servers
- if n.http.Endpoint() != n.ws.Endpoint() {
- if err := n.startWS(n.ws.Endpoint(), n.config.WSModules, n.config.WSOrigins, n.config.WSExposeAll); err != nil {
- n.stopHTTP()
+ // create and start ws server if the endpoint exists
+ if n.ws.endpoint != "" && n.http.endpoint != n.ws.endpoint {
+ n.ws.handler = n.ws.Srv.WebsocketHandler(n.ws.CorsAllowedOrigins)
+ if err := n.RegisterHTTP(n.ws, n.config.WSExposeAll); err != nil {
n.stopIPC()
n.stopInProc()
return err
}
+ n.ws.Start()
+ n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%s", n.ws.ListenerAddr))
}
-
// All API endpoints started successfully
return nil
}
diff --git a/node/rpcstack.go b/node/rpcstack.go
index fbb74cd7f97b..8696c2808558 100644
--- a/node/rpcstack.go
+++ b/node/rpcstack.go
@@ -18,6 +18,7 @@ package node
import (
"compress/gzip"
+ "context"
"fmt"
"github.com/ethereum/go-ethereum/rpc"
"io"
@@ -31,7 +32,7 @@ import (
"github.com/rs/cors"
)
-type HttpServer struct {
+type HTTPServer struct {
handler http.Handler
Srv *rpc.Server
Server *http.Server
@@ -54,19 +55,42 @@ type HttpServer struct {
WSAllowed bool
}
-func (h *HttpServer) Handler() http.Handler {
+// TODO document
+func (h *HTTPServer) Start() {
+ go h.Server.Serve(h.Listener)
+}
+
+// TODO document
+func (h *HTTPServer) Stop() {
+ if h.Server != nil {
+ //url := fmt.Sprintf("http://%v/", h.ListenerAddr)
+ // Don't bother imposing a timeout here.
+ h.Server.Shutdown(context.Background())
+ //n.log.Info("HTTP Endpoint closed", "url", url) // TODO log wherever this is called instead
+ }
+ if h.Srv != nil {
+ h.Srv.Stop()
+ h.Srv = nil
+ }
+}
+
+// Handler returns the handler of the HTTPServer
+func (h *HTTPServer) Handler() http.Handler {
return h.handler
}
-func (h *HttpServer) SetHandler(handler http.Handler) {
+// TODO document
+func (h *HTTPServer) SetHandler(handler http.Handler) {
h.handler = handler
}
-func (h *HttpServer) Endpoint() string {
+// TODO is this really necessary?
+func (h *HTTPServer) Endpoint() string {
return fmt.Sprintf("%s:%d", h.host, h.port)
}
-func (h *HttpServer) SetEndpoint(endpoint string) {
+// TODO is this necessary?
+func (h *HTTPServer) SetEndpoint(endpoint string) {
h.endpoint = endpoint
}
diff --git a/node/service.go b/node/service.go
index 7a482161e1d9..00ff552d76ba 100644
--- a/node/service.go
+++ b/node/service.go
@@ -93,6 +93,7 @@ func (ctx *ServiceContext) ExtRPCEnabled() bool {
return ctx.Config.ExtRPCEnabled()
}
+// TODO document
type Backend interface {
// Protocols retrieves the P2P protocols the service wishes to start.
Protocols() []p2p.Protocol
@@ -125,7 +126,7 @@ type Service interface {
// TODO document
type AuxiliaryService interface {
// TODO document
- Server() *HttpServer
+ Server() *HTTPServer
// AuxiliaryService also implements Lifecycle
Lifecycle
From 4985505f02f06a50203255e8aac419d9dd4d03fc Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Mon, 4 May 2020 11:38:43 +0200
Subject: [PATCH 016/160] enable rpc/ws
---
graphql/service.go | 8 +++++---
node/node.go | 3 +++
2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/graphql/service.go b/graphql/service.go
index b88e7109e561..59f9aa21cbac 100644
--- a/graphql/service.go
+++ b/graphql/service.go
@@ -53,18 +53,19 @@ func New(backend ethapi.Backend, endpoint string, cors, vhosts []string, timeout
// Start is called after all services have been constructed and the networking
// layer was also initialized to spawn any goroutines required by the service.
func (s *Service) Start() error {
- var err error
+ // create handler stack and wrap the graphql handler
handler, err := newHandler(s.backend)
if err != nil {
return err
}
+ handler = node.NewHTTPHandlerStack(handler, s.graphqlServer.CorsAllowedOrigins, s.graphqlServer.Vhosts)
+ s.graphqlServer.SetHandler(handler)
listener, err := net.Listen("tcp", s.graphqlServer.Endpoint())
if err != nil {
return err
}
- // create handler stack and wrap the graphql handler
- handler = node.NewHTTPHandlerStack(handler, s.graphqlServer.CorsAllowedOrigins, s.graphqlServer.Vhosts)
+
// make sure timeout values are meaningful
node.CheckTimeouts(&s.graphqlServer.Timeouts)
// create http server
@@ -80,6 +81,7 @@ func (s *Service) Start() error {
s.graphqlServer.Server = httpSrv
s.graphqlServer.ListenerAddr = listener.Addr()
s.graphqlServer.SetHandler(handler)
+
return nil
}
diff --git a/node/node.go b/node/node.go
index c9d639945eea..9445495a823d 100644
--- a/node/node.go
+++ b/node/node.go
@@ -410,10 +410,12 @@ func (n *Node) startRPC() error {
return err
}
n.http.Start()
+ n.http.RPCAllowed = true
n.log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%v/", n.http.ListenerAddr),
"cors", strings.Join(n.http.CorsAllowedOrigins, ","),
"vhosts", strings.Join(n.http.Vhosts, ","))
if n.http.Endpoint() == n.ws.Endpoint() {
+ n.http.WSAllowed = true
n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", n.http.ListenerAddr))
}
}
@@ -426,6 +428,7 @@ func (n *Node) startRPC() error {
return err
}
n.ws.Start()
+ n.ws.WSAllowed = true
n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%s", n.ws.ListenerAddr))
}
// All API endpoints started successfully
From 62ec8473d1bea36cf74bb7b549be6b71731793da Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Mon, 4 May 2020 14:07:28 +0200
Subject: [PATCH 017/160] changed RegisterHTTP and cleaned up some code, now
gql can start on same port as http
---
cmd/utils/flags.go | 40 +++++++++++++++---------------
graphql/service.go | 61 +++++++++++++++++++++++++++++-----------------
node/node.go | 46 ++++++++++++++++++++++++++--------
node/rpcstack.go | 22 +++++++++++++++--
4 files changed, 114 insertions(+), 55 deletions(-)
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index f915566f9dc4..9eac2beb7110 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -20,6 +20,7 @@ package utils
import (
"crypto/ecdsa"
"fmt"
+ "github.com/ethereum/go-ethereum/internal/ethapi"
"io"
"io/ioutil"
"math/big"
@@ -1741,30 +1742,27 @@ func RegisterEthStatsService(stack *node.Node, url string) {
// RegisterGraphQLService is a utility function to construct a new service and register it against a node.
func RegisterGraphQLService(stack *node.Node, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) {
- // Try to construct the GraphQL service backed by a full node
- if ethBackend, ok := stack.Backend().(*eth.Ethereum); ok {
- graphqlAuxService, err := graphql.New(ethBackend.APIBackend, endpoint, cors, vhosts, timeouts)
- if err != nil {
- Fatalf("Failed to register the GraphQL service: %v", err)
- }
- if err := stack.RegisterAuxService(graphqlAuxService); err != nil {
- Fatalf("Failed to register the GraphQL service: %v", err)
- }
- stack.RegisterLifecycle(graphqlAuxService)
+ var backend ethapi.Backend
+ switch stack.Backend() {
+ case stack.Backend().(*eth.Ethereum):
+ backend = stack.Backend().(*eth.Ethereum).APIBackend
+ case stack.Backend().(*les.LightEthereum):
+ backend = stack.Backend().(*les.LightEthereum).ApiBackend
+ default:
+ // Well, this should not have happened, bail out
+ Fatalf("no Ethereum service")
}
- // Try to construct the GraphQL service backed by a light node
- if lesBackend, ok := stack.Backend().(*les.LightEthereum); ok {
- graphqlAuxService, err := graphql.New(lesBackend.ApiBackend, endpoint, cors, vhosts, timeouts)
- if err != nil {
- Fatalf("Failed to register the GraphQL service: %v", err)
- }
- if err := stack.RegisterAuxService(graphqlAuxService); err != nil {
- Fatalf("Failed to register the GraphQL service: %v", err)
- }
+
+ graphqlAuxService, err := graphql.New(backend, endpoint, cors, vhosts, timeouts)
+ if err != nil {
+ Fatalf("Failed to register the GraphQL service: %v", err)
+ }
+ if err := stack.RegisterAuxService(graphqlAuxService); err != nil {
+ Fatalf("Failed to register the GraphQL service: %v", err)
+ }
+ if graphqlAuxService.Server().Endpoint() != stack.Config().HTTPEndpoint() {
stack.RegisterLifecycle(graphqlAuxService)
}
- // Well, this should not have happened, bail out
- Fatalf("no Ethereum service")
}
func SetupMetrics(ctx *cli.Context) {
diff --git a/graphql/service.go b/graphql/service.go
index 59f9aa21cbac..5224fd0a61d7 100644
--- a/graphql/service.go
+++ b/graphql/service.go
@@ -44,28 +44,63 @@ func New(backend ethapi.Backend, endpoint string, cors, vhosts []string, timeout
Timeouts: timeouts,
Vhosts: vhosts,
CorsAllowedOrigins: cors,
+ GQLAllowed: true,
},
}
service.graphqlServer.SetEndpoint(endpoint)
+ // create handler
+ handler, err := service.CreateHandler()
+ if err != nil {
+ return nil, err
+ }
+ service.graphqlServer.SetHandler(handler)
+
return service, nil
}
+func (s *Service) CreateHandler() (http.Handler, error) {
+ // create handler stack and wrap the graphql handler
+ handler, err := newHandler(s.backend)
+ if err != nil {
+ return nil, err
+ }
+
+ return handler, nil
+}
+
+// newHandler returns a new `http.Handler` that will answer GraphQL queries.
+// It additionally exports an interactive query browser on the / endpoint.
+func newHandler(backend ethapi.Backend) (http.Handler, error) {
+ q := Resolver{backend}
+
+ s, err := graphql.ParseSchema(schema, &q)
+ if err != nil {
+ return nil, err
+ }
+ h := &relay.Handler{Schema: s}
+
+ mux := http.NewServeMux()
+ mux.Handle("/", GraphiQL{})
+ mux.Handle("/graphql", h)
+ mux.Handle("/graphql/", h)
+ return mux, nil
+}
+
// Start is called after all services have been constructed and the networking
// layer was also initialized to spawn any goroutines required by the service.
func (s *Service) Start() error {
- // create handler stack and wrap the graphql handler
- handler, err := newHandler(s.backend)
+ handler, err := s.CreateHandler()
if err != nil {
return err
}
handler = node.NewHTTPHandlerStack(handler, s.graphqlServer.CorsAllowedOrigins, s.graphqlServer.Vhosts)
s.graphqlServer.SetHandler(handler)
+ // start listening on given endpoint
listener, err := net.Listen("tcp", s.graphqlServer.Endpoint())
if err != nil {
return err
}
-
// make sure timeout values are meaningful
node.CheckTimeouts(&s.graphqlServer.Timeouts)
// create http server
@@ -76,7 +111,7 @@ func (s *Service) Start() error {
IdleTimeout: s.graphqlServer.Timeouts.IdleTimeout,
}
go httpSrv.Serve(listener)
- log.Info("GraphQL endpoint opened", "url", fmt.Sprintf("http://%s", s.graphqlServer.Endpoint))
+ log.Info("GraphQL endpoint opened", "url", fmt.Sprintf("http://%v", listener.Addr()))
// add information to graphql http server
s.graphqlServer.Server = httpSrv
s.graphqlServer.ListenerAddr = listener.Addr()
@@ -85,24 +120,6 @@ func (s *Service) Start() error {
return nil
}
-// newHandler returns a new `http.Handler` that will answer GraphQL queries.
-// It additionally exports an interactive query browser on the / endpoint.
-func newHandler(backend ethapi.Backend) (http.Handler, error) {
- q := Resolver{backend}
-
- s, err := graphql.ParseSchema(schema, &q)
- if err != nil {
- return nil, err
- }
- h := &relay.Handler{Schema: s}
-
- mux := http.NewServeMux()
- mux.Handle("/", GraphiQL{})
- mux.Handle("/graphql", h)
- mux.Handle("/graphql/", h)
- return mux, nil
-}
-
// Stop terminates all goroutines belonging to the service, blocking until they
// are all terminated.
func (s *Service) Stop() error {
diff --git a/node/node.go b/node/node.go
index 9445495a823d..275c1d2794fe 100644
--- a/node/node.go
+++ b/node/node.go
@@ -129,6 +129,7 @@ func New(conf *Config) (*Node, error) {
endpoint: conf.HTTPEndpoint(),
host: conf.HTTPHost,
port: conf.HTTPPort,
+ RPCAllowed: true,
},
ws: &HTTPServer{
CorsAllowedOrigins: conf.WSOrigins,
@@ -137,6 +138,7 @@ func New(conf *Config) (*Node, error) {
endpoint: conf.WSEndpoint(),
host: conf.WSHost,
port: conf.WSPort,
+ WSAllowed: true,
},
eventmux: new(event.TypeMux),
log: conf.Logger,
@@ -245,8 +247,24 @@ func (n *Node) RegisterRPC(apis []rpc.API) {
n.rpcAPIs = apis
}
-// TODO what is the purpose of this function? Define it and document it.
-func (n *Node) RegisterHTTP(h *HTTPServer, exposeAll bool) error {
+// TODO document
+func (n *Node) RegisterHTTP(dest *HTTPServer, toRegister *HTTPServer) {
+ // takes in default existing http server
+ // enables ____ on it
+ if toRegister.WSAllowed {
+ dest.handler = NewWebsocketUpgradeHandler(dest.handler, toRegister.handler)
+ dest.WSAllowed = true
+ log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", toRegister.endpoint))
+ }
+ if toRegister.GQLAllowed {
+ dest.handler = NewGQLUpgradeHandler(dest.handler, toRegister.handler)
+ dest.GQLAllowed = true
+ log.Info("GraphQL endpoint opened", "url", fmt.Sprintf("http://%v", toRegister.endpoint))
+ }
+}
+
+// CreateHTTPServer creates an http.Server and adds it to the given HTTPServer // TODO improve?
+func (n *Node) CreateHTTPServer(h *HTTPServer, exposeAll bool) error {
// register apis and create handler stack
err := RegisterApisFromWhitelist(n.rpcAPIs, h.Whitelist, h.Srv, exposeAll)
if err != nil {
@@ -325,7 +343,6 @@ func (n *Node) Start() error {
n.server.Stop()
return err
}
-
// Start all registered lifecycles
var started []Lifecycle
for _, lifecycle := range n.lifecycles {
@@ -398,31 +415,40 @@ func (n *Node) startRPC() error {
return err
}
// create and start http server if the endpoint exists
+ // TODO CLEAN THIS UP!!!!!!!!!
if n.http.endpoint != "" {
+ var exposeAll bool
+
// wrap handler in websocket handler only if websocket port is the same as http rpc
n.http.handler = NewHTTPHandlerStack(n.http.Srv, n.http.CorsAllowedOrigins, n.http.Vhosts)
if n.http.endpoint == n.ws.endpoint {
- n.http.handler = NewWebsocketUpgradeHandler(n.http.handler, n.http.Srv.WebsocketHandler(n.ws.CorsAllowedOrigins))
+ n.ws.handler = n.ws.Srv.WebsocketHandler(n.ws.CorsAllowedOrigins)
+ n.RegisterHTTP(n.http, n.ws)
+ exposeAll = n.config.WSExposeAll
}
- if err := n.RegisterHTTP(n.http, false); err != nil {
+
+ for _, auxServices := range n.auxServices {
+ if auxServices.Server().endpoint == n.http.endpoint {
+ n.RegisterHTTP(n.http, auxServices.Server())
+ }
+ }
+
+ if err := n.CreateHTTPServer(n.http, exposeAll); err != nil {
n.stopIPC()
n.stopInProc()
return err
}
+
n.http.Start()
n.http.RPCAllowed = true
n.log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%v/", n.http.ListenerAddr),
"cors", strings.Join(n.http.CorsAllowedOrigins, ","),
"vhosts", strings.Join(n.http.Vhosts, ","))
- if n.http.Endpoint() == n.ws.Endpoint() {
- n.http.WSAllowed = true
- n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", n.http.ListenerAddr))
- }
}
// create and start ws server if the endpoint exists
if n.ws.endpoint != "" && n.http.endpoint != n.ws.endpoint {
n.ws.handler = n.ws.Srv.WebsocketHandler(n.ws.CorsAllowedOrigins)
- if err := n.RegisterHTTP(n.ws, n.config.WSExposeAll); err != nil {
+ if err := n.CreateHTTPServer(n.ws, n.config.WSExposeAll); err != nil {
n.stopIPC()
n.stopInProc()
return err
diff --git a/node/rpcstack.go b/node/rpcstack.go
index 8696c2808558..ec10d6335703 100644
--- a/node/rpcstack.go
+++ b/node/rpcstack.go
@@ -19,7 +19,6 @@ package node
import (
"compress/gzip"
"context"
- "fmt"
"github.com/ethereum/go-ethereum/rpc"
"io"
"io/ioutil"
@@ -53,6 +52,7 @@ type HTTPServer struct {
RPCAllowed bool
WSAllowed bool
+ GQLAllowed bool
}
// TODO document
@@ -86,7 +86,7 @@ func (h *HTTPServer) SetHandler(handler http.Handler) {
// TODO is this really necessary?
func (h *HTTPServer) Endpoint() string {
- return fmt.Sprintf("%s:%d", h.host, h.port)
+ return h.endpoint
}
// TODO is this necessary?
@@ -222,3 +222,21 @@ func isWebsocket(r *http.Request) bool {
return strings.ToLower(r.Header.Get("Upgrade")) == "websocket" &&
strings.ToLower(r.Header.Get("Connection")) == "upgrade"
}
+
+// TODO document
+func NewGQLUpgradeHandler(h http.Handler, gql http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if isGQL(r) {
+ gql.ServeHTTP(w, r)
+ log.Debug("serving graphql request")
+ return
+ }
+
+ h.ServeHTTP(w, r)
+ })
+}
+
+// TODO document
+func isGQL(r *http.Request) bool {
+ return r.URL.Path == "/graphql" || r.URL.Path == "/graphql/"
+}
From 104ca9cb38c343df918d0cbce0b7b8b732364142 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Mon, 4 May 2020 14:33:05 +0200
Subject: [PATCH 018/160] some clean up
---
graphql/service.go | 2 +-
node/node.go | 12 +++++-------
2 files changed, 6 insertions(+), 8 deletions(-)
diff --git a/graphql/service.go b/graphql/service.go
index 5224fd0a61d7..523a6b4eff68 100644
--- a/graphql/service.go
+++ b/graphql/service.go
@@ -65,6 +65,7 @@ func (s *Service) CreateHandler() (http.Handler, error) {
return nil, err
}
+ handler = node.NewHTTPHandlerStack(handler, s.graphqlServer.CorsAllowedOrigins, s.graphqlServer.Vhosts)
return handler, nil
}
@@ -93,7 +94,6 @@ func (s *Service) Start() error {
if err != nil {
return err
}
- handler = node.NewHTTPHandlerStack(handler, s.graphqlServer.CorsAllowedOrigins, s.graphqlServer.Vhosts)
s.graphqlServer.SetHandler(handler)
// start listening on given endpoint
diff --git a/node/node.go b/node/node.go
index 275c1d2794fe..397fce4a3193 100644
--- a/node/node.go
+++ b/node/node.go
@@ -249,8 +249,8 @@ func (n *Node) RegisterRPC(apis []rpc.API) {
// TODO document
func (n *Node) RegisterHTTP(dest *HTTPServer, toRegister *HTTPServer) {
- // takes in default existing http server
- // enables ____ on it
+ // takes in default existing http server
+ // enables ____ on it
if toRegister.WSAllowed {
dest.handler = NewWebsocketUpgradeHandler(dest.handler, toRegister.handler)
dest.WSAllowed = true
@@ -414,11 +414,9 @@ func (n *Node) startRPC() error {
n.stopInProc()
return err
}
- // create and start http server if the endpoint exists
- // TODO CLEAN THIS UP!!!!!!!!!
+ // create and start http server if the endpoint exists // TODO CLEAN THIS UP!!!!!!!!!
if n.http.endpoint != "" {
var exposeAll bool
-
// wrap handler in websocket handler only if websocket port is the same as http rpc
n.http.handler = NewHTTPHandlerStack(n.http.Srv, n.http.CorsAllowedOrigins, n.http.Vhosts)
if n.http.endpoint == n.ws.endpoint {
@@ -426,13 +424,13 @@ func (n *Node) startRPC() error {
n.RegisterHTTP(n.http, n.ws)
exposeAll = n.config.WSExposeAll
}
-
+ // if an auxiliary service has not been started, check if it has the same endpoint, then start
for _, auxServices := range n.auxServices {
if auxServices.Server().endpoint == n.http.endpoint {
n.RegisterHTTP(n.http, auxServices.Server())
}
}
-
+ // create the HTTP Server
if err := n.CreateHTTPServer(n.http, exposeAll); err != nil {
n.stopIPC()
n.stopInProc()
From 6e53f68ceb0a59f17dd2101a06682e74f501617a Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Mon, 4 May 2020 14:49:32 +0200
Subject: [PATCH 019/160] changed console http startup
---
node/api.go | 25 +++++++++++++++++++------
node/node.go | 4 +---
2 files changed, 20 insertions(+), 9 deletions(-)
diff --git a/node/api.go b/node/api.go
index 01a206a6438f..b32984c2b4ef 100644
--- a/node/api.go
+++ b/node/api.go
@@ -147,8 +147,8 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
api.node.lock.Lock()
defer api.node.lock.Unlock()
- if api.node.http != nil {
- return false, fmt.Errorf("HTTP RPC already running on %s", api.node.http.Endpoint)
+ if api.node.http.Server != nil {
+ return false, fmt.Errorf("HTTP RPC already running on %v", api.node.http.ListenerAddr)
}
if host == nil {
@@ -161,6 +161,9 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
if port == nil {
port = &api.node.config.HTTPPort
}
+ api.node.http.host = *host
+ api.node.http.port = *port
+ api.node.http.endpoint = fmt.Sprintf("%s:%d", *host, *port)
allowedOrigins := api.node.config.HTTPCors
if cors != nil {
@@ -169,6 +172,7 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
allowedOrigins = append(allowedOrigins, strings.TrimSpace(origin))
}
}
+ api.node.http.CorsAllowedOrigins = allowedOrigins
allowedVHosts := api.node.config.HTTPVirtualHosts
if vhosts != nil {
@@ -177,6 +181,7 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
allowedVHosts = append(allowedVHosts, strings.TrimSpace(vhost))
}
}
+ api.node.http.Vhosts = allowedVHosts
modules := api.node.http.Whitelist
if apis != nil {
@@ -185,10 +190,18 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
modules = append(modules, strings.TrimSpace(m))
}
}
-
- if err := api.node.startHTTP(fmt.Sprintf("%s:%d", *host, *port), modules, allowedOrigins, allowedVHosts, api.node.config.HTTPTimeouts, api.node.config.WSOrigins); err != nil {
+ api.node.http.Whitelist = modules
+ // create handler
+ api.node.http.handler = NewHTTPHandlerStack(api.node.http.Srv, api.node.http.CorsAllowedOrigins, api.node.http.Vhosts)
+ // create HTTP server
+ if err := api.node.CreateHTTPServer(api.node.http, false); err != nil {
return false, err
}
+ // start the HTTP server
+ api.node.http.Start()
+ api.node.log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%v/", api.node.http.ListenerAddr),
+ "cors", strings.Join(api.node.http.CorsAllowedOrigins, ","),
+ "vhosts", strings.Join(api.node.http.Vhosts, ","))
return true, nil
}
@@ -209,8 +222,8 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
api.node.lock.Lock()
defer api.node.lock.Unlock()
- if api.node.ws != nil {
- return false, fmt.Errorf("WebSocket RPC already running on %s", api.node.ws.Endpoint)
+ if api.node.ws.Server != nil {
+ return false, fmt.Errorf("WebSocket RPC already running on %v", api.node.ws.ListenerAddr)
}
if host == nil {
diff --git a/node/node.go b/node/node.go
index 397fce4a3193..fbac1a9fb0b2 100644
--- a/node/node.go
+++ b/node/node.go
@@ -426,7 +426,7 @@ func (n *Node) startRPC() error {
}
// if an auxiliary service has not been started, check if it has the same endpoint, then start
for _, auxServices := range n.auxServices {
- if auxServices.Server().endpoint == n.http.endpoint {
+ if auxServices.Server().endpoint == n.http.endpoint { // TODO maybe also check that auxServices.Server().Server == nil? or is it unnecessary?
n.RegisterHTTP(n.http, auxServices.Server())
}
}
@@ -436,9 +436,7 @@ func (n *Node) startRPC() error {
n.stopInProc()
return err
}
-
n.http.Start()
- n.http.RPCAllowed = true
n.log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%v/", n.http.ListenerAddr),
"cors", strings.Join(n.http.CorsAllowedOrigins, ","),
"vhosts", strings.Join(n.http.Vhosts, ","))
From deb1a8ce73595e29c1c6bd159015cd990672794c Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Mon, 4 May 2020 17:47:47 +0200
Subject: [PATCH 020/160] allow ws to be enabled on same port as http from
console
---
node/api.go | 28 +++++++++++++++++---
node/node.go | 59 ++++++++++++++++++++++++++-----------------
node/rpcstack.go | 4 +--
node/rpcstack_test.go | 5 ++--
4 files changed, 65 insertions(+), 31 deletions(-)
diff --git a/node/api.go b/node/api.go
index b32984c2b4ef..437807f6dc53 100644
--- a/node/api.go
+++ b/node/api.go
@@ -224,8 +224,10 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
if api.node.ws.Server != nil {
return false, fmt.Errorf("WebSocket RPC already running on %v", api.node.ws.ListenerAddr)
+ } else if api.node.http.WSAllowed {
+ return false, fmt.Errorf("WebSocket RPC already running on %v", api.node.http.ListenerAddr)
}
-
+ // set host, port and endpoint
if host == nil {
h := DefaultWSHost
if api.node.config.WSHost != "" {
@@ -236,6 +238,15 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
if port == nil {
port = &api.node.config.WSPort
}
+ api.node.ws.host = *host
+ api.node.ws.port = *port
+ api.node.ws.endpoint = fmt.Sprintf("%s:%d", *host, *port)
+
+ if api.node.ws.endpoint == api.node.http.endpoint && api.node.http.Server != nil {
+ api.node.http.WSAllowed = true
+ api.node.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", api.node.http.ListenerAddr))
+ return true, nil
+ }
origins := api.node.config.WSOrigins
if allowedOrigins != nil {
@@ -244,6 +255,7 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
origins = append(origins, strings.TrimSpace(origin))
}
}
+ api.node.ws.WsOrigins = origins
modules := api.node.config.WSModules
if apis != nil {
@@ -252,10 +264,15 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
modules = append(modules, strings.TrimSpace(m))
}
}
+ api.node.ws.Whitelist = modules
- if err := api.node.startWS(fmt.Sprintf("%s:%d", *host, *port), modules, origins, api.node.config.WSExposeAll); err != nil {
+ api.node.ws.handler = api.node.ws.Srv.WebsocketHandler(api.node.ws.WsOrigins)
+ if err := api.node.CreateHTTPServer(api.node.ws, api.node.config.WSExposeAll); err != nil {
return false, err
}
+
+ api.node.ws.Start()
+ api.node.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", api.node.ws.ListenerAddr))
return true, nil
}
@@ -264,9 +281,14 @@ func (api *PrivateAdminAPI) StopWS() (bool, error) {
api.node.lock.Lock()
defer api.node.lock.Unlock()
- if api.node.ws == nil {
+ if api.node.ws.Server == nil && !api.node.http.WSAllowed {
return false, fmt.Errorf("WebSocket RPC not running")
}
+ if api.node.http.WSAllowed {
+ api.node.http.WSAllowed = false
+ return true, nil
+ }
+
api.node.stopWS()
return true, nil
}
diff --git a/node/node.go b/node/node.go
index fbac1a9fb0b2..155593b53c43 100644
--- a/node/node.go
+++ b/node/node.go
@@ -129,7 +129,6 @@ func New(conf *Config) (*Node, error) {
endpoint: conf.HTTPEndpoint(),
host: conf.HTTPHost,
port: conf.HTTPPort,
- RPCAllowed: true,
},
ws: &HTTPServer{
CorsAllowedOrigins: conf.WSOrigins,
@@ -138,11 +137,17 @@ func New(conf *Config) (*Node, error) {
endpoint: conf.WSEndpoint(),
host: conf.WSHost,
port: conf.WSPort,
- WSAllowed: true,
},
eventmux: new(event.TypeMux),
log: conf.Logger,
}
+ if conf.HTTPHost != "" {
+ node.http.RPCAllowed = true
+ }
+ if conf.WSHost != "" {
+ node.ws.WSAllowed = true
+ }
+
node.ServiceContext.EventMux = node.eventmux
node.ServiceContext.AccountManager = node.accman
return node, nil
@@ -251,15 +256,15 @@ func (n *Node) RegisterRPC(apis []rpc.API) {
func (n *Node) RegisterHTTP(dest *HTTPServer, toRegister *HTTPServer) {
// takes in default existing http server
// enables ____ on it
- if toRegister.WSAllowed {
- dest.handler = NewWebsocketUpgradeHandler(dest.handler, toRegister.handler)
- dest.WSAllowed = true
- log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", toRegister.endpoint))
- }
if toRegister.GQLAllowed {
dest.handler = NewGQLUpgradeHandler(dest.handler, toRegister.handler)
dest.GQLAllowed = true
log.Info("GraphQL endpoint opened", "url", fmt.Sprintf("http://%v", toRegister.endpoint))
+ return
+ }
+ dest.handler = dest.NewWebsocketUpgradeHandler(dest.handler, toRegister.handler)
+ if toRegister.WSAllowed {
+ log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%s", toRegister.endpoint))
}
}
@@ -414,15 +419,30 @@ func (n *Node) startRPC() error {
n.stopInProc()
return err
}
+ // create and start ws server if the endpoint exists
+ if n.ws.endpoint != "" && n.http.endpoint != n.ws.endpoint {
+ n.ws.handler = n.ws.Srv.WebsocketHandler(n.ws.CorsAllowedOrigins)
+ if err := n.CreateHTTPServer(n.ws, n.config.WSExposeAll); err != nil {
+ n.stopIPC()
+ n.stopInProc()
+ return err
+ }
+ n.ws.Start()
+ n.ws.WSAllowed = true
+ n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%s", n.ws.ListenerAddr))
+ }
// create and start http server if the endpoint exists // TODO CLEAN THIS UP!!!!!!!!!
if n.http.endpoint != "" {
- var exposeAll bool
// wrap handler in websocket handler only if websocket port is the same as http rpc
n.http.handler = NewHTTPHandlerStack(n.http.Srv, n.http.CorsAllowedOrigins, n.http.Vhosts)
- if n.http.endpoint == n.ws.endpoint {
+ // if websocket server is not already started, or is specified on the same endpoint as http,
+ // register websocket on the http server
+ if n.ws.Server == nil {
+ if n.http.endpoint == n.ws.endpoint {
+ n.http.WSAllowed = true
+ }
n.ws.handler = n.ws.Srv.WebsocketHandler(n.ws.CorsAllowedOrigins)
n.RegisterHTTP(n.http, n.ws)
- exposeAll = n.config.WSExposeAll
}
// if an auxiliary service has not been started, check if it has the same endpoint, then start
for _, auxServices := range n.auxServices {
@@ -430,6 +450,11 @@ func (n *Node) startRPC() error {
n.RegisterHTTP(n.http, auxServices.Server())
}
}
+ // only set exposeAll if websocket is enabled
+ var exposeAll bool
+ if n.http.WSAllowed {
+ exposeAll = n.config.WSExposeAll
+ }
// create the HTTP Server
if err := n.CreateHTTPServer(n.http, exposeAll); err != nil {
n.stopIPC()
@@ -441,18 +466,6 @@ func (n *Node) startRPC() error {
"cors", strings.Join(n.http.CorsAllowedOrigins, ","),
"vhosts", strings.Join(n.http.Vhosts, ","))
}
- // create and start ws server if the endpoint exists
- if n.ws.endpoint != "" && n.http.endpoint != n.ws.endpoint {
- n.ws.handler = n.ws.Srv.WebsocketHandler(n.ws.CorsAllowedOrigins)
- if err := n.CreateHTTPServer(n.ws, n.config.WSExposeAll); err != nil {
- n.stopIPC()
- n.stopInProc()
- return err
- }
- n.ws.Start()
- n.ws.WSAllowed = true
- n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%s", n.ws.ListenerAddr))
- }
// All API endpoints started successfully
return nil
}
@@ -523,7 +536,7 @@ func (n *Node) startHTTP(endpoint string, modules []string, cors []string, vhost
handler := NewHTTPHandlerStack(srv, cors, vhosts)
// wrap handler in websocket handler only if websocket port is the same as http rpc
if n.http.Endpoint() == n.ws.Endpoint() {
- handler = NewWebsocketUpgradeHandler(handler, srv.WebsocketHandler(wsOrigins))
+ handler = n.http.NewWebsocketUpgradeHandler(handler, srv.WebsocketHandler(wsOrigins))
}
httpServer, addr, err := StartHTTPEndpoint(endpoint, timeouts, handler)
if err != nil {
diff --git a/node/rpcstack.go b/node/rpcstack.go
index ec10d6335703..4d214d80e45d 100644
--- a/node/rpcstack.go
+++ b/node/rpcstack.go
@@ -205,9 +205,9 @@ func newGzipHandler(next http.Handler) http.Handler {
// NewWebsocketUpgradeHandler returns a websocket handler that serves an incoming request only if it contains an upgrade
// request to the websocket protocol. If not, serves the the request with the http handler.
-func NewWebsocketUpgradeHandler(h http.Handler, ws http.Handler) http.Handler {
+func (hs *HTTPServer) NewWebsocketUpgradeHandler(h http.Handler, ws http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- if isWebsocket(r) {
+ if hs.WSAllowed && isWebsocket(r) {
ws.ServeHTTP(w, r)
log.Debug("serving websocket request")
return
diff --git a/node/rpcstack_test.go b/node/rpcstack_test.go
index 9db03181c9a7..040e087dcbbc 100644
--- a/node/rpcstack_test.go
+++ b/node/rpcstack_test.go
@@ -10,9 +10,8 @@ import (
)
func TestNewWebsocketUpgradeHandler_websocket(t *testing.T) {
- srv := rpc.NewServer()
-
- handler := NewWebsocketUpgradeHandler(nil, srv.WebsocketHandler([]string{}))
+ h := &HTTPServer{Srv: rpc.NewServer()}
+ handler := h.NewWebsocketUpgradeHandler(nil, h.Srv.WebsocketHandler([]string{}))
ts := httptest.NewServer(handler)
defer ts.Close()
From 06a8de885f8ee229c7734fa3b6009e4a454cef31 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Thu, 7 May 2020 20:32:05 +0200
Subject: [PATCH 021/160] added todos
---
cmd/utils/flags.go | 4 ++--
ethstats/ethstats.go | 2 +-
node/node.go | 4 ++--
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index 9eac2beb7110..335878339387 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -1711,10 +1711,10 @@ func RegisterEthService(stack *node.Node, cfg *eth.Config) {
ls, _ := les.NewLesServer(fullNode, cfg)
fullNode.AddLesServer(ls)
}
- if err := stack.RegisterBackend(fullNode); err != nil {
+ if err := stack.RegisterBackend(fullNode); err != nil { // TODO this stuff should be handled by eth package (cause eth package only knows that it's a backend)
Fatalf("Failed to register the Ethereum service: %v", err)
}
- stack.RegisterLifecycle(fullNode)
+ stack.RegisterLifecycle(fullNode) // TODO this too (node should call this stuff so it register itself)
}
}
diff --git a/ethstats/ethstats.go b/ethstats/ethstats.go
index c9f6343da56f..b1598803b4aa 100644
--- a/ethstats/ethstats.go
+++ b/ethstats/ethstats.go
@@ -83,7 +83,7 @@ type Service struct {
}
// New returns a monitoring service ready for stats reporting.
-func New(node *node.Node, url string, backend node.Backend) (node.AuxiliaryService, error) {
+func New(node *node.Node, url string, backend node.Backend) (node.AuxiliaryService, error) { // TODO, this thing receives the backend explicitly, does whatever, registers itself
// Parse the netstats connection url
re := regexp.MustCompile("([^:@]*)(:([^@]*))?@(.+)")
parts := re.FindStringSubmatch(url)
diff --git a/node/node.go b/node/node.go
index 155593b53c43..622d1b88fce4 100644
--- a/node/node.go
+++ b/node/node.go
@@ -55,7 +55,7 @@ type Node struct {
lifecycles []Lifecycle // All registered backends, services, and auxiliary services that have a lifecycle
- backend Backend // The registered Backend of the node
+ backend Backend // The registered Backend of the node // TODO unnecessary
services map[reflect.Type]Service // Currently running services
auxServices map[reflect.Type]AuxiliaryService // Currently running auxiliary services
@@ -318,7 +318,7 @@ func (n *Node) Start() error {
// Initialize the p2p server. This creates the node key and
// discovery databases.
- n.server = &p2p.Server{Config: n.config.P2P}
+ n.server = &p2p.Server{Config: n.config.P2P} // TODO add init step for p2p server
n.server.Config.PrivateKey = n.config.NodeKey()
n.server.Config.Name = n.config.NodeName()
n.server.Config.Logger = n.log
From 4dd45c91c440d92273e6419a47f46b2578cdb640 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Tue, 12 May 2020 12:33:30 +0200
Subject: [PATCH 022/160] first steps implementing new design
---
cmd/faucet/faucet.go | 15 +---
cmd/geth/config.go | 7 +-
cmd/utils/flags.go | 67 +++++-------------
eth/backend.go | 32 ++++++---
ethstats/ethstats.go | 46 +++++-------
graphql/service.go | 20 ++++--
les/client.go | 28 ++++----
node/node.go | 132 +++++++----------------------------
node/service.go | 44 ------------
whisper/whisperv6/whisper.go | 9 ++-
10 files changed, 127 insertions(+), 273 deletions(-)
diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go
index db2505b51cd3..988c5dc0d094 100644
--- a/cmd/faucet/faucet.go
+++ b/cmd/faucet/faucet.go
@@ -241,24 +241,15 @@ func newFaucet(genesis *core.Genesis, port int, enodes []*discv5.Node, network u
cfg.SyncMode = downloader.LightSync
cfg.NetworkId = network
cfg.Genesis = genesis
- lesBackend, err := les.New(stack.ServiceContext, &cfg)
- // register the backend and lifecycle
- if err := stack.RegisterBackend(lesBackend); err != nil {
- return nil, err
+ if err := les.New(stack, &cfg); err != nil {
+ return nil, fmt.Errorf("Failed to register the Ethereum service: %w", err)
}
- stack.RegisterLifecycle(lesBackend)
// Assemble the ethstats monitoring and reporting service'
if stats != "" {
- var serv *les.LightEthereum
- ethstatsAuxService, err := ethstats.New(stack, stats, serv)
- if err != nil {
- return nil, err
- }
- if err := stack.RegisterAuxService(ethstatsAuxService); err != nil {
+ if err := ethstats.New(stack, stats); err != nil {
return nil, err
}
- stack.RegisterLifecycle(ethstatsAuxService)
}
// Boot up the client and ensure it connects to bootnodes
if err := stack.Start(); err != nil {
diff --git a/cmd/geth/config.go b/cmd/geth/config.go
index 01ca0a9cfbd9..766d3fb24a37 100644
--- a/cmd/geth/config.go
+++ b/cmd/geth/config.go
@@ -146,7 +146,7 @@ func enableWhisper(ctx *cli.Context) bool {
func makeFullNode(ctx *cli.Context) *node.Node {
stack, cfg := makeConfigNode(ctx)
- utils.RegisterEthService(stack, &cfg.Eth)
+ ethBackend, lesBackend := utils.RegisterEthService(stack, &cfg.Eth)
// Whisper must be explicitly enabled by specifying at least 1 whisper flag or in dev mode
shhEnabled := enableWhisper(ctx)
@@ -165,12 +165,13 @@ func makeFullNode(ctx *cli.Context) *node.Node {
}
// Configure GraphQL if requested
if ctx.GlobalIsSet(utils.GraphQLEnabledFlag.Name) {
- utils.RegisterGraphQLService(stack, cfg.Node.GraphQLEndpoint(), cfg.Node.GraphQLCors, cfg.Node.GraphQLVirtualHosts, cfg.Node.HTTPTimeouts)
+ utils.RegisterGraphQLService(stack, ethBackend, lesBackend, cfg.Node.GraphQLEndpoint(), cfg.Node.GraphQLCors, cfg.Node.GraphQLVirtualHosts, cfg.Node.HTTPTimeouts)
}
// Add the Ethereum Stats daemon if requested.
if cfg.Ethstats.URL != "" {
- utils.RegisterEthStatsService(stack, cfg.Ethstats.URL)
+ utils.RegisterEthStatsService(stack, ethBackend, lesBackend, cfg.Ethstats.URL)
}
+
return stack
}
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index 335878339387..3ec66962ba5e 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -20,7 +20,6 @@ package utils
import (
"crypto/ecdsa"
"fmt"
- "github.com/ethereum/go-ethereum/internal/ethapi"
"io"
"io/ioutil"
"math/big"
@@ -1692,76 +1691,42 @@ func setDNSDiscoveryDefaults(cfg *eth.Config, genesis common.Hash) {
}
// RegisterEthService adds an Ethereum client to the stack.
-func RegisterEthService(stack *node.Node, cfg *eth.Config) {
+func RegisterEthService(stack *node.Node, cfg *eth.Config) (*eth.Ethereum, *les.LightEthereum) {
if cfg.SyncMode == downloader.LightSync {
- lesBackend, err := les.New(stack.ServiceContext, cfg)
+ backend, err := les.New(stack, cfg)
if err != nil {
- Fatalf("Failed to register the Ethereum service: %v", err)
- }
- stack.RegisterLifecycle(lesBackend)
- if err := stack.RegisterBackend(lesBackend); err != nil {
- Fatalf("Failed to register the Ethereum service: %v", err)
+ Fatalf("Failed to register the Ethereum service: %w", err)
}
+ return nil, backend
} else {
- fullNode, err := eth.New(stack.ServiceContext, cfg)
+ backend, err := eth.New(stack, cfg)
if err != nil {
- Fatalf("Failed to register the Ethereum service: %v", err)
- }
- if fullNode != nil && cfg.LightServ > 0 {
- ls, _ := les.NewLesServer(fullNode, cfg)
- fullNode.AddLesServer(ls)
- }
- if err := stack.RegisterBackend(fullNode); err != nil { // TODO this stuff should be handled by eth package (cause eth package only knows that it's a backend)
- Fatalf("Failed to register the Ethereum service: %v", err)
+ Fatalf("Failed to register the Ethereum service: %w", err)
}
- stack.RegisterLifecycle(fullNode) // TODO this too (node should call this stuff so it register itself)
+
+ return backend, nil
}
}
// RegisterShhService configures Whisper and adds it to the given node.
func RegisterShhService(stack *node.Node, cfg *whisper.Config) {
- whisperService := whisper.New(cfg)
- if err := stack.RegisterService(whisperService); err != nil {
- Fatalf("Failed to register the Whisper service: %v", err)
+ if err := whisper.New(stack, cfg); err != nil {
+ Fatalf("Failed to register the Whisper service: %w", err)
}
- stack.RegisterLifecycle(whisperService)
}
// RegisterEthStatsService configures the Ethereum Stats daemon and adds it to
// the given node.
-func RegisterEthStatsService(stack *node.Node, url string) {
- ethstatsAuxService, err := ethstats.New(stack, url, stack.Backend())
- if err != nil {
- Fatalf("Failed to register the Ethereum Stats service: %v", err)
- }
- if err := stack.RegisterAuxService(ethstatsAuxService); err != nil {
- Fatalf("Failed to register the Ethereum Stats service: %v", err)
+func RegisterEthStatsService(stack *node.Node, ethBackend *eth.Ethereum, lesBackend *les.LightEthereum, url string) {
+ if err := ethstats.New(stack, ethBackend, lesBackend, url); err != nil {
+ Fatalf("Failed to register the Ethereum Stats service: %w", err)
}
- stack.RegisterLifecycle(ethstatsAuxService)
}
// RegisterGraphQLService is a utility function to construct a new service and register it against a node.
-func RegisterGraphQLService(stack *node.Node, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) {
- var backend ethapi.Backend
- switch stack.Backend() {
- case stack.Backend().(*eth.Ethereum):
- backend = stack.Backend().(*eth.Ethereum).APIBackend
- case stack.Backend().(*les.LightEthereum):
- backend = stack.Backend().(*les.LightEthereum).ApiBackend
- default:
- // Well, this should not have happened, bail out
- Fatalf("no Ethereum service")
- }
-
- graphqlAuxService, err := graphql.New(backend, endpoint, cors, vhosts, timeouts)
- if err != nil {
- Fatalf("Failed to register the GraphQL service: %v", err)
- }
- if err := stack.RegisterAuxService(graphqlAuxService); err != nil {
- Fatalf("Failed to register the GraphQL service: %v", err)
- }
- if graphqlAuxService.Server().Endpoint() != stack.Config().HTTPEndpoint() {
- stack.RegisterLifecycle(graphqlAuxService)
+func RegisterGraphQLService(stack *node.Node, ethBackend *eth.Ethereum, lesBackend *les.LightEthereum, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) {
+ if err := graphql.New(stack, ethBackend, lesBackend, endpoint, cors, vhosts, timeouts); err != nil {
+ Fatalf("Failed to register the GraphQL service: %w", err)
}
}
diff --git a/eth/backend.go b/eth/backend.go
index d0cf9f779878..7dbd9a95ad6c 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -20,6 +20,7 @@ package eth
import (
"errors"
"fmt"
+ "github.com/ethereum/go-ethereum/les"
"math/big"
"runtime"
"sync"
@@ -114,7 +115,7 @@ func (s *Ethereum) SetContractBackend(backend bind.ContractBackend) {
// New creates a new Ethereum object (including the
// initialisation of the common Ethereum object)
-func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
+func New(stack *node.Node, config *Config) (*Ethereum, error) {
// Ensure configuration values are compatible and sane
if config.SyncMode == downloader.LightSync {
return nil, errors.New("can't run eth.Ethereum in light sync mode, use les.LightEthereum")
@@ -138,7 +139,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
log.Info("Allocated trie memory caches", "clean", common.StorageSize(config.TrieCleanCache)*1024*1024, "dirty", common.StorageSize(config.TrieDirtyCache)*1024*1024)
// Assemble the Ethereum object
- chainDb, err := ctx.OpenDatabaseWithFreezer("chaindata", config.DatabaseCache, config.DatabaseHandles, config.DatabaseFreezer, "eth/db/chaindata/")
+ chainDb, err := stack.ServiceContext.OpenDatabaseWithFreezer("chaindata", config.DatabaseCache, config.DatabaseHandles, config.DatabaseFreezer, "eth/db/chaindata/")
if err != nil {
return nil, err
}
@@ -151,9 +152,9 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
eth := &Ethereum{
config: config,
chainDb: chainDb,
- eventMux: ctx.EventMux,
- accountManager: ctx.AccountManager,
- engine: CreateConsensusEngine(ctx, chainConfig, &config.Ethash, config.Miner.Notify, config.Miner.Noverify, chainDb),
+ eventMux: stack.ServiceContext.EventMux,
+ accountManager: stack.ServiceContext.AccountManager,
+ engine: CreateConsensusEngine(stack.ServiceContext, chainConfig, &config.Ethash, config.Miner.Notify, config.Miner.Noverify, chainDb),
closeBloomHandler: make(chan struct{}),
networkID: config.NetworkId,
gasPrice: config.Miner.GasPrice,
@@ -207,7 +208,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
eth.bloomIndexer.Start(eth.blockchain)
if config.TxPool.Journal != "" {
- config.TxPool.Journal = ctx.ResolvePath(config.TxPool.Journal)
+ config.TxPool.Journal = stack.ServiceContext.ResolvePath(config.TxPool.Journal)
}
eth.txPool = core.NewTxPool(config.TxPool, chainConfig, eth.blockchain)
@@ -223,19 +224,32 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
eth.miner = miner.New(eth, &config.Miner, chainConfig, eth.EventMux(), eth.engine, eth.isLocalBlock)
eth.miner.SetExtra(makeExtraData(config.Miner.ExtraData))
- eth.APIBackend = &EthAPIBackend{ctx.ExtRPCEnabled(), eth, nil}
+ eth.APIBackend = &EthAPIBackend{stack.ServiceContext.ExtRPCEnabled(), eth, nil}
gpoParams := config.GPO
if gpoParams.Default == nil {
gpoParams.Default = config.Miner.GasPrice
}
eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, gpoParams)
- eth.dialCandidates, err = eth.setupDiscovery(&ctx.Config.P2P)
+ eth.dialCandiates, err = eth.setupDiscovery(&stack.ServiceContext.Config.P2P)
if err != nil {
return nil, err
}
- return eth, nil
+ if config.LightServ > 0 {
+ ls, _ := les.NewLesServer(eth, config)
+ eth.AddLesServer(ls)
+ }
+
+ // Register the backend on the node
+ stack.RegisterAPIs(eth.APIs())
+ if err := stack.RegisterProtocols(eth.Protocols()); err != nil {
+ return nil, err
+ }
+ if err := stack.RegisterBackend(eth, nil); err != nil {
+ return nil, err
+ }
+ return eth, stack.RegisterLifecycle(eth)
}
func makeExtraData(extra []byte) []byte {
diff --git a/ethstats/ethstats.go b/ethstats/ethstats.go
index b1598803b4aa..f1328f5ed9a4 100644
--- a/ethstats/ethstats.go
+++ b/ethstats/ethstats.go
@@ -83,41 +83,31 @@ type Service struct {
}
// New returns a monitoring service ready for stats reporting.
-func New(node *node.Node, url string, backend node.Backend) (node.AuxiliaryService, error) { // TODO, this thing receives the backend explicitly, does whatever, registers itself
+func New(node *node.Node, ethBackend *eth.Ethereum, lesBackend *les.LightEthereum, url string) error { // TODO, this thing receives the backend explicitly, does whatever, registers itself
// Parse the netstats connection url
re := regexp.MustCompile("([^:@]*)(:([^@]*))?@(.+)")
parts := re.FindStringSubmatch(url)
if len(parts) != 5 {
- return nil, fmt.Errorf("invalid netstats url: \"%s\", should be nodename:secret@host:port", url)
+ return fmt.Errorf("invalid netstats url: \"%s\", should be nodename:secret@host:port", url)
}
// fetch type of Backend
- if ethBackend, ok := backend.(*eth.Ethereum); ok {
- return &Service{
- server: node.Server(),
- eth: ethBackend,
- les: nil, // TODO is this okay?
- engine: ethBackend.Engine(),
- node: parts[1],
- pass: parts[3],
- host: parts[4],
- pongCh: make(chan struct{}),
- histCh: make(chan []uint64, 1),
- }, nil
- } else if lesBackend, ok := backend.(*les.LightEthereum); ok {
- return &Service{
- server: node.Server(),
- eth: nil, // TODO is this okay?
- les: lesBackend,
- engine: lesBackend.Engine(),
- node: parts[1],
- pass: parts[3],
- host: parts[4],
- pongCh: make(chan struct{}),
- histCh: make(chan []uint64, 1),
- }, nil
- }
- return nil, errors.New("no Ethereum service") // TODO is this okay to return?
+ if ethBackend == nil && lesBackend == nil {
+ return errors.New("no Ethereum service") // TODO is this okay to return?
+ }
+ ethstats := &Service{
+ server: node.Server(),
+ eth: ethBackend,
+ les: lesBackend,
+ engine: ethBackend.Engine(),
+ node: parts[1],
+ pass: parts[3],
+ host: parts[4],
+ pongCh: make(chan struct{}),
+ histCh: make(chan []uint64, 1),
+ }
+
+ return node.RegisterLifecycle(ethstats)
}
// Start implements node.Service, starting up the monitoring and reporting daemon.
diff --git a/graphql/service.go b/graphql/service.go
index 523a6b4eff68..68e41fde4689 100644
--- a/graphql/service.go
+++ b/graphql/service.go
@@ -18,7 +18,10 @@ package graphql
import (
"context"
+ "errors"
"fmt"
+ "github.com/ethereum/go-ethereum/eth"
+ "github.com/ethereum/go-ethereum/les"
"net"
"net/http"
@@ -37,9 +40,8 @@ type Service struct {
}
// New constructs a new GraphQL service instance.
-func New(backend ethapi.Backend, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) (*Service, error) {
+func New(stack *node.Node, ethBackend *eth.Ethereum, lesBackend *les.LightEthereum, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) error {
service := &Service{
- backend: backend,
graphqlServer: &node.HTTPServer{
Timeouts: timeouts,
Vhosts: vhosts,
@@ -47,15 +49,25 @@ func New(backend ethapi.Backend, endpoint string, cors, vhosts []string, timeout
GQLAllowed: true,
},
}
+ // add backend
+ if ethBackend != nil {
+ service.backend = ethBackend.APIBackend
+ } else if lesBackend != nil {
+ service.backend = lesBackend.ApiBackend
+ } else {
+ return errors.New("no Ethereum service")
+ }
+
service.graphqlServer.SetEndpoint(endpoint)
// create handler
handler, err := service.CreateHandler()
if err != nil {
- return nil, err
+ return err
}
service.graphqlServer.SetHandler(handler)
- return service, nil
+ // TODO register http
+ return stack.RegisterLifecycle(service)
}
func (s *Service) CreateHandler() (http.Handler, error) {
diff --git a/les/client.go b/les/client.go
index ae81c79db430..3e587ad0adce 100644
--- a/les/client.go
+++ b/les/client.go
@@ -77,12 +77,12 @@ type LightEthereum struct {
p2pServer *p2p.Server
}
-func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
- chainDb, err := ctx.OpenDatabase("lightchaindata", config.DatabaseCache, config.DatabaseHandles, "eth/db/chaindata/")
+func New(stack *node.Node, config *eth.Config) (*LightEthereum, error) {
+ chainDb, err := stack.ServiceContext.OpenDatabase("lightchaindata", config.DatabaseCache, config.DatabaseHandles, "eth/db/chaindata/")
if err != nil {
return nil, err
}
- lespayDb, err := ctx.OpenDatabase("lespay", 0, 0, "eth/db/lespay")
+ lespayDb, err := stack.ServiceContext.OpenDatabase("lespay", 0, 0, "eth/db/lespay")
if err != nil {
return nil, err
}
@@ -103,10 +103,10 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
closeCh: make(chan struct{}),
},
peers: peers,
- eventMux: ctx.EventMux,
+ eventMux: stack.ServiceContext.EventMux,
reqDist: newRequestDistributor(peers, &mclock.System{}),
- accountManager: ctx.AccountManager,
- engine: eth.CreateConsensusEngine(ctx, chainConfig, &config.Ethash, nil, false, chainDb),
+ accountManager: stack.ServiceContext.AccountManager,
+ engine: eth.CreateConsensusEngine(stack.ServiceContext, chainConfig, &config.Ethash, nil, false, chainDb),
bloomRequests: make(chan chan *bloombits.Retrieval),
bloomIndexer: eth.NewBloomIndexer(chainDb, params.BloomBitsBlocksClient, params.HelperTrieConfirmations),
valueTracker: lpc.NewValueTracker(lespayDb, &mclock.System{}, requestList, time.Minute, 1/float64(time.Hour), 1/float64(time.Hour*100), 1/float64(time.Hour*1000)),
@@ -163,19 +163,23 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
rawdb.WriteChainConfig(chainDb, genesisHash, chainConfig)
}
- leth.ApiBackend = &LesApiBackend{ctx.ExtRPCEnabled(), leth, nil}
+ leth.ApiBackend = &LesApiBackend{stack.ServiceContext.ExtRPCEnabled(), leth, nil}
gpoParams := config.GPO
if gpoParams.Default == nil {
gpoParams.Default = config.Miner.GasPrice
}
leth.ApiBackend.gpo = gasprice.NewOracle(leth.ApiBackend, gpoParams)
- leth.handler = newClientHandler(config.UltraLightServers, config.UltraLightFraction, checkpoint, leth)
- if leth.handler.ulc != nil {
- log.Warn("Ultra light client is enabled", "trustedNodes", len(leth.handler.ulc.keys), "minTrustedFraction", leth.handler.ulc.fraction)
- leth.blockchain.DisableCheckFreq()
+
+ // Register the backend on the node
+ stack.RegisterAPIs(leth.APIs())
+ if err := stack.RegisterProtocols(leth.Protocols()); err != nil {
+ return nil, err
+ }
+ if err := stack.RegisterBackend(nil, leth); err != nil {
+ return nil, err
}
- return leth, nil
+ return leth, stack.RegisterLifecycle(leth)
}
// vtSubscription implements serverPeerSubscriber
diff --git a/node/node.go b/node/node.go
index 622d1b88fce4..2ce3d547db16 100644
--- a/node/node.go
+++ b/node/node.go
@@ -20,6 +20,8 @@ import (
"context"
"errors"
"fmt"
+ "github.com/ethereum/go-ethereum/eth"
+ "github.com/ethereum/go-ethereum/les"
"net"
"net/http"
"os"
@@ -55,10 +57,6 @@ type Node struct {
lifecycles []Lifecycle // All registered backends, services, and auxiliary services that have a lifecycle
- backend Backend // The registered Backend of the node // TODO unnecessary
- services map[reflect.Type]Service // Currently running services
- auxServices map[reflect.Type]AuxiliaryService // Currently running auxiliary services
-
rpcAPIs []rpc.API // List of APIs currently provided by the node
inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
@@ -66,7 +64,6 @@ type Node struct {
http *HTTPServer // TODO
ws *HTTPServer // TODO
-
stop chan struct{} // Channel to wait for termination notifications
lock sync.RWMutex
@@ -115,8 +112,6 @@ func New(conf *Config) (*Node, error) {
ServiceContext: &ServiceContext{
Config: *conf,
},
- services: make(map[reflect.Type]Service),
- auxServices: make(map[reflect.Type]AuxiliaryService),
ipc: &HTTPServer{
endpoint: conf.IPCEndpoint(),
},
@@ -177,60 +172,14 @@ func (n *Node) Close() error {
}
// TODO document
-func (n *Node) RegisterLifecycle(lifecycle Lifecycle) {
- n.lifecycles = append(n.lifecycles, lifecycle)
-}
-
-// TODO document
-func (n *Node) RegisterBackend(backend Backend) error {
- n.lock.Lock()
- defer n.lock.Unlock()
- // check if p2p node is already running
- if n.running() {
- return ErrNodeRunning
- }
- // check that there is not already a backend registered on the node
- if n.backend != nil {
- return errors.New("a backend has already been registered on the node") // TODO is this error okay?
- }
- n.backend = backend
- return nil
-}
-
-// Register injects a new service into the node's stack. The service created by
-// the passed constructor must be unique in its type with regard to sibling ones.
-func (n *Node) RegisterService(service Service) error {
- n.lock.Lock()
- defer n.lock.Unlock()
-
- if n.running() {
- return ErrNodeRunning
- }
-
- kind := reflect.TypeOf(service)
- if _, exists := n.services[kind]; exists {
- return &DuplicateServiceError{Kind: kind}
- }
- n.services[kind] = service
-
- return nil
-}
-
-// TODO document
-func (n *Node) RegisterAuxService(auxService AuxiliaryService) error {
- n.lock.Lock()
- defer n.lock.Unlock()
-
- if n.running() {
- return ErrNodeRunning
- }
- // make sure auxiliary service is not duplicated
- kind := reflect.TypeOf(auxService)
- if _, exists := n.auxServices[kind]; exists {
- return &DuplicateServiceError{Kind: kind}
+func (n *Node) RegisterLifecycle(lifecycle Lifecycle) error {
+ for _, existing := range n.lifecycles { // TODO is checking for duplicates a good idea?
+ if existing == lifecycle {
+ return errors.New("Lifecycle already registered")
+ }
}
- n.auxServices[kind] = auxService
+ n.lifecycles = append(n.lifecycles, lifecycle)
return nil
}
@@ -238,18 +187,17 @@ func (n *Node) RegisterProtocols(protocols []p2p.Protocol) error {
if !n.running() {
return ErrNodeStopped
}
- // add backend's protocols to the o2o server
+ // TODO check for duplicates?
+
+ // add backend's protocols to the p2p server
n.server.Protocols = append(n.server.Protocols, protocols...)
return nil
}
-func (n *Node) RegisterRPC(apis []rpc.API) {
- // Gather all the possible APIs to surface
- apis = append(apis, n.backend.APIs()...)
- for _, service := range n.services {
- apis = append(apis, service.APIs()...)
- }
- n.rpcAPIs = apis
+func (n *Node) RegisterAPIs(apis []rpc.API) {
+ // TODO check for duplicates?
+
+ n.rpcAPIs = append(n.rpcAPIs, apis...)
}
// TODO document
@@ -364,11 +312,8 @@ func (n *Node) Start() error {
return err
}
// Finish initializing the service context
- n.ServiceContext.backend = n.backend
n.ServiceContext.AccountManager = n.accman
n.ServiceContext.EventMux = n.eventmux
- n.ServiceContext.services = n.services
- n.ServiceContext.auxServices = n.auxServices
// Finish initializing the startup
n.stop = make(chan struct{})
@@ -714,8 +659,15 @@ func (n *Node) RPCHandler() (*rpc.Server, error) {
return n.inprocHandler, nil
}
-func (n *Node) Backend() Backend {
- return n.backend
+func (n *Node) Backend() (*eth.Ethereum, *les.LightEthereum) {
+ if n.ethBackend != nil && n.lesBackend == nil {
+ return n.ethBackend, nil
+ }
+ if n.ethBackend == nil && n.lesBackend != nil {
+ return nil, n.lesBackend
+ }
+
+ return nil, nil
}
// Server retrieves the currently running P2P network layer. This method is meant
@@ -728,42 +680,6 @@ func (n *Node) Server() *p2p.Server {
return n.server
}
-// Service retrieves a currently running service registered of a specific type.
-func (n *Node) Service(service interface{}) error {
- n.lock.RLock()
- defer n.lock.RUnlock()
-
- // Short circuit if the node's not running
- if n.server == nil {
- return ErrNodeStopped
- }
- // Otherwise try to find the service to return
- element := reflect.ValueOf(service).Elem()
- if running, ok := n.services[element.Type()]; ok {
- element.Set(reflect.ValueOf(running))
- return nil
- }
- return ErrServiceUnknown
-}
-
-// Service retrieves a currently running service registered of a specific type.
-func (n *Node) AuxService(auxService interface{}) error {
- n.lock.RLock()
- defer n.lock.RUnlock()
-
- // Short circuit if the node's not running
- if n.server == nil {
- return ErrNodeStopped
- }
- // Otherwise try to find the service to return
- element := reflect.ValueOf(auxService).Elem()
- if running, ok := n.auxServices[element.Type()]; ok {
- element.Set(reflect.ValueOf(running))
- return nil
- }
- return ErrServiceUnknown
-}
-
// DataDir retrieves the current datadir used by the protocol stack.
// Deprecated: No files should be stored in this directory, use InstanceDir instead.
func (n *Node) DataDir() string {
diff --git a/node/service.go b/node/service.go
index 00ff552d76ba..80971d7c5301 100644
--- a/node/service.go
+++ b/node/service.go
@@ -24,17 +24,12 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
- "github.com/ethereum/go-ethereum/p2p"
- "github.com/ethereum/go-ethereum/rpc"
)
// ServiceContext is a collection of service independent options inherited from
// the protocol stack, that is passed to all constructors to be optionally used;
// as well as utility methods to operate on the service environment.
type ServiceContext struct {
- backend Backend // Copy of the already constructed Backend // TODO update this comment
- services map[reflect.Type]Service // Index of the already constructed services
- auxServices map[reflect.Type]AuxiliaryService // Index of the already constructed auxiliary services
Config Config
EventMux *event.TypeMux // Event multiplexer used for decoupled notifications
AccountManager *accounts.Manager // Account manager created by the node.
@@ -93,45 +88,6 @@ func (ctx *ServiceContext) ExtRPCEnabled() bool {
return ctx.Config.ExtRPCEnabled()
}
-// TODO document
-type Backend interface {
- // Protocols retrieves the P2P protocols the service wishes to start.
- Protocols() []p2p.Protocol
-
- // Backend can register a P2P Server
- P2PServer(server *p2p.Server) error
-
- // Backend also implements the Service interface.
- Service
-}
-
-// Service is an individual protocol that can be registered into a node.
-//
-// Notes:
-//
-// • Service life-cycle management is delegated to the node. The service is allowed to
-// initialize itself upon creation, but no goroutines should be spun up outside of the
-// Start method.
-//
-// • Restart logic is not required as the node will create a fresh instance
-// every time a service is started.
-type Service interface {
- // APIs retrieves the list of RPC descriptors the service provides
- APIs() []rpc.API
-
- // Service also implements Lifecycle
- Lifecycle
-}
-
-// TODO document
-type AuxiliaryService interface {
- // TODO document
- Server() *HTTPServer
-
- // AuxiliaryService also implements Lifecycle
- Lifecycle
-}
-
// TODO document
type Lifecycle interface {
// Start is called after all services have been constructed and the networking
diff --git a/whisper/whisperv6/whisper.go b/whisper/whisperv6/whisper.go
index 053c22b3cb7d..6d2c9cf154fe 100644
--- a/whisper/whisperv6/whisper.go
+++ b/whisper/whisperv6/whisper.go
@@ -21,6 +21,7 @@ import (
"crypto/ecdsa"
"crypto/sha256"
"fmt"
+ "github.com/ethereum/go-ethereum/node"
"math"
"runtime"
"sync"
@@ -93,7 +94,7 @@ type Whisper struct {
}
// New creates a Whisper client ready to communicate through the Ethereum P2P network.
-func New(cfg *Config) *Whisper {
+func New(stack *node.Node, cfg *Config) error {
if cfg == nil {
cfg = &DefaultConfig
}
@@ -132,7 +133,11 @@ func New(cfg *Config) *Whisper {
},
}
- return whisper
+ stack.RegisterAPIs(whisper.APIs())
+ if err := stack.RegisterProtocols(whisper.Protocols()); err != nil {
+ return err
+ }
+ return stack.RegisterLifecycle(whisper)
}
// MinPow returns the PoW value required by this node.
From c4f1d637ce64501e53de4065d9dd2506c2d78e3f Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Tue, 12 May 2020 18:38:55 +0200
Subject: [PATCH 023/160] functional geth
---
cmd/faucet/faucet.go | 5 ++-
cmd/geth/chaincmd.go | 14 +++---
cmd/geth/config.go | 5 ++-
cmd/geth/consolecmd.go | 8 ++--
cmd/geth/main.go | 27 +++++------
cmd/utils/flags.go | 5 ++-
eth/backend.go | 11 +----
les/client.go | 4 +-
node/node.go | 100 ++++++++++++++---------------------------
node/service.go | 19 ++++----
p2p/server.go | 4 ++
11 files changed, 81 insertions(+), 121 deletions(-)
diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go
index 988c5dc0d094..7f66eae87fe7 100644
--- a/cmd/faucet/faucet.go
+++ b/cmd/faucet/faucet.go
@@ -241,13 +241,14 @@ func newFaucet(genesis *core.Genesis, port int, enodes []*discv5.Node, network u
cfg.SyncMode = downloader.LightSync
cfg.NetworkId = network
cfg.Genesis = genesis
- if err := les.New(stack, &cfg); err != nil {
+ lesBackend, err := les.New(stack, &cfg)
+ if err != nil {
return nil, fmt.Errorf("Failed to register the Ethereum service: %w", err)
}
// Assemble the ethstats monitoring and reporting service'
if stats != "" {
- if err := ethstats.New(stack, stats); err != nil {
+ if err := ethstats.New(stack, nil, lesBackend, stats); err != nil {
return nil, err
}
}
diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go
index 247c202bca17..07485306492e 100644
--- a/cmd/geth/chaincmd.go
+++ b/cmd/geth/chaincmd.go
@@ -240,7 +240,7 @@ func initGenesis(ctx *cli.Context) error {
utils.Fatalf("invalid genesis file: %v", err)
}
// Open an initialise both full and light databases
- stack := makeFullNode(ctx)
+ stack, _, _ := makeFullNode(ctx)
defer stack.Close()
for _, name := range []string{"chaindata", "lightchaindata"} {
@@ -277,7 +277,7 @@ func importChain(ctx *cli.Context) error {
utils.SetupMetrics(ctx)
// Start system runtime metrics collection
go metrics.CollectProcessMetrics(3 * time.Second)
- stack := makeFullNode(ctx)
+ stack, _, _ := makeFullNode(ctx)
defer stack.Close()
chain, db := utils.MakeChain(ctx, stack, false)
@@ -371,7 +371,7 @@ func exportChain(ctx *cli.Context) error {
if len(ctx.Args()) < 1 {
utils.Fatalf("This command requires an argument.")
}
- stack := makeFullNode(ctx)
+ stack, _, _ := makeFullNode(ctx)
defer stack.Close()
chain, _ := utils.MakeChain(ctx, stack, true)
@@ -406,7 +406,7 @@ func importPreimages(ctx *cli.Context) error {
if len(ctx.Args()) < 1 {
utils.Fatalf("This command requires an argument.")
}
- stack := makeFullNode(ctx)
+ stack, _, _ := makeFullNode(ctx)
defer stack.Close()
db := utils.MakeChainDatabase(ctx, stack)
@@ -424,7 +424,7 @@ func exportPreimages(ctx *cli.Context) error {
if len(ctx.Args()) < 1 {
utils.Fatalf("This command requires an argument.")
}
- stack := makeFullNode(ctx)
+ stack, _, _ := makeFullNode(ctx)
defer stack.Close()
db := utils.MakeChainDatabase(ctx, stack)
@@ -446,7 +446,7 @@ func copyDb(ctx *cli.Context) error {
utils.Fatalf("Source ancient chain directory path argument missing")
}
// Initialize a new chain for the running node to sync into
- stack := makeFullNode(ctx)
+ stack, _, _ := makeFullNode(ctx)
defer stack.Close()
chain, chainDb := utils.MakeChain(ctx, stack, false)
@@ -554,7 +554,7 @@ func confirmAndRemoveDB(database string, kind string) {
}
func dump(ctx *cli.Context) error {
- stack := makeFullNode(ctx)
+ stack, _, _ := makeFullNode(ctx)
defer stack.Close()
chain, chainDb := utils.MakeChain(ctx, stack, true)
diff --git a/cmd/geth/config.go b/cmd/geth/config.go
index 766d3fb24a37..df452b8b4fd8 100644
--- a/cmd/geth/config.go
+++ b/cmd/geth/config.go
@@ -20,6 +20,7 @@ import (
"bufio"
"errors"
"fmt"
+ "github.com/ethereum/go-ethereum/les"
"os"
"reflect"
"unicode"
@@ -144,7 +145,7 @@ func enableWhisper(ctx *cli.Context) bool {
return false
}
-func makeFullNode(ctx *cli.Context) *node.Node {
+func makeFullNode(ctx *cli.Context) (*node.Node, *eth.Ethereum, *les.LightEthereum) {
stack, cfg := makeConfigNode(ctx)
ethBackend, lesBackend := utils.RegisterEthService(stack, &cfg.Eth)
@@ -172,7 +173,7 @@ func makeFullNode(ctx *cli.Context) *node.Node {
utils.RegisterEthStatsService(stack, ethBackend, lesBackend, cfg.Ethstats.URL)
}
- return stack
+ return stack, ethBackend, lesBackend
}
// dumpConfig is the dumpconfig command.
diff --git a/cmd/geth/consolecmd.go b/cmd/geth/consolecmd.go
index 2a304636eb62..226a2537bac4 100644
--- a/cmd/geth/consolecmd.go
+++ b/cmd/geth/consolecmd.go
@@ -78,8 +78,8 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/JavaScript-Cons
func localConsole(ctx *cli.Context) error {
// Create and start the node based on the CLI flags
prepare(ctx)
- node := makeFullNode(ctx)
- startNode(ctx, node)
+ node, ethBackend, lesBackend := makeFullNode(ctx)
+ startNode(ctx, node, ethBackend, lesBackend)
defer node.Close()
// Attach to the newly started node and start the JavaScript console
@@ -190,8 +190,8 @@ func dialRPC(endpoint string) (*rpc.Client, error) {
// everything down.
func ephemeralConsole(ctx *cli.Context) error {
// Create and start the node based on the CLI flags
- node := makeFullNode(ctx)
- startNode(ctx, node)
+ node, ethBackend, lesBackend := makeFullNode(ctx)
+ startNode(ctx, node, ethBackend, lesBackend)
defer node.Close()
// Attach to the newly started node and start the JavaScript console
diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index bb39c512cf49..5f71eb5324ca 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -351,9 +351,9 @@ func geth(ctx *cli.Context) error {
return fmt.Errorf("invalid command: %q", args[0])
}
prepare(ctx)
- node := makeFullNode(ctx)
+ node, ethBackend, lesBackend := makeFullNode(ctx)
defer node.Close()
- startNode(ctx, node)
+ startNode(ctx, node, ethBackend, lesBackend)
node.Wait()
return nil
@@ -362,7 +362,7 @@ func geth(ctx *cli.Context) error {
// startNode boots up the system node and all registered protocols, after which
// it unlocks any requested accounts, and starts the RPC/IPC interfaces and the
// miner.
-func startNode(ctx *cli.Context, stack *node.Node) {
+func startNode(ctx *cli.Context, stack *node.Node, ethBackend *eth.Ethereum, lesBackend *les.LightEthereum) {
debug.Memsize.Add("node", stack)
// Start up the node itself
@@ -385,20 +385,18 @@ func startNode(ctx *cli.Context, stack *node.Node) {
// Set contract backend for ethereum service if local node
// is serving LES requests.
if ctx.GlobalInt(utils.LegacyLightServFlag.Name) > 0 || ctx.GlobalInt(utils.LightServeFlag.Name) > 0 {
- var ethService *eth.Ethereum
- if err := stack.Service(ðService); err != nil {
+ if ethBackend == nil {
utils.Fatalf("Failed to retrieve ethereum service: %v", err)
}
- ethService.SetContractBackend(ethClient)
+ ethBackend.SetContractBackend(ethClient)
}
// Set contract backend for les service if local node is
// running as a light client.
if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" {
- var lesService *les.LightEthereum
- if err := stack.Service(&lesService); err != nil {
+ if lesBackend == nil {
utils.Fatalf("Failed to retrieve light ethereum service: %v", err)
}
- lesService.SetContractBackend(ethClient)
+ lesBackend.SetContractBackend(ethClient)
}
go func() {
@@ -465,11 +463,7 @@ func startNode(ctx *cli.Context, stack *node.Node) {
utils.Fatalf("Light clients do not support mining")
}
// Check if node's backend is eth and that it exists // TODO fix this section up -- not sure if it's doing what it's supposed to.
- ethereum, ok := stack.Backend().(*eth.Ethereum)
- if !ok {
- if stack.Backend() == nil {
- utils.Fatalf("Ethereum service not running: backend is nil")
- }
+ if ethBackend == nil {
utils.Fatalf("Ethereum service not running: backend is not an eth backend")
}
// Set the gas price to the limits from the CLI and start mining
@@ -477,15 +471,14 @@ func startNode(ctx *cli.Context, stack *node.Node) {
if ctx.GlobalIsSet(utils.LegacyMinerGasPriceFlag.Name) && !ctx.GlobalIsSet(utils.MinerGasPriceFlag.Name) {
gasprice = utils.GlobalBig(ctx, utils.LegacyMinerGasPriceFlag.Name)
}
- ethereum.TxPool().SetGasPrice(gasprice)
+ ethBackend.TxPool().SetGasPrice(gasprice)
threads := ctx.GlobalInt(utils.MinerThreadsFlag.Name)
if ctx.GlobalIsSet(utils.LegacyMinerThreadsFlag.Name) && !ctx.GlobalIsSet(utils.MinerThreadsFlag.Name) {
threads = ctx.GlobalInt(utils.LegacyMinerThreadsFlag.Name)
log.Warn("The flag --minerthreads is deprecated and will be removed in the future, please use --miner.threads")
}
-
- if err := ethereum.StartMining(threads); err != nil {
+ if err := ethBackend.StartMining(threads); err != nil {
utils.Fatalf("Failed to start mining: %v", err)
}
}
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index 3ec66962ba5e..25faf1b91ec2 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -1703,7 +1703,10 @@ func RegisterEthService(stack *node.Node, cfg *eth.Config) (*eth.Ethereum, *les.
if err != nil {
Fatalf("Failed to register the Ethereum service: %w", err)
}
-
+ if cfg.LightServ > 0 {
+ ls, _ := les.NewLesServer(backend, cfg)
+ backend.AddLesServer(ls)
+ }
return backend, nil
}
}
diff --git a/eth/backend.go b/eth/backend.go
index 7dbd9a95ad6c..361758cc435d 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -20,7 +20,6 @@ package eth
import (
"errors"
"fmt"
- "github.com/ethereum/go-ethereum/les"
"math/big"
"runtime"
"sync"
@@ -161,6 +160,7 @@ func New(stack *node.Node, config *Config) (*Ethereum, error) {
etherbase: config.Miner.Etherbase,
bloomRequests: make(chan chan *bloombits.Retrieval),
bloomIndexer: NewBloomIndexer(chainDb, params.BloomBitsBlocks, params.BloomConfirms),
+ p2pServer: stack.Server(),
}
bcVersion := rawdb.ReadDatabaseVersion(chainDb)
@@ -221,6 +221,7 @@ func New(stack *node.Node, config *Config) (*Ethereum, error) {
if eth.protocolManager, err = NewProtocolManager(chainConfig, checkpoint, config.SyncMode, config.NetworkId, eth.eventMux, eth.txPool, eth.engine, eth.blockchain, chainDb, cacheLimit, config.Whitelist); err != nil {
return nil, err
}
+
eth.miner = miner.New(eth, &config.Miner, chainConfig, eth.EventMux(), eth.engine, eth.isLocalBlock)
eth.miner.SetExtra(makeExtraData(config.Miner.ExtraData))
@@ -236,19 +237,11 @@ func New(stack *node.Node, config *Config) (*Ethereum, error) {
return nil, err
}
- if config.LightServ > 0 {
- ls, _ := les.NewLesServer(eth, config)
- eth.AddLesServer(ls)
- }
-
// Register the backend on the node
stack.RegisterAPIs(eth.APIs())
if err := stack.RegisterProtocols(eth.Protocols()); err != nil {
return nil, err
}
- if err := stack.RegisterBackend(eth, nil); err != nil {
- return nil, err
- }
return eth, stack.RegisterLifecycle(eth)
}
diff --git a/les/client.go b/les/client.go
index 3e587ad0adce..c8b7b39b5d00 100644
--- a/les/client.go
+++ b/les/client.go
@@ -110,6 +110,7 @@ func New(stack *node.Node, config *eth.Config) (*LightEthereum, error) {
bloomRequests: make(chan chan *bloombits.Retrieval),
bloomIndexer: eth.NewBloomIndexer(chainDb, params.BloomBitsBlocksClient, params.HelperTrieConfirmations),
valueTracker: lpc.NewValueTracker(lespayDb, &mclock.System{}, requestList, time.Minute, 1/float64(time.Hour), 1/float64(time.Hour*100), 1/float64(time.Hour*1000)),
+ p2pServer: stack.Server(),
}
peers.subscribe((*vtSubscription)(leth.valueTracker))
@@ -176,9 +177,6 @@ func New(stack *node.Node, config *eth.Config) (*LightEthereum, error) {
if err := stack.RegisterProtocols(leth.Protocols()); err != nil {
return nil, err
}
- if err := stack.RegisterBackend(nil, leth); err != nil {
- return nil, err
- }
return leth, stack.RegisterLifecycle(leth)
}
diff --git a/node/node.go b/node/node.go
index 2ce3d547db16..2d56fceb7653 100644
--- a/node/node.go
+++ b/node/node.go
@@ -20,8 +20,6 @@ import (
"context"
"errors"
"fmt"
- "github.com/ethereum/go-ethereum/eth"
- "github.com/ethereum/go-ethereum/les"
"net"
"net/http"
"os"
@@ -117,21 +115,21 @@ func New(conf *Config) (*Node, error) {
},
http: &HTTPServer{
CorsAllowedOrigins: conf.HTTPCors,
- Vhosts: conf.HTTPVirtualHosts,
- Whitelist: conf.HTTPModules,
- Timeouts: conf.HTTPTimeouts,
- Srv: rpc.NewServer(),
- endpoint: conf.HTTPEndpoint(),
- host: conf.HTTPHost,
- port: conf.HTTPPort,
+ Vhosts: conf.HTTPVirtualHosts,
+ Whitelist: conf.HTTPModules,
+ Timeouts: conf.HTTPTimeouts,
+ Srv: rpc.NewServer(),
+ endpoint: conf.HTTPEndpoint(),
+ host: conf.HTTPHost,
+ port: conf.HTTPPort,
},
ws: &HTTPServer{
CorsAllowedOrigins: conf.WSOrigins,
- Whitelist: conf.WSModules,
- Srv: rpc.NewServer(),
- endpoint: conf.WSEndpoint(),
- host: conf.WSHost,
- port: conf.WSPort,
+ Whitelist: conf.WSModules,
+ Srv: rpc.NewServer(),
+ endpoint: conf.WSEndpoint(),
+ host: conf.WSHost,
+ port: conf.WSPort,
},
eventmux: new(event.TypeMux),
log: conf.Logger,
@@ -143,6 +141,22 @@ func New(conf *Config) (*Node, error) {
node.ws.WSAllowed = true
}
+ // Initialize the p2p server. This creates the node key and
+ // discovery databases.
+ node.server = &p2p.Server{Config: conf.P2P} // TODO add init step for p2p server
+ node.server.Config.PrivateKey = node.config.NodeKey()
+ node.server.Config.Name = node.config.NodeName()
+ node.server.Config.Logger = node.log
+ if node.server.Config.StaticNodes == nil {
+ node.server.Config.StaticNodes = node.config.StaticNodes()
+ }
+ if node.server.Config.TrustedNodes == nil {
+ node.server.Config.TrustedNodes = node.config.TrustedNodes()
+ }
+ if node.server.Config.NodeDatabase == "" {
+ node.server.Config.NodeDatabase = node.config.NodeDB()
+ }
+
node.ServiceContext.EventMux = node.eventmux
node.ServiceContext.AccountManager = node.accman
return node, nil
@@ -184,9 +198,6 @@ func (n *Node) RegisterLifecycle(lifecycle Lifecycle) error {
}
func (n *Node) RegisterProtocols(protocols []p2p.Protocol) error {
- if !n.running() {
- return ErrNodeStopped
- }
// TODO check for duplicates?
// add backend's protocols to the p2p server
@@ -248,7 +259,7 @@ func (n *Node) CreateHTTPServer(h *HTTPServer, exposeAll bool) error {
// running returns true if the node's p2p server is already running
func (n *Node) running() bool {
- return n.server != nil
+ return n.server.Listening()
}
// Start creates a live P2P node and starts running it.
@@ -264,38 +275,14 @@ func (n *Node) Start() error {
return err
}
- // Initialize the p2p server. This creates the node key and
- // discovery databases.
- n.server = &p2p.Server{Config: n.config.P2P} // TODO add init step for p2p server
- n.server.Config.PrivateKey = n.config.NodeKey()
- n.server.Config.Name = n.config.NodeName()
- n.server.Config.Logger = n.log
- if n.server.Config.StaticNodes == nil {
- n.server.Config.StaticNodes = n.config.StaticNodes()
- }
- if n.server.Config.TrustedNodes == nil {
- n.server.Config.TrustedNodes = n.config.TrustedNodes()
- }
- if n.server.Config.NodeDatabase == "" {
- n.server.Config.NodeDatabase = n.config.NodeDB()
- }
-
// Start the p2p node
if err := n.server.Start(); err != nil {
return convertFileLockError(err)
}
n.log.Info("Starting peer-to-peer node", "instance", n.server.Name)
- // Register the running p2p server with the Backend
- if err := n.backend.P2PServer(n.server); err != nil {
- n.server.Stop()
- return err
- }
- // Register the Backend's protocols with the p2p server
- if err := n.RegisterProtocols(n.backend.Protocols()); err != nil {
- n.server.Stop()
- return err
- }
+ // TODO running p2p server needs to somehow be added to the backend
+
// Start all registered lifecycles
var started []Lifecycle
for _, lifecycle := range n.lifecycles {
@@ -355,7 +342,6 @@ func (n *Node) openDataDir() error {
// startup. It's not meant to be called at any time afterwards as it makes certain
// assumptions about the state of the node.
func (n *Node) startRPC() error {
- n.RegisterRPC(n.apis())
// Start the various API endpoints, terminating all in case of errors
if err := n.startInProc(); err != nil {
return err
@@ -389,12 +375,6 @@ func (n *Node) startRPC() error {
n.ws.handler = n.ws.Srv.WebsocketHandler(n.ws.CorsAllowedOrigins)
n.RegisterHTTP(n.http, n.ws)
}
- // if an auxiliary service has not been started, check if it has the same endpoint, then start
- for _, auxServices := range n.auxServices {
- if auxServices.Server().endpoint == n.http.endpoint { // TODO maybe also check that auxServices.Server().Server == nil? or is it unnecessary?
- n.RegisterHTTP(n.http, auxServices.Server())
- }
- }
// only set exposeAll if websocket is enabled
var exposeAll bool
if n.http.WSAllowed {
@@ -576,13 +556,12 @@ func (n *Node) Stop() error {
failure := &StopError{
Services: make(map[reflect.Type]error),
}
- for kind, service := range n.services {
- if err := service.Stop(); err != nil {
- failure.Services[kind] = err
+ for _, lifecycle := range n.lifecycles {
+ if err := lifecycle.Stop(); err != nil {
+ failure.Services[reflect.TypeOf(lifecycle)] = err
}
}
n.server.Stop()
- n.services = nil
n.server = nil
// Release instance directory lock.
@@ -659,17 +638,6 @@ func (n *Node) RPCHandler() (*rpc.Server, error) {
return n.inprocHandler, nil
}
-func (n *Node) Backend() (*eth.Ethereum, *les.LightEthereum) {
- if n.ethBackend != nil && n.lesBackend == nil {
- return n.ethBackend, nil
- }
- if n.ethBackend == nil && n.lesBackend != nil {
- return nil, n.lesBackend
- }
-
- return nil, nil
-}
-
// Server retrieves the currently running P2P network layer. This method is meant
// only to inspect fields of the currently running server, life cycle management
// should be left to this Node entity.
diff --git a/node/service.go b/node/service.go
index 80971d7c5301..c86372bb053e 100644
--- a/node/service.go
+++ b/node/service.go
@@ -18,7 +18,6 @@ package node
import (
"path/filepath"
- "reflect"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/core/rawdb"
@@ -72,15 +71,15 @@ func (ctx *ServiceContext) ResolvePath(path string) string {
return ctx.Config.ResolvePath(path)
}
-// Service retrieves a currently running service registered of a specific type.
-func (ctx *ServiceContext) Service(service interface{}) error {
- element := reflect.ValueOf(service).Elem()
- if running, ok := ctx.services[element.Type()]; ok {
- element.Set(reflect.ValueOf(running))
- return nil
- }
- return ErrServiceUnknown
-}
+//// Service retrieves a currently running service registered of a specific type.
+//func (ctx *ServiceContext) Service(service interface{}) error {
+// element := reflect.ValueOf(service).Elem()
+// if running, ok := ctx.services[element.Type()]; ok {
+// element.Set(reflect.ValueOf(running))
+// return nil
+// }
+// return ErrServiceUnknown
+//}
// ExtRPCEnabled returns the indicator whether node enables the external
// RPC(http, ws or graphql).
diff --git a/p2p/server.go b/p2p/server.go
index 1fe5f3978923..2e7a9c0b14be 100644
--- a/p2p/server.go
+++ b/p2p/server.go
@@ -1119,3 +1119,7 @@ func (srv *Server) PeersInfo() []*PeerInfo {
}
return infos
}
+
+func (srv *Server) Listening() bool {
+ return srv.listener != nil
+}
From e15007e3fda333b0c8ed4233583729059e31db8e Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Tue, 12 May 2020 19:26:58 +0200
Subject: [PATCH 024/160] registering all apis
---
node/node.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/node/node.go b/node/node.go
index 2d56fceb7653..7f7fe4e044d8 100644
--- a/node/node.go
+++ b/node/node.go
@@ -206,8 +206,6 @@ func (n *Node) RegisterProtocols(protocols []p2p.Protocol) error {
}
func (n *Node) RegisterAPIs(apis []rpc.API) {
- // TODO check for duplicates?
-
n.rpcAPIs = append(n.rpcAPIs, apis...)
}
@@ -342,6 +340,8 @@ func (n *Node) openDataDir() error {
// startup. It's not meant to be called at any time afterwards as it makes certain
// assumptions about the state of the node.
func (n *Node) startRPC() error {
+ n.RegisterAPIs(n.apis())
+
// Start the various API endpoints, terminating all in case of errors
if err := n.startInProc(); err != nil {
return err
From 3993923388d1e170469d3cdad6ff3e9f496abbfb Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Wed, 13 May 2020 14:21:20 +0200
Subject: [PATCH 025/160] added todo
---
eth/backend.go | 2 ++
1 file changed, 2 insertions(+)
diff --git a/eth/backend.go b/eth/backend.go
index 361758cc435d..71d1ddee1576 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -237,6 +237,8 @@ func New(stack *node.Node, config *Config) (*Ethereum, error) {
return nil, err
}
+ // TODO don't forget to RegisterName on rpc.Server!!!!!!!!
+
// Register the backend on the node
stack.RegisterAPIs(eth.APIs())
if err := stack.RegisterProtocols(eth.Protocols()); err != nil {
From 0a3f9a212cf2ae01a8a0d5db006a6587b2a1366d Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Wed, 13 May 2020 14:55:58 +0200
Subject: [PATCH 026/160] removed todo
---
eth/backend.go | 2 --
1 file changed, 2 deletions(-)
diff --git a/eth/backend.go b/eth/backend.go
index 71d1ddee1576..361758cc435d 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -237,8 +237,6 @@ func New(stack *node.Node, config *Config) (*Ethereum, error) {
return nil, err
}
- // TODO don't forget to RegisterName on rpc.Server!!!!!!!!
-
// Register the backend on the node
stack.RegisterAPIs(eth.APIs())
if err := stack.RegisterProtocols(eth.Protocols()); err != nil {
From 2888ca46dde0d0e7878d813f56d004c1417cb407 Mon Sep 17 00:00:00 2001
From: rene <41963722+renaynay@users.noreply.github.com>
Date: Fri, 15 May 2020 16:16:24 +0200
Subject: [PATCH 027/160] Register http (#16)
* register http new impl
* start ws thorugh console on same port as http
---
go.mod | 4 +-
go.sum | 9 +-
graphql/service.go | 91 +++++-------
node/api.go | 121 +++++++++------
node/node.go | 361 +++++++++++++++++++++++++--------------------
node/rpcstack.go | 2 +
6 files changed, 327 insertions(+), 261 deletions(-)
diff --git a/go.mod b/go.mod
index 2299eb501753..db16cd3cb592 100644
--- a/go.mod
+++ b/go.mod
@@ -25,8 +25,8 @@ require (
github.com/go-ole/go-ole v1.2.1 // indirect
github.com/go-sourcemap/sourcemap v2.1.2+incompatible // indirect
github.com/go-stack/stack v1.8.0
- github.com/golang/protobuf v1.3.2-0.20190517061210-b285ee9cfc6c
- github.com/golang/snappy v0.0.2-0.20200707131729-196ae77b8a26
+ github.com/golang/protobuf v1.3.3
+ github.com/golang/snappy v0.0.2-0.20190904063534-ff6b7dc882cf
github.com/google/go-cmp v0.3.1 // indirect
github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989
github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277
diff --git a/go.sum b/go.sum
index 4c46eeb5afb0..2bb6d1e16912 100644
--- a/go.sum
+++ b/go.sum
@@ -79,14 +79,15 @@ github.com/go-sourcemap/sourcemap v2.1.2+incompatible h1:0b/xya7BKGhXuqFESKM4oIi
github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.2-0.20190517061210-b285ee9cfc6c h1:zqAKixg3cTcIasAMJV+EcfVbWwLpOZ7LeoWJvcuD/5Q=
-github.com/golang/protobuf v1.3.2-0.20190517061210-b285ee9cfc6c/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
+github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/golang/snappy v0.0.2-0.20200707131729-196ae77b8a26 h1:lMm2hD9Fy0ynom5+85/pbdkiYcBqM1JWmhpAXLmy0fw=
-github.com/golang/snappy v0.0.2-0.20200707131729-196ae77b8a26/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v0.0.2-0.20190904063534-ff6b7dc882cf h1:gFVkHXmVAhEbxZVDln5V9GKrLaluNoFHDbrZwAWZgws=
+github.com/golang/snappy v0.0.2-0.20190904063534-ff6b7dc882cf/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989 h1:giknQ4mEuDFmmHSrGcbargOuLHQGtywqo4mheITex54=
diff --git a/graphql/service.go b/graphql/service.go
index 68e41fde4689..559bb2852643 100644
--- a/graphql/service.go
+++ b/graphql/service.go
@@ -17,16 +17,12 @@
package graphql
import (
- "context"
"errors"
- "fmt"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/les"
- "net"
"net/http"
"github.com/ethereum/go-ethereum/internal/ethapi"
- "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/rpc"
"github.com/graph-gophers/graphql-go"
@@ -41,14 +37,7 @@ type Service struct {
// New constructs a new GraphQL service instance.
func New(stack *node.Node, ethBackend *eth.Ethereum, lesBackend *les.LightEthereum, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) error {
- service := &Service{
- graphqlServer: &node.HTTPServer{
- Timeouts: timeouts,
- Vhosts: vhosts,
- CorsAllowedOrigins: cors,
- GQLAllowed: true,
- },
- }
+ service := new(Service)
// add backend
if ethBackend != nil {
service.backend = ethBackend.APIBackend
@@ -58,26 +47,52 @@ func New(stack *node.Node, ethBackend *eth.Ethereum, lesBackend *les.LightEthere
return errors.New("no Ethereum service")
}
- service.graphqlServer.SetEndpoint(endpoint)
- // create handler
- handler, err := service.CreateHandler()
+ // check if http server with given endpoint exists and enable graphQL on it
+ server := stack.ExistingHTTPServer(endpoint)
+ if server != nil {
+ server.GQLAllowed = true
+ server.Vhosts = append(server.Vhosts, vhosts...)
+ server.CorsAllowedOrigins = append(server.CorsAllowedOrigins, cors...)
+ server.Timeouts = timeouts
+ // create handler
+ handler, err := createHandler(service.backend, cors, vhosts)
+ if err != nil {
+ return err
+ }
+ server.GQLHandler = handler
+ // don't register lifecycle if registering on existing http server
+ return nil
+ }
+ // otherwise create a new server
+ handler, err := createHandler(service.backend, cors, vhosts)
if err != nil {
return err
}
- service.graphqlServer.SetHandler(handler)
+ // create the http server
+ gqlServer := &node.HTTPServer{
+ Vhosts: vhosts,
+ CorsAllowedOrigins: cors,
+ Timeouts: timeouts,
+ GQLAllowed: true,
+ GQLHandler: handler,
+ Srv: rpc.NewServer(),
+ }
+ gqlServer.SetEndpoint(endpoint)
+ stack.RegisterHTTPServer(gqlServer)
+
+ service.graphqlServer = gqlServer
- // TODO register http
- return stack.RegisterLifecycle(service)
+ return nil
}
-func (s *Service) CreateHandler() (http.Handler, error) {
+func createHandler(backend ethapi.Backend, cors, vhosts []string) (http.Handler, error) {
// create handler stack and wrap the graphql handler
- handler, err := newHandler(s.backend)
+ handler, err := newHandler(backend)
if err != nil {
return nil, err
}
+ handler = node.NewHTTPHandlerStack(handler, cors, vhosts)
- handler = node.NewHTTPHandlerStack(handler, s.graphqlServer.CorsAllowedOrigins, s.graphqlServer.Vhosts)
return handler, nil
}
@@ -102,32 +117,6 @@ func newHandler(backend ethapi.Backend) (http.Handler, error) {
// Start is called after all services have been constructed and the networking
// layer was also initialized to spawn any goroutines required by the service.
func (s *Service) Start() error {
- handler, err := s.CreateHandler()
- if err != nil {
- return err
- }
- s.graphqlServer.SetHandler(handler)
-
- // start listening on given endpoint
- listener, err := net.Listen("tcp", s.graphqlServer.Endpoint())
- if err != nil {
- return err
- }
- // make sure timeout values are meaningful
- node.CheckTimeouts(&s.graphqlServer.Timeouts)
- // create http server
- httpSrv := &http.Server{
- Handler: handler,
- ReadTimeout: s.graphqlServer.Timeouts.ReadTimeout,
- WriteTimeout: s.graphqlServer.Timeouts.WriteTimeout,
- IdleTimeout: s.graphqlServer.Timeouts.IdleTimeout,
- }
- go httpSrv.Serve(listener)
- log.Info("GraphQL endpoint opened", "url", fmt.Sprintf("http://%v", listener.Addr()))
- // add information to graphql http server
- s.graphqlServer.Server = httpSrv
- s.graphqlServer.ListenerAddr = listener.Addr()
- s.graphqlServer.SetHandler(handler)
return nil
}
@@ -135,10 +124,10 @@ func (s *Service) Start() error {
// Stop terminates all goroutines belonging to the service, blocking until they
// are all terminated.
func (s *Service) Stop() error {
- if s.graphqlServer.Server != nil {
- s.graphqlServer.Server.Shutdown(context.Background())
- log.Info("GraphQL endpoint closed", "url", fmt.Sprintf("http://%v", s.graphqlServer.ListenerAddr))
- }
+ //if s.graphqlServer.Server != nil {
+ // s.graphqlServer.Server.Shutdown(context.Background())
+ // log.Info("GraphQL endpoint closed", "url", fmt.Sprintf("http://%v", s.graphqlServer.ListenerAddr))
+ //}
return nil
}
diff --git a/node/api.go b/node/api.go
index 437807f6dc53..0ae40cc208c6 100644
--- a/node/api.go
+++ b/node/api.go
@@ -146,9 +146,11 @@ func (api *PrivateAdminAPI) PeerEvents(ctx context.Context) (*rpc.Subscription,
func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis *string, vhosts *string) (bool, error) {
api.node.lock.Lock()
defer api.node.lock.Unlock()
-
- if api.node.http.Server != nil {
- return false, fmt.Errorf("HTTP RPC already running on %v", api.node.http.ListenerAddr)
+ // check if HTTP server already exists
+ for _, httpServer := range api.node.httpServers {
+ if httpServer.RPCAllowed {
+ return false, fmt.Errorf("HTTP RPC already running on %v", httpServer.ListenerAddr)
+ }
}
if host == nil {
@@ -161,9 +163,7 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
if port == nil {
port = &api.node.config.HTTPPort
}
- api.node.http.host = *host
- api.node.http.port = *port
- api.node.http.endpoint = fmt.Sprintf("%s:%d", *host, *port)
+ endpoint := fmt.Sprintf("%s:%d", *host, *port)
allowedOrigins := api.node.config.HTTPCors
if cors != nil {
@@ -172,7 +172,6 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
allowedOrigins = append(allowedOrigins, strings.TrimSpace(origin))
}
}
- api.node.http.CorsAllowedOrigins = allowedOrigins
allowedVHosts := api.node.config.HTTPVirtualHosts
if vhosts != nil {
@@ -181,27 +180,37 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
allowedVHosts = append(allowedVHosts, strings.TrimSpace(vhost))
}
}
- api.node.http.Vhosts = allowedVHosts
- modules := api.node.http.Whitelist
+ modules := api.node.config.HTTPModules
if apis != nil {
modules = nil
for _, m := range strings.Split(*apis, ",") {
modules = append(modules, strings.TrimSpace(m))
}
}
- api.node.http.Whitelist = modules
+ // configure http server
+ httpServer := &HTTPServer{
+ host: *host,
+ port: *port,
+ endpoint: endpoint,
+ Srv: rpc.NewServer(),
+ CorsAllowedOrigins: allowedOrigins,
+ Vhosts: allowedVHosts,
+ Whitelist: modules,
+ }
// create handler
- api.node.http.handler = NewHTTPHandlerStack(api.node.http.Srv, api.node.http.CorsAllowedOrigins, api.node.http.Vhosts)
+ httpServer.handler = NewHTTPHandlerStack(httpServer.Srv, httpServer.CorsAllowedOrigins, httpServer.Vhosts)
// create HTTP server
- if err := api.node.CreateHTTPServer(api.node.http, false); err != nil {
+ if err := api.node.CreateHTTPServer(httpServer, false); err != nil {
return false, err
}
// start the HTTP server
- api.node.http.Start()
- api.node.log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%v/", api.node.http.ListenerAddr),
- "cors", strings.Join(api.node.http.CorsAllowedOrigins, ","),
- "vhosts", strings.Join(api.node.http.Vhosts, ","))
+ httpServer.Start()
+ api.node.log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%v/", httpServer.ListenerAddr),
+ "cors", strings.Join(httpServer.CorsAllowedOrigins, ","),
+ "vhosts", strings.Join(httpServer.Vhosts, ","))
+
+ api.node.RegisterHTTPServer(httpServer)
return true, nil
}
@@ -210,22 +219,25 @@ func (api *PrivateAdminAPI) StopRPC() (bool, error) {
api.node.lock.Lock()
defer api.node.lock.Unlock()
- if api.node.http == nil {
- return false, fmt.Errorf("HTTP RPC not running")
+ for _, httpServer := range api.node.httpServers {
+ if httpServer.RPCAllowed {
+ api.node.stopServer(httpServer)
+ return true, nil
+ }
}
- api.node.stopHTTP()
- return true, nil
+
+ return false, fmt.Errorf("HTTP RPC not running")
}
// StartWS starts the websocket RPC API server.
func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *string, apis *string) (bool, error) {
api.node.lock.Lock()
defer api.node.lock.Unlock()
-
- if api.node.ws.Server != nil {
- return false, fmt.Errorf("WebSocket RPC already running on %v", api.node.ws.ListenerAddr)
- } else if api.node.http.WSAllowed {
- return false, fmt.Errorf("WebSocket RPC already running on %v", api.node.http.ListenerAddr)
+ // check if an existing HTTP server already handles websocket
+ for _, httpServer := range api.node.httpServers {
+ if httpServer.WSAllowed {
+ return false, fmt.Errorf("WebSocket RPC already running on %v", httpServer.ListenerAddr)
+ }
}
// set host, port and endpoint
if host == nil {
@@ -238,15 +250,7 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
if port == nil {
port = &api.node.config.WSPort
}
- api.node.ws.host = *host
- api.node.ws.port = *port
- api.node.ws.endpoint = fmt.Sprintf("%s:%d", *host, *port)
-
- if api.node.ws.endpoint == api.node.http.endpoint && api.node.http.Server != nil {
- api.node.http.WSAllowed = true
- api.node.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", api.node.http.ListenerAddr))
- return true, nil
- }
+ endpoint := fmt.Sprintf("%s:%d", *host, *port)
origins := api.node.config.WSOrigins
if allowedOrigins != nil {
@@ -255,7 +259,14 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
origins = append(origins, strings.TrimSpace(origin))
}
}
- api.node.ws.WsOrigins = origins
+ // check if an HTTP server exists on the given endpoint, and if so, enable websocket on that HTTP server
+ existingServer := api.node.ExistingHTTPServer(endpoint)
+ if existingServer != nil {
+ existingServer.WSAllowed = true
+ existingServer.WsOrigins = origins
+ api.node.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", existingServer.ListenerAddr))
+ return true, nil
+ }
modules := api.node.config.WSModules
if apis != nil {
@@ -264,15 +275,26 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
modules = append(modules, strings.TrimSpace(m))
}
}
- api.node.ws.Whitelist = modules
- api.node.ws.handler = api.node.ws.Srv.WebsocketHandler(api.node.ws.WsOrigins)
- if err := api.node.CreateHTTPServer(api.node.ws, api.node.config.WSExposeAll); err != nil {
+ wsServer := &HTTPServer{
+ Srv: rpc.NewServer(),
+ endpoint: endpoint,
+ host: *host,
+ port: *port,
+ Whitelist: modules,
+ WsOrigins: origins,
+ WSAllowed: true,
+ }
+
+ wsServer.handler = wsServer.Srv.WebsocketHandler(wsServer.WsOrigins)
+ if err := api.node.CreateHTTPServer(wsServer, api.node.config.WSExposeAll); err != nil {
return false, err
}
- api.node.ws.Start()
- api.node.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", api.node.ws.ListenerAddr))
+ wsServer.Start()
+ api.node.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", wsServer.ListenerAddr))
+
+ api.node.RegisterHTTPServer(wsServer)
return true, nil
}
@@ -281,16 +303,19 @@ func (api *PrivateAdminAPI) StopWS() (bool, error) {
api.node.lock.Lock()
defer api.node.lock.Unlock()
- if api.node.ws.Server == nil && !api.node.http.WSAllowed {
- return false, fmt.Errorf("WebSocket RPC not running")
- }
- if api.node.http.WSAllowed {
- api.node.http.WSAllowed = false
- return true, nil
+ for _, httpServer := range api.node.httpServers {
+ if httpServer.WSAllowed {
+ httpServer.WSAllowed = false
+ // if RPC is not enabled on the WS http server, shut it down
+ if !httpServer.RPCAllowed {
+ api.node.stopServer(httpServer)
+ }
+
+ return true, nil
+ }
}
- api.node.stopWS()
- return true, nil
+ return false, fmt.Errorf("WebSocket RPC not running")
}
// PublicAdminAPI is the collection of administrative API methods exposed over
diff --git a/node/node.go b/node/node.go
index 7f7fe4e044d8..11ebea4d32bd 100644
--- a/node/node.go
+++ b/node/node.go
@@ -58,9 +58,9 @@ type Node struct {
rpcAPIs []rpc.API // List of APIs currently provided by the node
inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
+ httpServers []*HTTPServer // Stores information about all http servers (if any), including http, ws, and graphql
+
ipc *HTTPServer // TODO
- http *HTTPServer // TODO
- ws *HTTPServer // TODO
stop chan struct{} // Channel to wait for termination notifications
lock sync.RWMutex
@@ -110,36 +110,13 @@ func New(conf *Config) (*Node, error) {
ServiceContext: &ServiceContext{
Config: *conf,
},
+ httpServers: make([]*HTTPServer, 0),
ipc: &HTTPServer{
endpoint: conf.IPCEndpoint(),
},
- http: &HTTPServer{
- CorsAllowedOrigins: conf.HTTPCors,
- Vhosts: conf.HTTPVirtualHosts,
- Whitelist: conf.HTTPModules,
- Timeouts: conf.HTTPTimeouts,
- Srv: rpc.NewServer(),
- endpoint: conf.HTTPEndpoint(),
- host: conf.HTTPHost,
- port: conf.HTTPPort,
- },
- ws: &HTTPServer{
- CorsAllowedOrigins: conf.WSOrigins,
- Whitelist: conf.WSModules,
- Srv: rpc.NewServer(),
- endpoint: conf.WSEndpoint(),
- host: conf.WSHost,
- port: conf.WSPort,
- },
eventmux: new(event.TypeMux),
log: conf.Logger,
}
- if conf.HTTPHost != "" {
- node.http.RPCAllowed = true
- }
- if conf.WSHost != "" {
- node.ws.WSAllowed = true
- }
// Initialize the p2p server. This creates the node key and
// discovery databases.
@@ -156,9 +133,44 @@ func New(conf *Config) (*Node, error) {
if node.server.Config.NodeDatabase == "" {
node.server.Config.NodeDatabase = node.config.NodeDB()
}
-
+ // Configure service context
node.ServiceContext.EventMux = node.eventmux
node.ServiceContext.AccountManager = node.accman
+ // Configure HTTP server(s)
+ if conf.HTTPHost != "" {
+ httpServ := &HTTPServer{
+ CorsAllowedOrigins: conf.HTTPCors,
+ Vhosts: conf.HTTPVirtualHosts,
+ Whitelist: conf.HTTPModules,
+ Timeouts: conf.HTTPTimeouts,
+ Srv: rpc.NewServer(),
+ endpoint: conf.HTTPEndpoint(),
+ host: conf.HTTPHost,
+ port: conf.HTTPPort,
+ RPCAllowed: true,
+ }
+ // check if ws is enabled and if ws port is the same as http port
+ if conf.WSHost != "" && conf.WSPort == conf.HTTPPort {
+ httpServ.WSAllowed = true
+ httpServ.WsOrigins = conf.WSOrigins
+ httpServ.Whitelist = append(httpServ.Whitelist, conf.WSModules...)
+ node.httpServers = append(node.httpServers, httpServ)
+ return node, nil
+ }
+ node.httpServers = append(node.httpServers, httpServ)
+ }
+ if conf.WSHost != "" {
+ node.httpServers = append(node.httpServers, &HTTPServer{
+ WsOrigins: conf.WSOrigins,
+ Whitelist: conf.WSModules,
+ Srv: rpc.NewServer(),
+ endpoint: conf.WSEndpoint(),
+ host: conf.WSHost,
+ port: conf.WSPort,
+ WSAllowed: true,
+ })
+ }
+
return node, nil
}
@@ -209,6 +221,20 @@ func (n *Node) RegisterAPIs(apis []rpc.API) {
n.rpcAPIs = append(n.rpcAPIs, apis...)
}
+func (n *Node) ExistingHTTPServer(endpoint string) *HTTPServer {
+ for _, httpServer := range n.httpServers {
+ if endpoint == httpServer.endpoint {
+ return httpServer
+ }
+ }
+
+ return nil
+}
+
+func (n *Node) RegisterHTTPServer(server *HTTPServer) {
+ n.httpServers = append(n.httpServers, server)
+}
+
// TODO document
func (n *Node) RegisterHTTP(dest *HTTPServer, toRegister *HTTPServer) {
// takes in default existing http server
@@ -247,6 +273,7 @@ func (n *Node) CreateHTTPServer(h *HTTPServer, exposeAll bool) error {
httpSrv.WriteTimeout = h.Timeouts.WriteTimeout
httpSrv.IdleTimeout = h.Timeouts.IdleTimeout
}
+
// complete the HTTPServer
h.Listener = listener
h.ListenerAddr = listener.Addr()
@@ -350,46 +377,36 @@ func (n *Node) startRPC() error {
n.stopInProc()
return err
}
- // create and start ws server if the endpoint exists
- if n.ws.endpoint != "" && n.http.endpoint != n.ws.endpoint {
- n.ws.handler = n.ws.Srv.WebsocketHandler(n.ws.CorsAllowedOrigins)
- if err := n.CreateHTTPServer(n.ws, n.config.WSExposeAll); err != nil {
- n.stopIPC()
- n.stopInProc()
- return err
+
+ for _, server := range n.httpServers {
+ // configure the handlers
+ if server.RPCAllowed {
+ server.handler = NewHTTPHandlerStack(server.Srv, server.CorsAllowedOrigins, server.Vhosts)
+ // wrap ws handler just in case ws is enabled through the console after start-up
+ wsHandler := server.Srv.WebsocketHandler(server.WsOrigins)
+ server.handler = server.NewWebsocketUpgradeHandler(server.handler, wsHandler)
+
+ n.log.Info("HTTP configured on endpoint ", "endpoint", server.endpoint)
}
- n.ws.Start()
- n.ws.WSAllowed = true
- n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%s", n.ws.ListenerAddr))
- }
- // create and start http server if the endpoint exists // TODO CLEAN THIS UP!!!!!!!!!
- if n.http.endpoint != "" {
- // wrap handler in websocket handler only if websocket port is the same as http rpc
- n.http.handler = NewHTTPHandlerStack(n.http.Srv, n.http.CorsAllowedOrigins, n.http.Vhosts)
- // if websocket server is not already started, or is specified on the same endpoint as http,
- // register websocket on the http server
- if n.ws.Server == nil {
- if n.http.endpoint == n.ws.endpoint {
- n.http.WSAllowed = true
- }
- n.ws.handler = n.ws.Srv.WebsocketHandler(n.ws.CorsAllowedOrigins)
- n.RegisterHTTP(n.http, n.ws)
+ if server.WSAllowed && server.handler == nil {
+ server.handler = server.Srv.WebsocketHandler(server.WsOrigins)
+ n.log.Info("Websocket configured on endpoint ", "endpoint", server.endpoint)
}
- // only set exposeAll if websocket is enabled
- var exposeAll bool
- if n.http.WSAllowed {
- exposeAll = n.config.WSExposeAll
+ if server.GQLAllowed {
+ if server.handler == nil {
+ server.handler = server.GQLHandler
+ } else {
+ server.handler = NewGQLUpgradeHandler(server.handler, server.GQLHandler)
+ }
+ n.log.Info("GraphQL configured on endpoint ", "endpoint", server.endpoint)
}
- // create the HTTP Server
- if err := n.CreateHTTPServer(n.http, exposeAll); err != nil {
- n.stopIPC()
- n.stopInProc()
+ // create the HTTP server
+ if err := n.CreateHTTPServer(server, false); err != nil {
return err
}
- n.http.Start()
- n.log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%v/", n.http.ListenerAddr),
- "cors", strings.Join(n.http.CorsAllowedOrigins, ","),
- "vhosts", strings.Join(n.http.Vhosts, ","))
+ // start HTTP server
+ server.Start()
+ n.log.Info("HTTP endpoint successfully opened", "url", fmt.Sprintf("http://%v/", server.ListenerAddr))
}
// All API endpoints started successfully
return nil
@@ -446,96 +463,115 @@ func (n *Node) stopIPC() {
}
}
-// startHTTP initializes and starts the HTTP RPC endpoint.
-func (n *Node) startHTTP(endpoint string, modules []string, cors []string, vhosts []string, timeouts rpc.HTTPTimeouts, wsOrigins []string) error {
- // Short circuit if the HTTP endpoint isn't being exposed
- if endpoint == "" {
- return nil
- }
- // register apis and create handler stack
- srv := rpc.NewServer()
- err := RegisterApisFromWhitelist(n.rpcAPIs, modules, srv, false)
- if err != nil {
- return err
- }
- handler := NewHTTPHandlerStack(srv, cors, vhosts)
- // wrap handler in websocket handler only if websocket port is the same as http rpc
- if n.http.Endpoint() == n.ws.Endpoint() {
- handler = n.http.NewWebsocketUpgradeHandler(handler, srv.WebsocketHandler(wsOrigins))
- }
- httpServer, addr, err := StartHTTPEndpoint(endpoint, timeouts, handler)
- if err != nil {
- return err
- }
- n.log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%v/", addr),
- "cors", strings.Join(cors, ","),
- "vhosts", strings.Join(vhosts, ","))
- if n.http.Endpoint() == n.ws.Endpoint() {
- n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", addr))
- }
- // All listeners booted successfully
- n.http.endpoint = endpoint
- n.http.Server = httpServer
- n.http.ListenerAddr = addr
- n.http.Srv = srv
-
- return nil
-}
-
-// stopHTTP terminates the HTTP RPC endpoint.
-func (n *Node) stopHTTP() {
- if n.http.Server != nil {
- url := fmt.Sprintf("http://%v/", n.http.ListenerAddr)
- // Don't bother imposing a timeout here.
- n.http.Server.Shutdown(context.Background())
- n.log.Info("HTTP Endpoint closed", "url", url)
- }
- if n.http.Srv != nil {
- n.http.Srv.Stop()
- n.http.Srv = nil
- }
-}
-
-// startWS initializes and starts the websocket RPC endpoint.
-func (n *Node) startWS(endpoint string, modules []string, wsOrigins []string, exposeAll bool) error {
- // Short circuit if the WS endpoint isn't being exposed
- if endpoint == "" {
- return nil
- }
-
- srv := rpc.NewServer()
- handler := srv.WebsocketHandler(wsOrigins)
- err := RegisterApisFromWhitelist(n.rpcAPIs, modules, srv, exposeAll)
- if err != nil {
- return err
- }
- httpServer, addr, err := startWSEndpoint(endpoint, handler)
- if err != nil {
- return err
- }
- n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%s", addr))
- // All listeners booted successfully
- n.ws.endpoint = endpoint
- n.ws.ListenerAddr = addr
- n.ws.Server = httpServer
- n.ws.Srv = srv
-
- return nil
-}
+//// startHTTP initializes and starts the HTTP RPC endpoint.
+//func (n *Node) startHTTP(endpoint string, modules []string, cors []string, vhosts []string, timeouts rpc.HTTPTimeouts, wsOrigins []string) error {
+// // Short circuit if the HTTP endpoint isn't being exposed
+// if endpoint == "" {
+// return nil
+// }
+// // register apis and create handler stack
+// srv := rpc.NewServer()
+// err := RegisterApisFromWhitelist(n.rpcAPIs, modules, srv, false)
+// if err != nil {
+// return err
+// }
+// handler := NewHTTPHandlerStack(srv, cors, vhosts)
+// // wrap handler in websocket handler only if websocket port is the same as http rpc
+// if n.http.Endpoint() == n.ws.Endpoint() {
+// handler = n.http.NewWebsocketUpgradeHandler(handler, srv.WebsocketHandler(wsOrigins))
+// }
+// httpServer, addr, err := StartHTTPEndpoint(endpoint, timeouts, handler)
+// if err != nil {
+// return err
+// }
+// n.log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%v/", addr),
+// "cors", strings.Join(cors, ","),
+// "vhosts", strings.Join(vhosts, ","))
+// if n.http.Endpoint() == n.ws.Endpoint() {
+// n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", addr))
+// }
+// // All listeners booted successfully
+// n.http.endpoint = endpoint
+// n.http.Server = httpServer
+// n.http.ListenerAddr = addr
+// n.http.Srv = srv
+//
+// return nil
+//}
-// stopWS terminates the websocket RPC endpoint.
-func (n *Node) stopWS() {
- if n.ws.Server != nil {
- url := fmt.Sprintf("http://%v/", n.ws.ListenerAddr)
+// stopServers terminates the given HTTP servers' endpoints
+func (n *Node) stopServer(server *HTTPServer) {
+ if server.Server != nil {
+ url := fmt.Sprintf("http://%v/", server.ListenerAddr)
// Don't bother imposing a timeout here.
- n.ws.Server.Shutdown(context.Background())
+ server.Server.Shutdown(context.Background())
n.log.Info("HTTP Endpoint closed", "url", url)
}
- if n.ws.Srv != nil {
- n.ws.Srv.Stop()
- n.ws.Srv = nil
- }
-}
+ if server.Srv != nil {
+ server.Srv.Stop()
+ server.Srv = nil
+ }
+}
+
+
+//// stopHTTP terminates the HTTP RPC endpoint.
+//func (n *Node) stopHTTP() {
+// for _, server := range n.httpServers {
+// if server.RPCAllowed {
+// if server.Server != nil {
+// url := fmt.Sprintf("http://%v/", server.ListenerAddr)
+// // Don't bother imposing a timeout here.
+// server.Server.Shutdown(context.Background())
+// n.log.Info("HTTP Endpoint closed", "url", url)
+// }
+// if server.Srv != nil {
+// server.Srv.Stop()
+// server.Srv = nil
+// }
+// }
+// }
+//}
+
+//// startWS initializes and starts the websocket RPC endpoint.
+//func (n *Node) startWS(endpoint string, modules []string, wsOrigins []string, exposeAll bool) error {
+// // Short circuit if the WS endpoint isn't being exposed
+// if endpoint == "" {
+// return nil
+// }
+//
+// srv := rpc.NewServer()
+// handler := srv.WebsocketHandler(wsOrigins)
+// err := RegisterApisFromWhitelist(n.rpcAPIs, modules, srv, exposeAll)
+// if err != nil {
+// return err
+// }
+// httpServer, addr, err := startWSEndpoint(endpoint, handler)
+// if err != nil {
+// return err
+// }
+// n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%s", addr))
+// // All listeners booted successfully
+// n.ws.endpoint = endpoint
+// n.ws.ListenerAddr = addr
+// n.ws.Server = httpServer
+// n.ws.Srv = srv
+//
+// return nil
+//}
+
+//// stopWS terminates the websocket RPC endpoint.
+//func (n *Node) stopWS() {
+// if n.ws.Server != nil {
+// url := fmt.Sprintf("http://%v/", n.ws.ListenerAddr)
+// // Don't bother imposing a timeout here.
+// n.ws.Server.Shutdown(context.Background())
+// n.log.Info("HTTP Endpoint closed", "url", url)
+// }
+// if n.ws.Srv != nil {
+// n.ws.Srv.Stop()
+// n.ws.Srv = nil
+// }
+//}
// Stop terminates a running node along with all it's services. In the node was
// not started, an error is returned.
@@ -549,8 +585,9 @@ func (n *Node) Stop() error {
}
// Terminate the API, services and the p2p server.
- n.stopWS()
- n.stopHTTP()
+ for _, httpServer := range n.httpServers {
+ n.stopServer(httpServer)
+ }
n.stopIPC()
n.rpcAPIs = nil
failure := &StopError{
@@ -674,10 +711,16 @@ func (n *Node) HTTPEndpoint() string {
n.lock.Lock()
defer n.lock.Unlock()
- if n.http.Server != nil {
- return n.http.ListenerAddr.String()
+ for _, httpServer := range n.httpServers {
+ if httpServer.RPCAllowed {
+ if httpServer.Listener != nil {
+ return httpServer.ListenerAddr.String()
+ }
+ return httpServer.endpoint
+ }
}
- return n.http.Endpoint()
+
+ return "" // TODO should return an empty string if http server not configured?
}
// WSEndpoint retrieves the current WS endpoint
@@ -686,10 +729,16 @@ func (n *Node) WSEndpoint() string {
n.lock.Lock()
defer n.lock.Unlock()
- if n.ws.Server != nil {
- return n.ws.ListenerAddr.String()
+ for _, httpServer := range n.httpServers {
+ if httpServer.WSAllowed {
+ if httpServer.Listener != nil {
+ return httpServer.ListenerAddr.String()
+ }
+ return httpServer.endpoint
+ }
}
- return n.ws.Endpoint()
+
+ return "" // TODO should return an empty string if ws server not configured?
}
// EventMux retrieves the event multiplexer used by all the network services in
diff --git a/node/rpcstack.go b/node/rpcstack.go
index 4d214d80e45d..3903762c88c2 100644
--- a/node/rpcstack.go
+++ b/node/rpcstack.go
@@ -53,6 +53,8 @@ type HTTPServer struct {
RPCAllowed bool
WSAllowed bool
GQLAllowed bool
+
+ GQLHandler http.Handler
}
// TODO document
From 1f1bc0dcb33c5ab07f6b396d53f639f4803b70d7 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Tue, 19 May 2020 10:11:09 +0200
Subject: [PATCH 028/160] remove unnecessary RegisterHTTP method
---
node/node.go | 16 ----------------
1 file changed, 16 deletions(-)
diff --git a/node/node.go b/node/node.go
index 11ebea4d32bd..da28d8f6a8b7 100644
--- a/node/node.go
+++ b/node/node.go
@@ -235,22 +235,6 @@ func (n *Node) RegisterHTTPServer(server *HTTPServer) {
n.httpServers = append(n.httpServers, server)
}
-// TODO document
-func (n *Node) RegisterHTTP(dest *HTTPServer, toRegister *HTTPServer) {
- // takes in default existing http server
- // enables ____ on it
- if toRegister.GQLAllowed {
- dest.handler = NewGQLUpgradeHandler(dest.handler, toRegister.handler)
- dest.GQLAllowed = true
- log.Info("GraphQL endpoint opened", "url", fmt.Sprintf("http://%v", toRegister.endpoint))
- return
- }
- dest.handler = dest.NewWebsocketUpgradeHandler(dest.handler, toRegister.handler)
- if toRegister.WSAllowed {
- log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%s", toRegister.endpoint))
- }
-}
-
// CreateHTTPServer creates an http.Server and adds it to the given HTTPServer // TODO improve?
func (n *Node) CreateHTTPServer(h *HTTPServer, exposeAll bool) error {
// register apis and create handler stack
From ae58c941965d5418ca231f3cb8d3fd4ab25e13f4 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Tue, 19 May 2020 14:08:50 +0200
Subject: [PATCH 029/160] added docs, removed err return from register
lifecycle
---
eth/backend.go | 4 ++-
ethstats/ethstats.go | 3 +-
les/client.go | 4 ++-
node/node.go | 53 +++++++++++++++++-------------------
whisper/whisperv6/whisper.go | 4 ++-
5 files changed, 36 insertions(+), 32 deletions(-)
diff --git a/eth/backend.go b/eth/backend.go
index 361758cc435d..d09db2374d42 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -242,7 +242,9 @@ func New(stack *node.Node, config *Config) (*Ethereum, error) {
if err := stack.RegisterProtocols(eth.Protocols()); err != nil {
return nil, err
}
- return eth, stack.RegisterLifecycle(eth)
+ stack.RegisterLifecycle(eth)
+
+ return eth, nil
}
func makeExtraData(extra []byte) []byte {
diff --git a/ethstats/ethstats.go b/ethstats/ethstats.go
index f1328f5ed9a4..bada875b0bbb 100644
--- a/ethstats/ethstats.go
+++ b/ethstats/ethstats.go
@@ -106,8 +106,9 @@ func New(node *node.Node, ethBackend *eth.Ethereum, lesBackend *les.LightEthereu
pongCh: make(chan struct{}),
histCh: make(chan []uint64, 1),
}
+ node.RegisterLifecycle(ethstats)
- return node.RegisterLifecycle(ethstats)
+ return nil
}
// Start implements node.Service, starting up the monitoring and reporting daemon.
diff --git a/les/client.go b/les/client.go
index c8b7b39b5d00..351cc952968f 100644
--- a/les/client.go
+++ b/les/client.go
@@ -177,7 +177,9 @@ func New(stack *node.Node, config *eth.Config) (*LightEthereum, error) {
if err := stack.RegisterProtocols(leth.Protocols()); err != nil {
return nil, err
}
- return leth, stack.RegisterLifecycle(leth)
+ stack.RegisterLifecycle(leth)
+
+ return leth, nil
}
// vtSubscription implements serverPeerSubscriber
diff --git a/node/node.go b/node/node.go
index da28d8f6a8b7..755c4e161393 100644
--- a/node/node.go
+++ b/node/node.go
@@ -20,6 +20,7 @@ import (
"context"
"errors"
"fmt"
+ "github.com/ethereum/go-ethereum/cmd/utils"
"net"
"net/http"
"os"
@@ -48,7 +49,6 @@ type Node struct {
ephemeralKeystore string // if non-empty, the key directory that will be removed by Stop
instanceDirLock fileutil.Releaser // prevents concurrent use of instance directory
- // TODO: removed p2pConfig b/c p2pServer already contains p2pConfig (is there a reason for it to be duplicated?
server *p2p.Server // Currently running P2P networking layer
ServiceContext *ServiceContext
@@ -60,7 +60,7 @@ type Node struct {
httpServers []*HTTPServer // Stores information about all http servers (if any), including http, ws, and graphql
- ipc *HTTPServer // TODO
+ ipc *HTTPServer // Stores information about the ipc http server
stop chan struct{} // Channel to wait for termination notifications
lock sync.RWMutex
@@ -147,7 +147,7 @@ func New(conf *Config) (*Node, error) {
endpoint: conf.HTTPEndpoint(),
host: conf.HTTPHost,
port: conf.HTTPPort,
- RPCAllowed: true,
+ RPCAllowed: true,
}
// check if ws is enabled and if ws port is the same as http port
if conf.WSHost != "" && conf.WSPort == conf.HTTPPort {
@@ -162,12 +162,12 @@ func New(conf *Config) (*Node, error) {
if conf.WSHost != "" {
node.httpServers = append(node.httpServers, &HTTPServer{
WsOrigins: conf.WSOrigins,
- Whitelist: conf.WSModules,
- Srv: rpc.NewServer(),
- endpoint: conf.WSEndpoint(),
- host: conf.WSHost,
- port: conf.WSPort,
- WSAllowed: true,
+ Whitelist: conf.WSModules,
+ Srv: rpc.NewServer(),
+ endpoint: conf.WSEndpoint(),
+ host: conf.WSHost,
+ port: conf.WSPort,
+ WSAllowed: true,
})
}
@@ -197,44 +197,42 @@ func (n *Node) Close() error {
}
}
-// TODO document
-func (n *Node) RegisterLifecycle(lifecycle Lifecycle) error {
- for _, existing := range n.lifecycles { // TODO is checking for duplicates a good idea?
+// RegisterLifecycle registers the given Lifecycle on the node
+func (n *Node) RegisterLifecycle(lifecycle Lifecycle) {
+ for _, existing := range n.lifecycles {
if existing == lifecycle {
- return errors.New("Lifecycle already registered")
+ utils.Fatalf("Lifecycle cannot be registered more than once", lifecycle)
}
}
-
n.lifecycles = append(n.lifecycles, lifecycle)
- return nil
}
+// RegisterProtocols adds backend's protocols to the node's p2p server
func (n *Node) RegisterProtocols(protocols []p2p.Protocol) error {
- // TODO check for duplicates?
-
- // add backend's protocols to the p2p server
n.server.Protocols = append(n.server.Protocols, protocols...)
return nil
}
+// RegisterAPIs registers the APIs a service provides on the node
func (n *Node) RegisterAPIs(apis []rpc.API) {
n.rpcAPIs = append(n.rpcAPIs, apis...)
}
+// RegisterHTTPServer registers the given HTTP server on the node
+func (n *Node) RegisterHTTPServer(server *HTTPServer) {
+ n.httpServers = append(n.httpServers, server)
+}
+
+// ExistingHTTPServer checks if an HTTP server is already configured on the given endpoint
func (n *Node) ExistingHTTPServer(endpoint string) *HTTPServer {
for _, httpServer := range n.httpServers {
if endpoint == httpServer.endpoint {
return httpServer
}
}
-
return nil
}
-func (n *Node) RegisterHTTPServer(server *HTTPServer) {
- n.httpServers = append(n.httpServers, server)
-}
-
// CreateHTTPServer creates an http.Server and adds it to the given HTTPServer // TODO improve?
func (n *Node) CreateHTTPServer(h *HTTPServer, exposeAll bool) error {
// register apis and create handler stack
@@ -302,7 +300,7 @@ func (n *Node) Start() error {
}
// Lastly, start the configured RPC interfaces
- if err := n.startRPC(); err != nil {
+ if err := n.configureRPC(); err != nil {
n.stopLifecycles(n.lifecycles)
n.server.Stop()
return err
@@ -316,7 +314,7 @@ func (n *Node) Start() error {
return nil
}
-// TODO document
+// stopLifecycles stops the node's running Lifecycles
func (n *Node) stopLifecycles(started []Lifecycle) {
for _, lifecycle := range started {
lifecycle.Stop()
@@ -347,10 +345,10 @@ func (n *Node) openDataDir() error {
return nil
}
-// startRPC is a helper method to start all the various RPC endpoints during node
+// configureRPC is a helper method to configure all the various RPC endpoints during node
// startup. It's not meant to be called at any time afterwards as it makes certain
// assumptions about the state of the node.
-func (n *Node) startRPC() error {
+func (n *Node) configureRPC() error {
n.RegisterAPIs(n.apis())
// Start the various API endpoints, terminating all in case of errors
@@ -497,7 +495,6 @@ func (n *Node) stopServer(server *HTTPServer) {
}
}
-
//// stopHTTP terminates the HTTP RPC endpoint.
//func (n *Node) stopHTTP() {
// for _, server := range n.httpServers {
diff --git a/whisper/whisperv6/whisper.go b/whisper/whisperv6/whisper.go
index 6d2c9cf154fe..8613893eb4a8 100644
--- a/whisper/whisperv6/whisper.go
+++ b/whisper/whisperv6/whisper.go
@@ -137,7 +137,9 @@ func New(stack *node.Node, cfg *Config) error {
if err := stack.RegisterProtocols(whisper.Protocols()); err != nil {
return err
}
- return stack.RegisterLifecycle(whisper)
+ stack.RegisterLifecycle(whisper)
+
+ return nil
}
// MinPow returns the PoW value required by this node.
From 7acc43f71504c9a4e4ad3c5f81c5e61785030d11 Mon Sep 17 00:00:00 2001
From: rene <41963722+renaynay@users.noreply.github.com>
Date: Tue, 19 May 2020 13:54:31 +0200
Subject: [PATCH 030/160] HTTPServer implements Lifecycle and can be started by
the lifecycle loop in node (#17)
---
node/api.go | 8 ++-
node/node.go | 132 +++++------------------------------------------
node/rpcstack.go | 13 +++--
3 files changed, 27 insertions(+), 126 deletions(-)
diff --git a/node/api.go b/node/api.go
index 0ae40cc208c6..fe31c4e7eea2 100644
--- a/node/api.go
+++ b/node/api.go
@@ -221,7 +221,9 @@ func (api *PrivateAdminAPI) StopRPC() (bool, error) {
for _, httpServer := range api.node.httpServers {
if httpServer.RPCAllowed {
- api.node.stopServer(httpServer)
+ if err := httpServer.Stop(); err != nil {
+ return false, err
+ }
return true, nil
}
}
@@ -308,7 +310,9 @@ func (api *PrivateAdminAPI) StopWS() (bool, error) {
httpServer.WSAllowed = false
// if RPC is not enabled on the WS http server, shut it down
if !httpServer.RPCAllowed {
- api.node.stopServer(httpServer)
+ if err := httpServer.Stop(); err != nil {
+ return false, err
+ }
}
return true, nil
diff --git a/node/node.go b/node/node.go
index 755c4e161393..57b5bb05271f 100644
--- a/node/node.go
+++ b/node/node.go
@@ -17,7 +17,6 @@
package node
import (
- "context"
"errors"
"fmt"
"github.com/ethereum/go-ethereum/cmd/utils"
@@ -290,6 +289,13 @@ func (n *Node) Start() error {
// TODO running p2p server needs to somehow be added to the backend
+ // Start the configured RPC interfaces
+ if err := n.startRPC(); err != nil {
+ n.stopLifecycles(n.lifecycles)
+ n.server.Stop()
+ return err
+ }
+
// Start all registered lifecycles
var started []Lifecycle
for _, lifecycle := range n.lifecycles {
@@ -299,12 +305,6 @@ func (n *Node) Start() error {
started = append(started, lifecycle)
}
- // Lastly, start the configured RPC interfaces
- if err := n.configureRPC(); err != nil {
- n.stopLifecycles(n.lifecycles)
- n.server.Stop()
- return err
- }
// Finish initializing the service context
n.ServiceContext.AccountManager = n.accman
n.ServiceContext.EventMux = n.eventmux
@@ -369,6 +369,9 @@ func (n *Node) configureRPC() error {
server.handler = server.NewWebsocketUpgradeHandler(server.handler, wsHandler)
n.log.Info("HTTP configured on endpoint ", "endpoint", server.endpoint)
+ if server.WSAllowed {
+ n.log.Info("Websocket configured on endpoint ", "endpoint", server.endpoint)
+ }
}
if server.WSAllowed && server.handler == nil {
server.handler = server.Srv.WebsocketHandler(server.WsOrigins)
@@ -387,7 +390,9 @@ func (n *Node) configureRPC() error {
return err
}
// start HTTP server
- server.Start()
+ if err := n.RegisterLifecycle(server); err != nil {
+ return err
+ }
n.log.Info("HTTP endpoint successfully opened", "url", fmt.Sprintf("http://%v/", server.ListenerAddr))
}
// All API endpoints started successfully
@@ -445,114 +450,6 @@ func (n *Node) stopIPC() {
}
}
-//// startHTTP initializes and starts the HTTP RPC endpoint.
-//func (n *Node) startHTTP(endpoint string, modules []string, cors []string, vhosts []string, timeouts rpc.HTTPTimeouts, wsOrigins []string) error {
-// // Short circuit if the HTTP endpoint isn't being exposed
-// if endpoint == "" {
-// return nil
-// }
-// // register apis and create handler stack
-// srv := rpc.NewServer()
-// err := RegisterApisFromWhitelist(n.rpcAPIs, modules, srv, false)
-// if err != nil {
-// return err
-// }
-// handler := NewHTTPHandlerStack(srv, cors, vhosts)
-// // wrap handler in websocket handler only if websocket port is the same as http rpc
-// if n.http.Endpoint() == n.ws.Endpoint() {
-// handler = n.http.NewWebsocketUpgradeHandler(handler, srv.WebsocketHandler(wsOrigins))
-// }
-// httpServer, addr, err := StartHTTPEndpoint(endpoint, timeouts, handler)
-// if err != nil {
-// return err
-// }
-// n.log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%v/", addr),
-// "cors", strings.Join(cors, ","),
-// "vhosts", strings.Join(vhosts, ","))
-// if n.http.Endpoint() == n.ws.Endpoint() {
-// n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", addr))
-// }
-// // All listeners booted successfully
-// n.http.endpoint = endpoint
-// n.http.Server = httpServer
-// n.http.ListenerAddr = addr
-// n.http.Srv = srv
-//
-// return nil
-//}
-
-// stopServers terminates the given HTTP servers' endpoints
-func (n *Node) stopServer(server *HTTPServer) {
- if server.Server != nil {
- url := fmt.Sprintf("http://%v/", server.ListenerAddr)
- // Don't bother imposing a timeout here.
- server.Server.Shutdown(context.Background())
- n.log.Info("HTTP Endpoint closed", "url", url)
- }
- if server.Srv != nil {
- server.Srv.Stop()
- server.Srv = nil
- }
-}
-
-//// stopHTTP terminates the HTTP RPC endpoint.
-//func (n *Node) stopHTTP() {
-// for _, server := range n.httpServers {
-// if server.RPCAllowed {
-// if server.Server != nil {
-// url := fmt.Sprintf("http://%v/", server.ListenerAddr)
-// // Don't bother imposing a timeout here.
-// server.Server.Shutdown(context.Background())
-// n.log.Info("HTTP Endpoint closed", "url", url)
-// }
-// if server.Srv != nil {
-// server.Srv.Stop()
-// server.Srv = nil
-// }
-// }
-// }
-//}
-
-//// startWS initializes and starts the websocket RPC endpoint.
-//func (n *Node) startWS(endpoint string, modules []string, wsOrigins []string, exposeAll bool) error {
-// // Short circuit if the WS endpoint isn't being exposed
-// if endpoint == "" {
-// return nil
-// }
-//
-// srv := rpc.NewServer()
-// handler := srv.WebsocketHandler(wsOrigins)
-// err := RegisterApisFromWhitelist(n.rpcAPIs, modules, srv, exposeAll)
-// if err != nil {
-// return err
-// }
-// httpServer, addr, err := startWSEndpoint(endpoint, handler)
-// if err != nil {
-// return err
-// }
-// n.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%s", addr))
-// // All listeners booted successfully
-// n.ws.endpoint = endpoint
-// n.ws.ListenerAddr = addr
-// n.ws.Server = httpServer
-// n.ws.Srv = srv
-//
-// return nil
-//}
-
-//// stopWS terminates the websocket RPC endpoint.
-//func (n *Node) stopWS() {
-// if n.ws.Server != nil {
-// url := fmt.Sprintf("http://%v/", n.ws.ListenerAddr)
-// // Don't bother imposing a timeout here.
-// n.ws.Server.Shutdown(context.Background())
-// n.log.Info("HTTP Endpoint closed", "url", url)
-// }
-// if n.ws.Srv != nil {
-// n.ws.Srv.Stop()
-// n.ws.Srv = nil
-// }
-//}
// Stop terminates a running node along with all it's services. In the node was
// not started, an error is returned.
@@ -566,9 +463,6 @@ func (n *Node) Stop() error {
}
// Terminate the API, services and the p2p server.
- for _, httpServer := range n.httpServers {
- n.stopServer(httpServer)
- }
n.stopIPC()
n.rpcAPIs = nil
failure := &StopError{
diff --git a/node/rpcstack.go b/node/rpcstack.go
index 3903762c88c2..c9a1b47e522b 100644
--- a/node/rpcstack.go
+++ b/node/rpcstack.go
@@ -19,6 +19,7 @@ package node
import (
"compress/gzip"
"context"
+ "fmt"
"github.com/ethereum/go-ethereum/rpc"
"io"
"io/ioutil"
@@ -58,22 +59,24 @@ type HTTPServer struct {
}
// TODO document
-func (h *HTTPServer) Start() {
+func (h *HTTPServer) Start() error {
go h.Server.Serve(h.Listener)
+ return nil
}
-// TODO document
-func (h *HTTPServer) Stop() {
+func (h *HTTPServer) Stop() error {
if h.Server != nil {
- //url := fmt.Sprintf("http://%v/", h.ListenerAddr)
+ url := fmt.Sprintf("http://%v/", h.ListenerAddr)
// Don't bother imposing a timeout here.
h.Server.Shutdown(context.Background())
- //n.log.Info("HTTP Endpoint closed", "url", url) // TODO log wherever this is called instead
+ log.Info("HTTP Endpoint closed", "url", url)
}
if h.Srv != nil {
h.Srv.Stop()
h.Srv = nil
}
+
+ return nil
}
// Handler returns the handler of the HTTPServer
From 35460fdade2bedf14dbb2d97537d1a57c75a8b94 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Tue, 19 May 2020 14:22:17 +0200
Subject: [PATCH 031/160] removed unnecessary ListenerAddr
---
graphql/service.go | 8 +-------
node/api.go | 10 +++++-----
node/node.go | 44 +++++++++++++++++++++++++++++++++++++++-----
node/rpcstack.go | 4 ++--
4 files changed, 47 insertions(+), 19 deletions(-)
diff --git a/graphql/service.go b/graphql/service.go
index 559bb2852643..b086315496aa 100644
--- a/graphql/service.go
+++ b/graphql/service.go
@@ -123,13 +123,7 @@ func (s *Service) Start() error {
// Stop terminates all goroutines belonging to the service, blocking until they
// are all terminated.
-func (s *Service) Stop() error {
- //if s.graphqlServer.Server != nil {
- // s.graphqlServer.Server.Shutdown(context.Background())
- // log.Info("GraphQL endpoint closed", "url", fmt.Sprintf("http://%v", s.graphqlServer.ListenerAddr))
- //}
- return nil
-}
+func (s *Service) Stop() error { return nil }
func (s *Service) Server() *node.HTTPServer {
return s.graphqlServer
diff --git a/node/api.go b/node/api.go
index fe31c4e7eea2..fec2fa6102c1 100644
--- a/node/api.go
+++ b/node/api.go
@@ -149,7 +149,7 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
// check if HTTP server already exists
for _, httpServer := range api.node.httpServers {
if httpServer.RPCAllowed {
- return false, fmt.Errorf("HTTP RPC already running on %v", httpServer.ListenerAddr)
+ return false, fmt.Errorf("HTTP RPC already running on %v", httpServer.Listener.Addr())
}
}
@@ -206,7 +206,7 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
}
// start the HTTP server
httpServer.Start()
- api.node.log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%v/", httpServer.ListenerAddr),
+ api.node.log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%v/", httpServer.Listener.Addr()),
"cors", strings.Join(httpServer.CorsAllowedOrigins, ","),
"vhosts", strings.Join(httpServer.Vhosts, ","))
@@ -238,7 +238,7 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
// check if an existing HTTP server already handles websocket
for _, httpServer := range api.node.httpServers {
if httpServer.WSAllowed {
- return false, fmt.Errorf("WebSocket RPC already running on %v", httpServer.ListenerAddr)
+ return false, fmt.Errorf("WebSocket RPC already running on %v", httpServer.Listener.Addr())
}
}
// set host, port and endpoint
@@ -266,7 +266,7 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
if existingServer != nil {
existingServer.WSAllowed = true
existingServer.WsOrigins = origins
- api.node.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", existingServer.ListenerAddr))
+ api.node.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", existingServer.Listener.Addr()))
return true, nil
}
@@ -294,7 +294,7 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
}
wsServer.Start()
- api.node.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", wsServer.ListenerAddr))
+ api.node.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", wsServer.Listener.Addr()))
api.node.RegisterHTTPServer(wsServer)
return true, nil
diff --git a/node/node.go b/node/node.go
index 57b5bb05271f..3eaea73969d1 100644
--- a/node/node.go
+++ b/node/node.go
@@ -19,12 +19,13 @@ package node
import (
"errors"
"fmt"
- "github.com/ethereum/go-ethereum/cmd/utils"
+ "io"
"net"
"net/http"
"os"
"path/filepath"
"reflect"
+ "runtime"
"strings"
"sync"
@@ -200,7 +201,7 @@ func (n *Node) Close() error {
func (n *Node) RegisterLifecycle(lifecycle Lifecycle) {
for _, existing := range n.lifecycles {
if existing == lifecycle {
- utils.Fatalf("Lifecycle cannot be registered more than once", lifecycle)
+ Fatalf("Lifecycle cannot be registered more than once", lifecycle)
}
}
n.lifecycles = append(n.lifecycles, lifecycle)
@@ -257,7 +258,6 @@ func (n *Node) CreateHTTPServer(h *HTTPServer, exposeAll bool) error {
// complete the HTTPServer
h.Listener = listener
- h.ListenerAddr = listener.Addr()
h.Server = httpSrv
return nil
@@ -450,6 +450,19 @@ func (n *Node) stopIPC() {
}
}
+// stopServers terminates the given HTTP servers' endpoints
+func (n *Node) stopServer(server *HTTPServer) {
+ if server.Server != nil {
+ url := fmt.Sprintf("http://%v/", server.Listener.Addr())
+ // Don't bother imposing a timeout here.
+ server.Server.Shutdown(context.Background())
+ n.log.Info("HTTP Endpoint closed", "url", url)
+ }
+ if server.Srv != nil {
+ server.Srv.Stop()
+ server.Srv = nil
+ }
+}
// Stop terminates a running node along with all it's services. In the node was
// not started, an error is returned.
@@ -589,7 +602,7 @@ func (n *Node) HTTPEndpoint() string {
for _, httpServer := range n.httpServers {
if httpServer.RPCAllowed {
if httpServer.Listener != nil {
- return httpServer.ListenerAddr.String()
+ return httpServer.Listener.Addr().String()
}
return httpServer.endpoint
}
@@ -607,7 +620,7 @@ func (n *Node) WSEndpoint() string {
for _, httpServer := range n.httpServers {
if httpServer.WSAllowed {
if httpServer.Listener != nil {
- return httpServer.ListenerAddr.String()
+ return httpServer.Listener.Addr().String()
}
return httpServer.endpoint
}
@@ -703,3 +716,24 @@ func RegisterApisFromWhitelist(apis []rpc.API, modules []string, srv *rpc.Server
}
return nil
}
+
+// TODO change this when you figure out how else to do a nice fatal err
+// Fatalf formats a message to standard error and exits the program.
+// The message is also printed to standard output if standard error
+// is redirected to a different file.
+func Fatalf(format string, args ...interface{}) {
+ w := io.MultiWriter(os.Stdout, os.Stderr)
+ if runtime.GOOS == "windows" {
+ // The SameFile check below doesn't work on Windows.
+ // stdout is unlikely to get redirected though, so just print there.
+ w = os.Stdout
+ } else {
+ outf, _ := os.Stdout.Stat()
+ errf, _ := os.Stderr.Stat()
+ if outf != nil && errf != nil && os.SameFile(outf, errf) {
+ w = os.Stderr
+ }
+ }
+ fmt.Fprintf(w, "Fatal: "+format+"\n", args...)
+ os.Exit(1)
+}
diff --git a/node/rpcstack.go b/node/rpcstack.go
index c9a1b47e522b..3b439134a64d 100644
--- a/node/rpcstack.go
+++ b/node/rpcstack.go
@@ -38,7 +38,6 @@ type HTTPServer struct {
Server *http.Server
Listener net.Listener
- ListenerAddr net.Addr
endpoint string
host string
@@ -61,12 +60,13 @@ type HTTPServer struct {
// TODO document
func (h *HTTPServer) Start() error {
go h.Server.Serve(h.Listener)
+ log.Info("HTTP endpoint successfully opened", "url", fmt.Sprintf("http://%v/", h.Listener.Addr()))
return nil
}
func (h *HTTPServer) Stop() error {
if h.Server != nil {
- url := fmt.Sprintf("http://%v/", h.ListenerAddr)
+ url := fmt.Sprintf("http://%v/", h.Listener.Addr())
// Don't bother imposing a timeout here.
h.Server.Shutdown(context.Background())
log.Info("HTTP Endpoint closed", "url", url)
From ccadac33327b4075d7ba5a8a61fb7252aac46fb8 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Tue, 19 May 2020 14:41:26 +0200
Subject: [PATCH 032/160] stopServer removes stopped server from list of
httpservers on node and also removes from list of lifecycles
---
node/api.go | 11 ++++-------
node/node.go | 25 +++++++++++++++++++++++++
2 files changed, 29 insertions(+), 7 deletions(-)
diff --git a/node/api.go b/node/api.go
index fec2fa6102c1..2effb4f2a48f 100644
--- a/node/api.go
+++ b/node/api.go
@@ -221,9 +221,7 @@ func (api *PrivateAdminAPI) StopRPC() (bool, error) {
for _, httpServer := range api.node.httpServers {
if httpServer.RPCAllowed {
- if err := httpServer.Stop(); err != nil {
- return false, err
- }
+ api.node.stopServer(httpServer)
return true, nil
}
}
@@ -309,10 +307,9 @@ func (api *PrivateAdminAPI) StopWS() (bool, error) {
if httpServer.WSAllowed {
httpServer.WSAllowed = false
// if RPC is not enabled on the WS http server, shut it down
- if !httpServer.RPCAllowed {
- if err := httpServer.Stop(); err != nil {
- return false, err
- }
+ if !httpServer.RPCAllowed && !httpServer.GQLAllowed { // TODO is the gql check necessary? Can GQL ever be on a WS server that doesn't also support regular http?
+ api.node.stopServer(httpServer)
+ return true, nil
}
return true, nil
diff --git a/node/node.go b/node/node.go
index 3eaea73969d1..2b477c616f25 100644
--- a/node/node.go
+++ b/node/node.go
@@ -462,6 +462,31 @@ func (n *Node) stopServer(server *HTTPServer) {
server.Srv.Stop()
server.Srv = nil
}
+ // remove stopped http server from node's http servers // TODO is this preferable?
+ remainingServers := make([]*HTTPServer, len(n.httpServers)-1)
+ index := 0
+ for _, remaining := range n.httpServers {
+ if remaining.Server != nil && remaining.Srv != nil {
+ remainingServers[index] = remaining
+ index ++
+ }
+ }
+ n.httpServers = remainingServers
+ // remove stopped http server from node's lifecycles
+ n.removeLifecycle(server)
+}
+
+// removeLifecycle removes a stopped Lifecycle from the running node's Lifecycles
+func (n *Node) removeLifecycle(lifecycle Lifecycle) {
+ remainingLifecycles := make([]Lifecycle, len(n.lifecycles)-1)
+ index := 0
+ for _, remaining := range n.lifecycles {
+ if remaining != lifecycle {
+ remainingLifecycles[index] = remaining
+ index ++
+ }
+ }
+ n.lifecycles = remainingLifecycles
}
// Stop terminates a running node along with all it's services. In the node was
From e3f2bd1db3980b09d347def9e0b1a1f466af8bd4 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Tue, 19 May 2020 16:14:46 +0200
Subject: [PATCH 033/160] starting to remove use of node.Service throughout
codebase
---
console/console_test.go | 10 +++++-----
eth/backend.go | 4 ++--
ethclient/ethclient_test.go | 20 ++++++++++++--------
ethstats/ethstats.go | 4 ++--
les/api_test.go | 4 ++--
5 files changed, 23 insertions(+), 19 deletions(-)
diff --git a/console/console_test.go b/console/console_test.go
index a474f33300de..c6fd90be7f14 100644
--- a/console/console_test.go
+++ b/console/console_test.go
@@ -109,9 +109,12 @@ func newTester(t *testing.T, confOverride func(*eth.Config)) *tester {
if confOverride != nil {
confOverride(ethConf)
}
- if err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { return eth.New(ctx, ethConf) }); err != nil {
+ ethBackend, err := eth.New(stack, ethConf)
+ if err != nil {
t.Fatalf("failed to register Ethereum protocol: %v", err)
}
+
+
// Start the node and assemble the JavaScript console around it
if err = stack.Start(); err != nil {
t.Fatalf("failed to start test stack: %v", err)
@@ -135,13 +138,10 @@ func newTester(t *testing.T, confOverride func(*eth.Config)) *tester {
t.Fatalf("failed to create JavaScript console: %v", err)
}
// Create the final tester and return
- var ethereum *eth.Ethereum
- stack.Service(ðereum)
-
return &tester{
workspace: workspace,
stack: stack,
- ethereum: ethereum,
+ ethereum: ethBackend,
console: console,
input: prompter,
output: printer,
diff --git a/eth/backend.go b/eth/backend.go
index d09db2374d42..82e5fb6bcd74 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -553,7 +553,7 @@ func (s *Ethereum) P2PServer(server *p2p.Server) error {
return nil
}
-// Start implements node.Service, starting all internal goroutines needed by the
+// Start implements node.Lifecycle, starting all internal goroutines needed by the
// Ethereum protocol implementation.
func (s *Ethereum) Start() error {
s.startEthEntryUpdate(s.p2pServer.LocalNode())
@@ -580,7 +580,7 @@ func (s *Ethereum) Start() error {
return nil
}
-// Stop implements node.Service, terminating all internal goroutines used by the
+// Stop implements node.Lifecycle, terminating all internal goroutines used by the
// Ethereum protocol.
func (s *Ethereum) Stop() error {
// Stop all the peer-related stuff first.
diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go
index 518a38788e57..c1d98f020279 100644
--- a/ethclient/ethclient_test.go
+++ b/ethclient/ethclient_test.go
@@ -188,15 +188,19 @@ func newTestBackend(t *testing.T) (*node.Node, []*types.Block) {
// Generate test chain.
genesis, blocks := generateTestChain()
- // Start Ethereum service.
- var ethservice *eth.Ethereum
+ // Create node
n, err := node.New(&node.Config{})
- n.Register(func(ctx *node.ServiceContext) (node.Service, error) {
- config := ð.Config{Genesis: genesis}
- config.Ethash.PowMode = ethash.ModeFake
- ethservice, err = eth.New(ctx, config)
- return ethservice, err
- })
+ if err != nil {
+ t.Fatalf("can't create new node: %v", err)
+ }
+
+ // Create Ethereum Service
+ config := ð.Config{Genesis: genesis}
+ config.Ethash.PowMode = ethash.ModeFake
+ ethservice, err := eth.New(n, config)
+ if err != nil {
+ t.Fatalf("can't create new ethereum service: %v", err)
+ }
// Import the test chain.
if err := n.Start(); err != nil {
diff --git a/ethstats/ethstats.go b/ethstats/ethstats.go
index bada875b0bbb..594c844d1e59 100644
--- a/ethstats/ethstats.go
+++ b/ethstats/ethstats.go
@@ -111,7 +111,7 @@ func New(node *node.Node, ethBackend *eth.Ethereum, lesBackend *les.LightEthereu
return nil
}
-// Start implements node.Service, starting up the monitoring and reporting daemon.
+// Start implements node.Lifecycle, starting up the monitoring and reporting daemon.
func (s *Service) Start() error {
go s.loop()
@@ -119,7 +119,7 @@ func (s *Service) Start() error {
return nil
}
-// Stop implements node.Service, terminating the monitoring and reporting daemon.
+// Stop implements node.Lifecycle, terminating the monitoring and reporting daemon.
func (s *Service) Stop() error {
log.Info("Stats daemon stopped")
return nil
diff --git a/les/api_test.go b/les/api_test.go
index 06a519b62bed..6a4a2565c5fd 100644
--- a/les/api_test.go
+++ b/les/api_test.go
@@ -492,11 +492,11 @@ func testSim(t *testing.T, serverCount, clientCount int, serverDir, clientDir []
return test(ctx, net, servers, clients)
}
-func newLesClientService(ctx *adapters.ServiceContext) (node.Service, error) {
+func newLesClientService(ctx *adapters.ServiceContext, stack *node.Node) (*LightEthereum, error) {
config := eth.DefaultConfig
config.SyncMode = downloader.LightSync
config.Ethash.PowMode = ethash.ModeFake
- return New(ctx.NodeContext, &config)
+ return New(stack, &config)
}
func newLesServerService(ctx *adapters.ServiceContext) (node.Service, error) {
From 1f5f52e073fef0850df76e41259b45788d8c08e9 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Tue, 19 May 2020 17:17:33 +0200
Subject: [PATCH 034/160] WIP, trying to remove node.Service from tests
---
les/api_test.go | 4 +-
les/client.go | 7 ++-
miner/stress_clique.go | 40 ++++++++---------
miner/stress_ethash.go | 41 +++++++++---------
mobile/geth.go | 16 ++-----
node/node_example_test.go | 30 ++++---------
node/node_test.go | 15 +++----
node/utils_test.go | 83 +++++++++---------------------------
whisper/whisperv6/whisper.go | 4 +-
9 files changed, 87 insertions(+), 153 deletions(-)
diff --git a/les/api_test.go b/les/api_test.go
index 6a4a2565c5fd..d6571fabe88f 100644
--- a/les/api_test.go
+++ b/les/api_test.go
@@ -499,12 +499,12 @@ func newLesClientService(ctx *adapters.ServiceContext, stack *node.Node) (*Light
return New(stack, &config)
}
-func newLesServerService(ctx *adapters.ServiceContext) (node.Service, error) {
+func newLesServerService(ctx *adapters.ServiceContext, stack *node.Node) (*eth.Ethereum, error) {
config := eth.DefaultConfig
config.SyncMode = downloader.FullSync
config.LightServ = testServerCapacity
config.LightPeers = testMaxClients
- ethereum, err := eth.New(ctx.NodeContext, &config)
+ ethereum, err := eth.New(stack, &config)
if err != nil {
return nil, err
}
diff --git a/les/client.go b/les/client.go
index 351cc952968f..58d5606ae903 100644
--- a/les/client.go
+++ b/les/client.go
@@ -272,8 +272,7 @@ func (s *LightEthereum) LesVersion() int { return int(ClientP
func (s *LightEthereum) Downloader() *downloader.Downloader { return s.handler.downloader }
func (s *LightEthereum) EventMux() *event.TypeMux { return s.eventMux }
-// Protocols implements node.Service, returning all the currently configured
-// network protocols to start.
+// Protocols returns all the currently configured network protocols to start.
func (s *LightEthereum) Protocols() []p2p.Protocol {
return s.makeProtocols(ClientProtocolVersions, s.handler.runPeer, func(id enode.ID) interface{} {
if p := s.peers.peer(id.String()); p != nil {
@@ -292,7 +291,7 @@ func (s *LightEthereum) P2PServer(server *p2p.Server) error {
return nil
}
-// Start implements node.Service, starting all internal goroutines needed by the
+// Start implements node.Lifecycle, starting all internal goroutines needed by the
// light ethereum protocol implementation.
func (s *LightEthereum) Start() error {
log.Warn("Light client mode is an experimental feature")
@@ -311,7 +310,7 @@ func (s *LightEthereum) Start() error {
return nil
}
-// Stop implements node.Service, terminating all internal goroutines used by the
+// Stop implements node.Lifecycle, terminating all internal goroutines used by the
// Ethereum protocol.
func (s *LightEthereum) Stop() error {
close(s.closeCh)
diff --git a/miner/stress_clique.go b/miner/stress_clique.go
index 2f8a28b68fa3..a3a63e38c45a 100644
--- a/miner/stress_clique.go
+++ b/miner/stress_clique.go
@@ -35,9 +35,7 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth"
- "github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/enode"
@@ -98,7 +96,7 @@ func main() {
for _, node := range nodes {
var ethereum *eth.Ethereum
- if err := node.Service(ðereum); err != nil {
+ if err := node.Lifecycle(ðereum); err != nil { // TODO does this work?
panic(err)
}
if err := ethereum.StartMining(1); err != nil {
@@ -191,25 +189,27 @@ func makeSealer(genesis *core.Genesis) (*node.Node, error) {
if err != nil {
return nil, err
}
- if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
- return eth.New(ctx, ð.Config{
- Genesis: genesis,
- NetworkId: genesis.Config.ChainID.Uint64(),
- SyncMode: downloader.FullSync,
- DatabaseCache: 256,
- DatabaseHandles: 256,
- TxPool: core.DefaultTxPoolConfig,
- GPO: eth.DefaultConfig.GPO,
- Miner: miner.Config{
- GasFloor: genesis.GasLimit * 9 / 10,
- GasCeil: genesis.GasLimit * 11 / 10,
- GasPrice: big.NewInt(1),
- Recommit: time.Second,
- },
- })
- }); err != nil {
+ // Create and register the backend
+ ethBackend, err := eth.New(ctx, ð.Config{
+ Genesis: genesis,
+ NetworkId: genesis.Config.ChainID.Uint64(),
+ SyncMode: downloader.FullSync,
+ DatabaseCache: 256,
+ DatabaseHandles: 256,
+ TxPool: core.DefaultTxPoolConfig,
+ GPO: eth.DefaultConfig.GPO,
+ Miner: miner.Config{
+ GasFloor: genesis.GasLimit * 9 / 10,
+ GasCeil: genesis.GasLimit * 11 / 10,
+ GasPrice: big.NewInt(1),
+ Recommit: time.Second,
+ },
+ })
+ if err != nil {
return nil, err
}
+ stack.RegisterLifecycle(ethBackend)
+
// Start the node and return if successful
return stack, stack.Start()
}
diff --git a/miner/stress_ethash.go b/miner/stress_ethash.go
index 94d5b30aa5b8..ed999f90cec4 100644
--- a/miner/stress_ethash.go
+++ b/miner/stress_ethash.go
@@ -94,7 +94,7 @@ func main() {
for _, node := range nodes {
var ethereum *eth.Ethereum
- if err := node.Service(ðereum); err != nil {
+ if err := node.Lifecycle(ðereum); err != nil { // TODO does this work?
panic(err)
}
if err := ethereum.StartMining(1); err != nil {
@@ -165,31 +165,32 @@ func makeMiner(genesis *core.Genesis) (*node.Node, error) {
NoUSB: true,
UseLightweightKDF: true,
}
- // Start the node and configure a full Ethereum node on it
+ // Create the node and configure a full Ethereum node on it
stack, err := node.New(config)
if err != nil {
return nil, err
}
- if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
- return eth.New(ctx, ð.Config{
- Genesis: genesis,
- NetworkId: genesis.Config.ChainID.Uint64(),
- SyncMode: downloader.FullSync,
- DatabaseCache: 256,
- DatabaseHandles: 256,
- TxPool: core.DefaultTxPoolConfig,
- GPO: eth.DefaultConfig.GPO,
- Ethash: eth.DefaultConfig.Ethash,
- Miner: miner.Config{
- GasFloor: genesis.GasLimit * 9 / 10,
- GasCeil: genesis.GasLimit * 11 / 10,
- GasPrice: big.NewInt(1),
- Recommit: time.Second,
- },
- })
- }); err != nil {
+ ethBackend, err := eth.New(ctx, ð.Config{
+ Genesis: genesis,
+ NetworkId: genesis.Config.ChainID.Uint64(),
+ SyncMode: downloader.FullSync,
+ DatabaseCache: 256,
+ DatabaseHandles: 256,
+ TxPool: core.DefaultTxPoolConfig,
+ GPO: eth.DefaultConfig.GPO,
+ Ethash: eth.DefaultConfig.Ethash,
+ Miner: miner.Config{
+ GasFloor: genesis.GasLimit * 9 / 10,
+ GasCeil: genesis.GasLimit * 11 / 10,
+ GasPrice: big.NewInt(1),
+ Recommit: time.Second,
+ },
+ })
+ if err != nil {
return nil, err
}
+ stack.RegisterLifecycle(ethBackend)
+
// Start the node and return if successful
return stack, stack.Start()
}
diff --git a/mobile/geth.go b/mobile/geth.go
index f20243426b5f..d93b9f1cd0cc 100644
--- a/mobile/geth.go
+++ b/mobile/geth.go
@@ -175,28 +175,20 @@ func NewNode(datadir string, config *NodeConfig) (stack *Node, _ error) {
ethConf.SyncMode = downloader.LightSync
ethConf.NetworkId = uint64(config.EthereumNetworkID)
ethConf.DatabaseCache = config.EthereumDatabaseCache
- if err := rawStack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
- return les.New(ctx, ðConf)
- }); err != nil {
+ lesBackend, err := les.New(rawStack, ðConf)
+ if err != nil {
return nil, fmt.Errorf("ethereum init: %v", err)
}
// If netstats reporting is requested, do it
if config.EthereumNetStats != "" {
- if err := rawStack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
- var lesServ *les.LightEthereum
- ctx.Service(&lesServ)
-
- return ethstats.New(config.EthereumNetStats, nil, lesServ)
- }); err != nil {
+ if err := ethstats.New(rawStack, nil, lesBackend, config.EthereumNetStats); err != nil {
return nil, fmt.Errorf("netstats init: %v", err)
}
}
}
// Register the Whisper protocol if requested
if config.WhisperEnabled {
- if err := rawStack.Register(func(*node.ServiceContext) (node.Service, error) {
- return whisper.New(&whisper.DefaultConfig), nil
- }); err != nil {
+ if err := whisper.New(rawStack, &whisper.DefaultConfig); err != nil {
return nil, fmt.Errorf("whisper init: %v", err)
}
}
diff --git a/node/node_example_test.go b/node/node_example_test.go
index 57b18855f1ed..ccaa3d990f53 100644
--- a/node/node_example_test.go
+++ b/node/node_example_test.go
@@ -21,24 +21,18 @@ import (
"log"
"github.com/ethereum/go-ethereum/node"
- "github.com/ethereum/go-ethereum/p2p"
- "github.com/ethereum/go-ethereum/rpc"
)
-// SampleService is a trivial network service that can be attached to a node for
+// SampleLifecycle is a trivial network service that can be attached to a node for
// life cycle management.
//
-// The following methods are needed to implement a node.Service:
-// - Protocols() []p2p.Protocol - devp2p protocols the service can communicate on
-// - APIs() []rpc.API - api methods the service wants to expose on rpc channels
+// The following methods are needed to implement a node.Lifecycle:
// - Start() error - method invoked when the node is ready to start the service
// - Stop() error - method invoked when the node terminates the service
-type SampleService struct{}
+type SampleLifecycle struct{}
-func (s *SampleService) Protocols() []p2p.Protocol { return nil }
-func (s *SampleService) APIs() []rpc.API { return nil }
-func (s *SampleService) Start(*p2p.Server) error { fmt.Println("Service starting..."); return nil }
-func (s *SampleService) Stop() error { fmt.Println("Service stopping..."); return nil }
+func (s *SampleLifecycle) Start() error { fmt.Println("Service starting..."); return nil }
+func (s *SampleLifecycle) Stop() error { fmt.Println("Service stopping..."); return nil }
func ExampleService() {
// Create a network node to run protocols with the default values.
@@ -48,16 +42,10 @@ func ExampleService() {
}
defer stack.Close()
- // Create and register a simple network service. This is done through the definition
- // of a node.ServiceConstructor that will instantiate a node.Service. The reason for
- // the factory method approach is to support service restarts without relying on the
- // individual implementations' support for such operations.
- constructor := func(context *node.ServiceContext) (node.Service, error) {
- return new(SampleService), nil
- }
- if err := stack.Register(constructor); err != nil {
- log.Fatalf("Failed to register service: %v", err)
- }
+ // Create and register a simple network Lifecycle.
+ service := new(SampleLifecycle)
+ stack.RegisterLifecycle(service)
+
// Boot up the entire protocol stack, do a restart and terminate
if err := stack.Start(); err != nil {
log.Fatalf("Failed to start the protocol stack: %v", err)
diff --git a/node/node_test.go b/node/node_test.go
index d62194a87681..b5dc12f54f62 100644
--- a/node/node_test.go
+++ b/node/node_test.go
@@ -121,12 +121,8 @@ func TestServiceRegistry(t *testing.T) {
defer stack.Close()
// Register a batch of unique services and ensure they start successfully
- services := []ServiceConstructor{NewNoopServiceA, NewNoopServiceB, NewNoopServiceC}
- for i, constructor := range services {
- if err := stack.Register(constructor); err != nil {
- t.Fatalf("service #%d: registration failed: %v", i, err)
- }
- }
+ noop, err := NewNoop(stack)
+
if err := stack.Start(); err != nil {
t.Fatalf("failed to start original service stack: %v", err)
}
@@ -134,9 +130,10 @@ func TestServiceRegistry(t *testing.T) {
t.Fatalf("failed to stop original service stack: %v", err)
}
// Duplicate one of the services and retry starting the node
- if err := stack.Register(NewNoopServiceB); err != nil {
- t.Fatalf("duplicate registration failed: %v", err)
- }
+ stack.RegisterLifecycle(noop) // TODO how to test for a fatal err ?
+ //err != nil {
+ // t.Fatalf("duplicate registration failed: %v", err)
+ //}
if err := stack.Start(); err == nil {
t.Fatalf("duplicate service started")
} else {
diff --git a/node/utils_test.go b/node/utils_test.go
index 9801b1ed4565..0484ee035708 100644
--- a/node/utils_test.go
+++ b/node/utils_test.go
@@ -20,31 +20,29 @@
package node
import (
- "reflect"
-
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/rpc"
)
// NoopService is a trivial implementation of the Service interface.
-type NoopService struct{}
+type NoopLifecycle struct{}
-func (s *NoopService) Protocols() []p2p.Protocol { return nil }
-func (s *NoopService) APIs() []rpc.API { return nil }
-func (s *NoopService) Start(*p2p.Server) error { return nil }
-func (s *NoopService) Stop() error { return nil }
+func (s *NoopLifecycle) Start() error { return nil }
+func (s *NoopLifecycle) Stop() error { return nil }
-func NewNoopService(*ServiceContext) (Service, error) { return new(NoopService), nil }
+func NewNoop(stack *Node) (*Noop, error) {
+ noop := new(Noop)
+ stack.RegisterLifecycle(noop)
+ return noop, nil
+}
// Set of services all wrapping the base NoopService resulting in the same method
// signatures but different outer types.
-type NoopServiceA struct{ NoopService }
-type NoopServiceB struct{ NoopService }
-type NoopServiceC struct{ NoopService }
+type Noop struct{ NoopLifecycle }
-func NewNoopServiceA(*ServiceContext) (Service, error) { return new(NoopServiceA), nil }
-func NewNoopServiceB(*ServiceContext) (Service, error) { return new(NoopServiceB), nil }
-func NewNoopServiceC(*ServiceContext) (Service, error) { return new(NoopServiceC), nil }
+//func NewNoopServiceA(*ServiceContext) (Lifecycle, error) { return new(NoopServiceA), nil }
+//func NewNoopServiceB(*ServiceContext) (Lifecycle, error) { return new(NoopServiceB), nil }
+//func NewNoopServiceC(*ServiceContext) (Lifecycle, error) { return new(NoopServiceC), nil }
// InstrumentedService is an implementation of Service for which all interface
// methods can be instrumented both return value as well as event hook wise.
@@ -54,12 +52,17 @@ type InstrumentedService struct {
start error
stop error
+ server *p2p.Server
+
protocolsHook func()
startHook func(*p2p.Server)
stopHook func()
}
-func NewInstrumentedService(*ServiceContext) (Service, error) { return new(InstrumentedService), nil }
+func NewInstrumentedService(server *p2p.Server) (Lifecycle, error) {
+ is := &InstrumentedService{ server: server }
+ return is, nil
+}
func (s *InstrumentedService) Protocols() []p2p.Protocol {
if s.protocolsHook != nil {
@@ -72,9 +75,9 @@ func (s *InstrumentedService) APIs() []rpc.API {
return s.apis
}
-func (s *InstrumentedService) Start(server *p2p.Server) error {
+func (s *InstrumentedService) Start() error {
if s.startHook != nil {
- s.startHook(server)
+ s.startHook(s.server)
}
return s.start
}
@@ -85,49 +88,3 @@ func (s *InstrumentedService) Stop() error {
}
return s.stop
}
-
-// InstrumentingWrapper is a method to specialize a service constructor returning
-// a generic InstrumentedService into one returning a wrapping specific one.
-type InstrumentingWrapper func(base ServiceConstructor) ServiceConstructor
-
-func InstrumentingWrapperMaker(base ServiceConstructor, kind reflect.Type) ServiceConstructor {
- return func(ctx *ServiceContext) (Service, error) {
- obj, err := base(ctx)
- if err != nil {
- return nil, err
- }
- wrapper := reflect.New(kind)
- wrapper.Elem().Field(0).Set(reflect.ValueOf(obj).Elem())
-
- return wrapper.Interface().(Service), nil
- }
-}
-
-// Set of services all wrapping the base InstrumentedService resulting in the
-// same method signatures but different outer types.
-type InstrumentedServiceA struct{ InstrumentedService }
-type InstrumentedServiceB struct{ InstrumentedService }
-type InstrumentedServiceC struct{ InstrumentedService }
-
-func InstrumentedServiceMakerA(base ServiceConstructor) ServiceConstructor {
- return InstrumentingWrapperMaker(base, reflect.TypeOf(InstrumentedServiceA{}))
-}
-
-func InstrumentedServiceMakerB(base ServiceConstructor) ServiceConstructor {
- return InstrumentingWrapperMaker(base, reflect.TypeOf(InstrumentedServiceB{}))
-}
-
-func InstrumentedServiceMakerC(base ServiceConstructor) ServiceConstructor {
- return InstrumentingWrapperMaker(base, reflect.TypeOf(InstrumentedServiceC{}))
-}
-
-// OneMethodAPI is a single-method API handler to be returned by test services.
-type OneMethodAPI struct {
- fun func()
-}
-
-func (api *OneMethodAPI) TheOneMethod() {
- if api.fun != nil {
- api.fun()
- }
-}
diff --git a/whisper/whisperv6/whisper.go b/whisper/whisperv6/whisper.go
index 8613893eb4a8..af848d2fdc79 100644
--- a/whisper/whisperv6/whisper.go
+++ b/whisper/whisperv6/whisper.go
@@ -641,7 +641,7 @@ func (whisper *Whisper) Send(envelope *Envelope) error {
return err
}
-// Start implements node.Service, starting the background data propagation thread
+// Start implements node.Lifecycle, starting the background data propagation thread
// of the Whisper protocol.
func (whisper *Whisper) Start() error {
log.Info("started whisper v." + ProtocolVersionStr)
@@ -657,7 +657,7 @@ func (whisper *Whisper) Start() error {
return nil
}
-// Stop implements node.Service, stopping the background data propagation thread
+// Stop implements node.Lifecycle, stopping the background data propagation thread
// of the Whisper protocol.
func (whisper *Whisper) Stop() error {
close(whisper.quit)
From 5866e01c2b7cfcca4cc53405e07a1a1497029b4c Mon Sep 17 00:00:00 2001
From: rene <41963722+renaynay@users.noreply.github.com>
Date: Mon, 25 May 2020 14:55:24 +0200
Subject: [PATCH 035/160] fixes node tests (#18)
---
node/errors.go | 11 -
node/node.go | 69 ++---
node/node_example_test.go | 7 +-
node/node_test.go | 540 +++++++++++---------------------------
node/rpcstack_test.go | 7 +-
node/service.go | 20 +-
node/service_test.go | 45 ++--
node/utils_test.go | 46 +---
p2p/server.go | 4 +-
9 files changed, 247 insertions(+), 502 deletions(-)
diff --git a/node/errors.go b/node/errors.go
index 2e0dadc4d6b3..67547bf691f1 100644
--- a/node/errors.go
+++ b/node/errors.go
@@ -39,17 +39,6 @@ func convertFileLockError(err error) error {
return err
}
-// DuplicateServiceError is returned during Node startup if a registered service
-// constructor returns a service of the same type that was already started.
-type DuplicateServiceError struct {
- Kind reflect.Type
-}
-
-// Error generates a textual representation of the duplicate service error.
-func (e *DuplicateServiceError) Error() string {
- return fmt.Sprintf("duplicate service: %v", e.Kind)
-}
-
// StopError is returned if a Node fails to stop either any of its registered
// services or itself.
type StopError struct {
diff --git a/node/node.go b/node/node.go
index 2b477c616f25..6a94f1c0dee7 100644
--- a/node/node.go
+++ b/node/node.go
@@ -53,7 +53,7 @@ type Node struct {
ServiceContext *ServiceContext
- lifecycles []Lifecycle // All registered backends, services, and auxiliary services that have a lifecycle
+ lifecycles map[reflect.Type]Lifecycle // All registered backends, services, and auxiliary services that have a lifecycle
rpcAPIs []rpc.API // List of APIs currently provided by the node
inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
@@ -107,8 +107,10 @@ func New(conf *Config) (*Node, error) {
accman: am,
ephemeralKeystore: ephemeralKeystore,
config: conf,
+ lifecycles: make(map[reflect.Type]Lifecycle),
ServiceContext: &ServiceContext{
Config: *conf,
+ Lifecycles: make(map[reflect.Type]Lifecycle),
},
httpServers: make([]*HTTPServer, 0),
ipc: &HTTPServer{
@@ -199,12 +201,12 @@ func (n *Node) Close() error {
// RegisterLifecycle registers the given Lifecycle on the node
func (n *Node) RegisterLifecycle(lifecycle Lifecycle) {
- for _, existing := range n.lifecycles {
- if existing == lifecycle {
- Fatalf("Lifecycle cannot be registered more than once", lifecycle)
- }
+ kind := reflect.TypeOf(lifecycle)
+ if _, exists := n.lifecycles[kind]; exists {
+ Fatalf("Lifecycle cannot be registered more than once", kind)
}
- n.lifecycles = append(n.lifecycles, lifecycle)
+
+ n.lifecycles[kind] = lifecycle
}
// RegisterProtocols adds backend's protocols to the node's p2p server
@@ -265,7 +267,7 @@ func (n *Node) CreateHTTPServer(h *HTTPServer, exposeAll bool) error {
// running returns true if the node's p2p server is already running
func (n *Node) running() bool {
- return n.server.Listening()
+ return n.server.Running()
}
// Start creates a live P2P node and starts running it.
@@ -289,9 +291,8 @@ func (n *Node) Start() error {
// TODO running p2p server needs to somehow be added to the backend
- // Start the configured RPC interfaces
- if err := n.startRPC(); err != nil {
- n.stopLifecycles(n.lifecycles)
+ // Configure the RPC interfaces
+ if err := n.configureRPC(); err != nil {
n.server.Stop()
return err
}
@@ -301,8 +302,11 @@ func (n *Node) Start() error {
for _, lifecycle := range n.lifecycles {
if err := lifecycle.Start(); err != nil {
n.stopLifecycles(started)
+ n.server.Stop()
+ return err
}
started = append(started, lifecycle)
+ n.ServiceContext.Lifecycles[reflect.TypeOf(lifecycle)] = lifecycle
}
// Finish initializing the service context
@@ -478,15 +482,7 @@ func (n *Node) stopServer(server *HTTPServer) {
// removeLifecycle removes a stopped Lifecycle from the running node's Lifecycles
func (n *Node) removeLifecycle(lifecycle Lifecycle) {
- remainingLifecycles := make([]Lifecycle, len(n.lifecycles)-1)
- index := 0
- for _, remaining := range n.lifecycles {
- if remaining != lifecycle {
- remainingLifecycles[index] = remaining
- index ++
- }
- }
- n.lifecycles = remainingLifecycles
+ delete(n.lifecycles, reflect.TypeOf(lifecycle))
}
// Stop terminates a running node along with all it's services. In the node was
@@ -496,7 +492,7 @@ func (n *Node) Stop() error {
defer n.lock.Unlock()
// Short circuit if the node's not running
- if n.server == nil {
+ if n.server == nil || !n.running() {
return ErrNodeStopped
}
@@ -506,10 +502,11 @@ func (n *Node) Stop() error {
failure := &StopError{
Services: make(map[reflect.Type]error),
}
- for _, lifecycle := range n.lifecycles {
+ for kind, lifecycle := range n.lifecycles {
if err := lifecycle.Stop(); err != nil {
failure.Services[reflect.TypeOf(lifecycle)] = err
}
+ delete(n.lifecycles, kind)
}
n.server.Stop()
n.server = nil
@@ -554,18 +551,6 @@ func (n *Node) Wait() {
<-stop
}
-// Restart terminates a running node and boots up a new one in its place. If the
-// node isn't running, an error is returned.
-func (n *Node) Restart() error {
- if err := n.Stop(); err != nil {
- return err
- }
- if err := n.Start(); err != nil {
- return err
- }
- return nil
-}
-
// Attach creates an RPC client attached to an in-process API handler.
func (n *Node) Attach() (*rpc.Client, error) {
n.lock.RLock()
@@ -695,6 +680,24 @@ func (n *Node) ResolvePath(x string) string {
return n.config.ResolvePath(x)
}
+// Lifecycle retrieves a currently running Lifecycle registered of a specific type.
+func (n *Node) Lifecycle(lifecycle interface{}) error {
+ n.lock.RLock()
+ defer n.lock.RUnlock()
+
+ // Short circuit if the node's not running
+ if !n.running() {
+ return ErrNodeStopped
+ }
+ // Otherwise try to find the service to return
+ element := reflect.ValueOf(lifecycle).Elem()
+ if running, ok := n.lifecycles[element.Type()]; ok {
+ element.Set(reflect.ValueOf(running))
+ return nil
+ }
+ return ErrServiceUnknown
+}
+
// apis returns the collection of RPC descriptors this node offers.
func (n *Node) apis() []rpc.API {
return []rpc.API{
diff --git a/node/node_example_test.go b/node/node_example_test.go
index ccaa3d990f53..9363bbc18379 100644
--- a/node/node_example_test.go
+++ b/node/node_example_test.go
@@ -34,7 +34,7 @@ type SampleLifecycle struct{}
func (s *SampleLifecycle) Start() error { fmt.Println("Service starting..."); return nil }
func (s *SampleLifecycle) Stop() error { fmt.Println("Service stopping..."); return nil }
-func ExampleService() {
+func ExampleLifecycle() {
// Create a network node to run protocols with the default values.
stack, err := node.New(&node.Config{})
if err != nil {
@@ -50,15 +50,10 @@ func ExampleService() {
if err := stack.Start(); err != nil {
log.Fatalf("Failed to start the protocol stack: %v", err)
}
- if err := stack.Restart(); err != nil {
- log.Fatalf("Failed to restart the protocol stack: %v", err)
- }
if err := stack.Stop(); err != nil {
log.Fatalf("Failed to stop the protocol stack: %v", err)
}
// Output:
// Service starting...
// Service stopping...
- // Service starting...
- // Service stopping...
}
diff --git a/node/node_test.go b/node/node_test.go
index b5dc12f54f62..e8764f1ab383 100644
--- a/node/node_test.go
+++ b/node/node_test.go
@@ -23,11 +23,9 @@ import (
"os"
"reflect"
"testing"
- "time"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/p2p"
- "github.com/ethereum/go-ethereum/rpc"
"github.com/stretchr/testify/assert"
)
@@ -43,7 +41,7 @@ func testNodeConfig() *Config {
}
}
-// Tests that an empty protocol stack can be started, restarted and stopped.
+// Tests that an empty protocol stack can be started and stopped.
func TestNodeLifeCycle(t *testing.T) {
stack, err := New(testNodeConfig())
if err != nil {
@@ -64,12 +62,6 @@ func TestNodeLifeCycle(t *testing.T) {
if err := stack.Start(); err != ErrNodeRunning {
t.Fatalf("start failure mismatch: have %v, want %v ", err, ErrNodeRunning)
}
- // Ensure that a node can be restarted arbitrarily many times
- for i := 0; i < 3; i++ {
- if err := stack.Restart(); err != nil {
- t.Fatalf("iter %d: failed to restart node: %v", i, err)
- }
- }
// Ensure that a node can be stopped, but only once
if err := stack.Stop(); err != nil {
t.Fatalf("failed to stop node: %v", err)
@@ -112,71 +104,63 @@ func TestNodeUsedDataDir(t *testing.T) {
}
}
-// Tests whether services can be registered and duplicates caught.
-func TestServiceRegistry(t *testing.T) {
+// Tests whether a Lifecycle can be registered.
+func TestLifecycleRegistry(t *testing.T) {
stack, err := New(testNodeConfig())
if err != nil {
t.Fatalf("failed to create protocol stack: %v", err)
}
defer stack.Close()
- // Register a batch of unique services and ensure they start successfully
- noop, err := NewNoop(stack)
+ noop := NewNoop()
+ stack.RegisterLifecycle(noop)
- if err := stack.Start(); err != nil {
- t.Fatalf("failed to start original service stack: %v", err)
- }
- if err := stack.Stop(); err != nil {
- t.Fatalf("failed to stop original service stack: %v", err)
- }
- // Duplicate one of the services and retry starting the node
- stack.RegisterLifecycle(noop) // TODO how to test for a fatal err ?
- //err != nil {
- // t.Fatalf("duplicate registration failed: %v", err)
- //}
- if err := stack.Start(); err == nil {
- t.Fatalf("duplicate service started")
- } else {
- if _, ok := err.(*DuplicateServiceError); !ok {
- t.Fatalf("duplicate error mismatch: have %v, want %v", err, DuplicateServiceError{})
- }
+ if _, exists := stack.lifecycles[reflect.TypeOf(noop)]; !exists {
+ t.Fatalf("lifecycle was not properly registered on the node, %v", err)
}
}
-// Tests that registered services get started and stopped correctly.
-func TestServiceLifeCycle(t *testing.T) {
+// Tests that registered Lifecycles get started and stopped correctly.
+func TestLifecycleLifeCycle(t *testing.T) {
stack, err := New(testNodeConfig())
if err != nil {
t.Fatalf("failed to create protocol stack: %v", err)
}
defer stack.Close()
- // Register a batch of life-cycle instrumented services
- services := map[string]InstrumentingWrapper{
- "A": InstrumentedServiceMakerA,
- "B": InstrumentedServiceMakerB,
- "C": InstrumentedServiceMakerC,
- }
started := make(map[string]bool)
stopped := make(map[string]bool)
- for id, maker := range services {
- id := id // Closure for the constructor
- constructor := func(*ServiceContext) (Service, error) {
- return &InstrumentedService{
- startHook: func(*p2p.Server) { started[id] = true },
- stopHook: func() { stopped[id] = true },
- }, nil
- }
- if err := stack.Register(maker(constructor)); err != nil {
- t.Fatalf("service %s: registration failed: %v", id, err)
- }
+ // Create a batch of instrumented services
+ lifecycles := map[string]Lifecycle{
+ "A": &InstrumentedServiceA{
+ InstrumentedService{
+ startHook: func() { started["A"] = true },
+ stopHook: func() { stopped["A"] = true },
+ },
+ },
+ "B": &InstrumentedServiceB{
+ InstrumentedService{
+ startHook: func() { started["B"] = true },
+ stopHook: func() { stopped["B"] = true },
+ },
+ },
+ "C": &InstrumentedServiceC{
+ InstrumentedService{
+ startHook: func() { started["C"] = true },
+ stopHook: func() { stopped["C"] = true },
+ },
+ },
+ }
+ // register lifecycles on node
+ for _, lifecycle := range lifecycles {
+ stack.RegisterLifecycle(lifecycle)
}
// Start the node and check that all services are running
if err := stack.Start(); err != nil {
t.Fatalf("failed to start protocol stack: %v", err)
}
- for id := range services {
+ for id := range lifecycles {
if !started[id] {
t.Fatalf("service %s: freshly started service not running", id)
}
@@ -188,157 +172,62 @@ func TestServiceLifeCycle(t *testing.T) {
if err := stack.Stop(); err != nil {
t.Fatalf("failed to stop protocol stack: %v", err)
}
- for id := range services {
+ for id := range lifecycles {
if !stopped[id] {
t.Fatalf("service %s: freshly terminated service still running", id)
}
}
}
-// Tests that services are restarted cleanly as new instances.
-func TestServiceRestarts(t *testing.T) {
+// Tests that if a Lifecycle fails to start, all others started before it will be
+// shut down.
+func TestLifecycleStartupAbortion(t *testing.T) {
stack, err := New(testNodeConfig())
if err != nil {
t.Fatalf("failed to create protocol stack: %v", err)
}
defer stack.Close()
- // Define a service that does not support restarts
- var (
- running bool
- started int
- )
- constructor := func(*ServiceContext) (Service, error) {
- running = false
-
- return &InstrumentedService{
- startHook: func(*p2p.Server) {
- if running {
- panic("already running")
- }
- running = true
- started++
- },
- }, nil
- }
- // Register the service and start the protocol stack
- if err := stack.Register(constructor); err != nil {
- t.Fatalf("failed to register the service: %v", err)
- }
- if err := stack.Start(); err != nil {
- t.Fatalf("failed to start protocol stack: %v", err)
- }
- defer stack.Stop()
+ started := make(map[string]bool)
+ stopped := make(map[string]bool)
- if !running || started != 1 {
- t.Fatalf("running/started mismatch: have %v/%d, want true/1", running, started)
- }
- // Restart the stack a few times and check successful service restarts
- for i := 0; i < 3; i++ {
- if err := stack.Restart(); err != nil {
- t.Fatalf("iter %d: failed to restart stack: %v", i, err)
- }
- }
- if !running || started != 4 {
- t.Fatalf("running/started mismatch: have %v/%d, want true/4", running, started)
+ // Create a batch of instrumented services
+ lifecycles := map[string]Lifecycle{
+ "A": &InstrumentedServiceA{
+ InstrumentedService{
+ startHook: func() { started["A"] = true },
+ stopHook: func() { stopped["A"] = true },
+ },
+ },
+ "B": &InstrumentedServiceB{
+ InstrumentedService{
+ startHook: func() { started["B"] = true },
+ stopHook: func() { stopped["B"] = true },
+ },
+ },
+ "C": &InstrumentedServiceC{
+ InstrumentedService{
+ startHook: func() { started["C"] = true },
+ stopHook: func() { stopped["C"] = true },
+ },
+ },
}
-}
-
-// Tests that if a service fails to initialize itself, none of the other services
-// will be allowed to even start.
-func TestServiceConstructionAbortion(t *testing.T) {
- stack, err := New(testNodeConfig())
- if err != nil {
- t.Fatalf("failed to create protocol stack: %v", err)
+ // register lifecycles on node
+ for _, lifecycle := range lifecycles {
+ stack.RegisterLifecycle(lifecycle)
}
- defer stack.Close()
- // Define a batch of good services
- services := map[string]InstrumentingWrapper{
- "A": InstrumentedServiceMakerA,
- "B": InstrumentedServiceMakerB,
- "C": InstrumentedServiceMakerC,
- }
- started := make(map[string]bool)
- for id, maker := range services {
- id := id // Closure for the constructor
- constructor := func(*ServiceContext) (Service, error) {
- return &InstrumentedService{
- startHook: func(*p2p.Server) { started[id] = true },
- }, nil
- }
- if err := stack.Register(maker(constructor)); err != nil {
- t.Fatalf("service %s: registration failed: %v", id, err)
- }
- }
// Register a service that fails to construct itself
failure := errors.New("fail")
- failer := func(*ServiceContext) (Service, error) {
- return nil, failure
- }
- if err := stack.Register(failer); err != nil {
- t.Fatalf("failer registration failed: %v", err)
- }
- // Start the protocol stack and ensure none of the services get started
- for i := 0; i < 100; i++ {
- if err := stack.Start(); err != failure {
- t.Fatalf("iter %d: stack startup failure mismatch: have %v, want %v", i, err, failure)
- }
- for id := range services {
- if started[id] {
- t.Fatalf("service %s: started should not have", id)
- }
- delete(started, id)
- }
- }
-}
+ failer := &InstrumentedService{ start: failure }
+ stack.RegisterLifecycle(failer)
-// Tests that if a service fails to start, all others started before it will be
-// shut down.
-func TestServiceStartupAbortion(t *testing.T) {
- stack, err := New(testNodeConfig())
- if err != nil {
- t.Fatalf("failed to create protocol stack: %v", err)
- }
- defer stack.Close()
-
- // Register a batch of good services
- services := map[string]InstrumentingWrapper{
- "A": InstrumentedServiceMakerA,
- "B": InstrumentedServiceMakerB,
- "C": InstrumentedServiceMakerC,
- }
- started := make(map[string]bool)
- stopped := make(map[string]bool)
-
- for id, maker := range services {
- id := id // Closure for the constructor
- constructor := func(*ServiceContext) (Service, error) {
- return &InstrumentedService{
- startHook: func(*p2p.Server) { started[id] = true },
- stopHook: func() { stopped[id] = true },
- }, nil
- }
- if err := stack.Register(maker(constructor)); err != nil {
- t.Fatalf("service %s: registration failed: %v", id, err)
- }
- }
- // Register a service that fails to start
- failure := errors.New("fail")
- failer := func(*ServiceContext) (Service, error) {
- return &InstrumentedService{
- start: failure,
- }, nil
- }
- if err := stack.Register(failer); err != nil {
- t.Fatalf("failer registration failed: %v", err)
- }
// Start the protocol stack and ensure all started services stop
for i := 0; i < 100; i++ {
if err := stack.Start(); err != failure {
t.Fatalf("iter %d: stack startup failure mismatch: have %v, want %v", i, err, failure)
}
- for id := range services {
+ for id := range lifecycles {
if started[id] && !stopped[id] {
t.Fatalf("service %s: started but not stopped", id)
}
@@ -348,85 +237,89 @@ func TestServiceStartupAbortion(t *testing.T) {
}
}
-// Tests that even if a registered service fails to shut down cleanly, it does
+// Tests that even if a registered Lifecycle fails to shut down cleanly, it does
// not influence the rest of the shutdown invocations.
-func TestServiceTerminationGuarantee(t *testing.T) {
+func TestLifecycleTerminationGuarantee(t *testing.T) {
stack, err := New(testNodeConfig())
if err != nil {
t.Fatalf("failed to create protocol stack: %v", err)
}
defer stack.Close()
- // Register a batch of good services
- services := map[string]InstrumentingWrapper{
- "A": InstrumentedServiceMakerA,
- "B": InstrumentedServiceMakerB,
- "C": InstrumentedServiceMakerC,
- }
started := make(map[string]bool)
stopped := make(map[string]bool)
- for id, maker := range services {
- id := id // Closure for the constructor
- constructor := func(*ServiceContext) (Service, error) {
- return &InstrumentedService{
- startHook: func(*p2p.Server) { started[id] = true },
- stopHook: func() { stopped[id] = true },
- }, nil
- }
- if err := stack.Register(maker(constructor)); err != nil {
- t.Fatalf("service %s: registration failed: %v", id, err)
- }
+ // Create a batch of instrumented services
+ lifecycles := map[string]Lifecycle{
+ "A": &InstrumentedServiceA{
+ InstrumentedService{
+ startHook: func() { started["A"] = true },
+ stopHook: func() { stopped["A"] = true },
+ },
+ },
+ "B": &InstrumentedServiceB{
+ InstrumentedService{
+ startHook: func() { started["B"] = true },
+ stopHook: func() { stopped["B"] = true },
+ },
+ },
+ "C": &InstrumentedServiceC{
+ InstrumentedService{
+ startHook: func() { started["C"] = true },
+ stopHook: func() { stopped["C"] = true },
+ },
+ },
}
+ // register lifecycles on node
+ for _, lifecycle := range lifecycles {
+ stack.RegisterLifecycle(lifecycle)
+ }
+
// Register a service that fails to shot down cleanly
failure := errors.New("fail")
- failer := func(*ServiceContext) (Service, error) {
- return &InstrumentedService{
- stop: failure,
- }, nil
- }
- if err := stack.Register(failer); err != nil {
- t.Fatalf("failer registration failed: %v", err)
+ failer := &InstrumentedService{ stop: failure }
+ stack.RegisterLifecycle(failer)
+
+ // Start the protocol stack, and ensure that a failing shut down terminates all // TODO, deleting loop because constructors no longer stored on node.
+ // Start the stack and make sure all is online
+ if err := stack.Start(); err != nil {
+ t.Fatalf("failed to start protocol stack: %v", err)
}
- // Start the protocol stack, and ensure that a failing shut down terminates all
- for i := 0; i < 100; i++ {
- // Start the stack and make sure all is online
- if err := stack.Start(); err != nil {
- t.Fatalf("iter %d: failed to start protocol stack: %v", i, err)
+ for id := range lifecycles {
+ if !started[id] {
+ t.Fatalf("service %s: service not running", id)
}
- for id := range services {
- if !started[id] {
- t.Fatalf("iter %d, service %s: service not running", i, id)
- }
- if stopped[id] {
- t.Fatalf("iter %d, service %s: service already stopped", i, id)
- }
+ if stopped[id] {
+ t.Fatalf("service %s: service already stopped", id)
}
- // Stop the stack, verify failure and check all terminations
- err := stack.Stop()
- if err, ok := err.(*StopError); !ok {
- t.Fatalf("iter %d: termination failure mismatch: have %v, want StopError", i, err)
- } else {
- failer := reflect.TypeOf(&InstrumentedService{})
- if err.Services[failer] != failure {
- t.Fatalf("iter %d: failer termination failure mismatch: have %v, want %v", i, err.Services[failer], failure)
- }
- if len(err.Services) != 1 {
- t.Fatalf("iter %d: failure count mismatch: have %d, want %d", i, len(err.Services), 1)
- }
+ }
+ // Stop the stack, verify failure and check all terminations
+ err = stack.Stop()
+ if err, ok := err.(*StopError); !ok {
+ t.Fatalf("termination failure mismatch: have %v, want StopError", err)
+ } else {
+ failer := reflect.TypeOf(&InstrumentedService{})
+ if err.Services[failer] != failure {
+ t.Fatalf("failer termination failure mismatch: have %v, want %v", err.Services[failer], failure)
}
- for id := range services {
- if !stopped[id] {
- t.Fatalf("iter %d, service %s: service not terminated", i, id)
- }
- delete(started, id)
- delete(stopped, id)
+ if len(err.Services) != 1 {
+ t.Fatalf("failure count mismatch: have %d, want %d", len(err.Services), 1)
+ }
+ }
+ for id := range lifecycles {
+ if !stopped[id] {
+ t.Fatalf("service %s: service not terminated", id)
}
+ delete(started, id)
+ delete(stopped, id)
}
+
+ stack.server = &p2p.Server{}
+ stack.server.PrivateKey = testNodeKey
}
-// TestServiceRetrieval tests that individual services can be retrieved.
-func TestServiceRetrieval(t *testing.T) {
+// TestLifecycleRetrieval tests that individual services can be retrieved.
+func TestLifecycleRetrieval(t *testing.T) {
// Create a simple stack and register two service types
stack, err := New(testNodeConfig())
if err != nil {
@@ -434,19 +327,22 @@ func TestServiceRetrieval(t *testing.T) {
}
defer stack.Close()
- if err := stack.Register(NewNoopService); err != nil {
- t.Fatalf("noop service registration failed: %v", err)
- }
- if err := stack.Register(NewInstrumentedService); err != nil {
- t.Fatalf("instrumented service registration failed: %v", err)
+ noop := NewNoop()
+ stack.RegisterLifecycle(noop)
+
+ is, err := NewInstrumentedService()
+ if err != nil {
+ t.Fatalf("instrumented service creation failed: %v", err)
}
+ stack.RegisterLifecycle(is)
+
// Make sure none of the services can be retrieved until started
- var noopServ *NoopService
- if err := stack.Service(&noopServ); err != ErrNodeStopped {
+ var noopServ *Noop
+ if err := stack.Lifecycle(&noopServ); err != ErrNodeStopped {
t.Fatalf("noop service retrieval mismatch: have %v, want %v", err, ErrNodeStopped)
}
var instServ *InstrumentedService
- if err := stack.Service(&instServ); err != ErrNodeStopped {
+ if err := stack.Lifecycle(&instServ); err != ErrNodeStopped {
t.Fatalf("instrumented service retrieval mismatch: have %v, want %v", err, ErrNodeStopped)
}
// Start the stack and ensure everything is retrievable now
@@ -455,152 +351,18 @@ func TestServiceRetrieval(t *testing.T) {
}
defer stack.Stop()
- if err := stack.Service(&noopServ); err != nil {
+ if err := stack.Lifecycle(&noopServ); err != nil {
t.Fatalf("noop service retrieval mismatch: have %v, want %v", err, nil)
}
- if err := stack.Service(&instServ); err != nil {
+ if err := stack.Lifecycle(&instServ); err != nil {
t.Fatalf("instrumented service retrieval mismatch: have %v, want %v", err, nil)
}
}
-// Tests that all protocols defined by individual services get launched.
-func TestProtocolGather(t *testing.T) {
- stack, err := New(testNodeConfig())
- if err != nil {
- t.Fatalf("failed to create protocol stack: %v", err)
- }
- defer stack.Close()
-
- // Register a batch of services with some configured number of protocols
- services := map[string]struct {
- Count int
- Maker InstrumentingWrapper
- }{
- "zero": {0, InstrumentedServiceMakerA},
- "one": {1, InstrumentedServiceMakerB},
- "many": {10, InstrumentedServiceMakerC},
- }
- for id, config := range services {
- protocols := make([]p2p.Protocol, config.Count)
- for i := 0; i < len(protocols); i++ {
- protocols[i].Name = id
- protocols[i].Version = uint(i)
- }
- constructor := func(*ServiceContext) (Service, error) {
- return &InstrumentedService{
- protocols: protocols,
- }, nil
- }
- if err := stack.Register(config.Maker(constructor)); err != nil {
- t.Fatalf("service %s: registration failed: %v", id, err)
- }
- }
- // Start the services and ensure all protocols start successfully
- if err := stack.Start(); err != nil {
- t.Fatalf("failed to start protocol stack: %v", err)
- }
- defer stack.Stop()
-
- protocols := stack.Server().Protocols
- if len(protocols) != 11 {
- t.Fatalf("mismatching number of protocols launched: have %d, want %d", len(protocols), 26)
- }
- for id, config := range services {
- for ver := 0; ver < config.Count; ver++ {
- launched := false
- for i := 0; i < len(protocols); i++ {
- if protocols[i].Name == id && protocols[i].Version == uint(ver) {
- launched = true
- break
- }
- }
- if !launched {
- t.Errorf("configured protocol not launched: %s v%d", id, ver)
- }
- }
- }
-}
-
-// Tests that all APIs defined by individual services get exposed.
-func TestAPIGather(t *testing.T) {
- stack, err := New(testNodeConfig())
- if err != nil {
- t.Fatalf("failed to create protocol stack: %v", err)
- }
- defer stack.Close()
-
- // Register a batch of services with some configured APIs
- calls := make(chan string, 1)
- makeAPI := func(result string) *OneMethodAPI {
- return &OneMethodAPI{fun: func() { calls <- result }}
- }
- services := map[string]struct {
- APIs []rpc.API
- Maker InstrumentingWrapper
- }{
- "Zero APIs": {
- []rpc.API{}, InstrumentedServiceMakerA},
- "Single API": {
- []rpc.API{
- {Namespace: "single", Version: "1", Service: makeAPI("single.v1"), Public: true},
- }, InstrumentedServiceMakerB},
- "Many APIs": {
- []rpc.API{
- {Namespace: "multi", Version: "1", Service: makeAPI("multi.v1"), Public: true},
- {Namespace: "multi.v2", Version: "2", Service: makeAPI("multi.v2"), Public: true},
- {Namespace: "multi.v2.nested", Version: "2", Service: makeAPI("multi.v2.nested"), Public: true},
- }, InstrumentedServiceMakerC},
- }
-
- for id, config := range services {
- config := config
- constructor := func(*ServiceContext) (Service, error) {
- return &InstrumentedService{apis: config.APIs}, nil
- }
- if err := stack.Register(config.Maker(constructor)); err != nil {
- t.Fatalf("service %s: registration failed: %v", id, err)
- }
- }
- // Start the services and ensure all API start successfully
- if err := stack.Start(); err != nil {
- t.Fatalf("failed to start protocol stack: %v", err)
- }
- defer stack.Stop()
-
- // Connect to the RPC server and verify the various registered endpoints
- client, err := stack.Attach()
- if err != nil {
- t.Fatalf("failed to connect to the inproc API server: %v", err)
- }
- defer client.Close()
-
- tests := []struct {
- Method string
- Result string
- }{
- {"single_theOneMethod", "single.v1"},
- {"multi_theOneMethod", "multi.v1"},
- {"multi.v2_theOneMethod", "multi.v2"},
- {"multi.v2.nested_theOneMethod", "multi.v2.nested"},
- }
- for i, test := range tests {
- if err := client.Call(nil, test.Method); err != nil {
- t.Errorf("test %d: API request failed: %v", i, err)
- }
- select {
- case result := <-calls:
- if result != test.Result {
- t.Errorf("test %d: result mismatch: have %s, want %s", i, result, test.Result)
- }
- case <-time.After(time.Second):
- t.Fatalf("test %d: rpc execution timeout", i)
- }
- }
-}
-
+// Tests whether websocket requests can be handled on the same port as a regular http server
func TestWebsocketHTTPOnSamePort_WebsocketRequest(t *testing.T) {
node := startHTTP(t)
- defer node.stopHTTP()
+ defer node.Stop()
wsReq, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:7453", nil)
if err != nil {
@@ -615,9 +377,10 @@ func TestWebsocketHTTPOnSamePort_WebsocketRequest(t *testing.T) {
assert.Equal(t, "websocket", resp.Header.Get("Upgrade"))
}
+// Tests whether http requests can be handled successfully
func TestWebsocketHTTPOnSamePort_HTTPRequest(t *testing.T) {
node := startHTTP(t)
- defer node.stopHTTP()
+ defer node.Stop()
httpReq, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:7453", nil)
if err != nil {
@@ -630,13 +393,17 @@ func TestWebsocketHTTPOnSamePort_HTTPRequest(t *testing.T) {
}
func startHTTP(t *testing.T) *Node {
- conf := &Config{HTTPPort: 7453, WSPort: 7453}
+ conf := &Config{
+ HTTPHost: "127.0.0.1",
+ HTTPPort: 7453,
+ WSHost: "127.0.0.1",
+ WSPort: 7453,
+ }
node, err := New(conf)
if err != nil {
t.Error("could not create a new node ", err)
}
-
- err = node.startHTTP("127.0.0.1:7453", []rpc.API{}, []string{}, []string{}, []string{}, rpc.HTTPTimeouts{}, []string{})
+ err = node.Start()
if err != nil {
t.Error("could not start http service on node ", err)
}
@@ -648,7 +415,8 @@ func doHTTPRequest(t *testing.T, req *http.Request) *http.Response {
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
- t.Error("could not issue a GET request to the given endpoint", err)
+ t.Fatal("could not issue a GET request to the given endpoint", err)
+
}
return resp
}
diff --git a/node/rpcstack_test.go b/node/rpcstack_test.go
index 040e087dcbbc..ff887738df33 100644
--- a/node/rpcstack_test.go
+++ b/node/rpcstack_test.go
@@ -10,7 +10,10 @@ import (
)
func TestNewWebsocketUpgradeHandler_websocket(t *testing.T) {
- h := &HTTPServer{Srv: rpc.NewServer()}
+ h := &HTTPServer{
+ Srv: rpc.NewServer(),
+ WSAllowed: true,
+ }
handler := h.NewWebsocketUpgradeHandler(nil, h.Srv.WebsocketHandler([]string{}))
ts := httptest.NewServer(handler)
defer ts.Close()
@@ -27,7 +30,7 @@ func TestNewWebsocketUpgradeHandler_websocket(t *testing.T) {
resp, err := client.Do(req)
if err != nil {
- t.Error("could not issue a GET request to the test http server", err)
+ t.Fatalf("could not issue a GET request to the test http server %v", err)
}
responses <- resp
}(responses)
diff --git a/node/service.go b/node/service.go
index c86372bb053e..53ed61017f39 100644
--- a/node/service.go
+++ b/node/service.go
@@ -18,6 +18,7 @@ package node
import (
"path/filepath"
+ "reflect"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/core/rawdb"
@@ -30,6 +31,7 @@ import (
// as well as utility methods to operate on the service environment.
type ServiceContext struct {
Config Config
+ Lifecycles map[reflect.Type]Lifecycle // TODO should this be in the service context or should it be on the node itself .. ?
EventMux *event.TypeMux // Event multiplexer used for decoupled notifications
AccountManager *accounts.Manager // Account manager created by the node.
}
@@ -71,15 +73,15 @@ func (ctx *ServiceContext) ResolvePath(path string) string {
return ctx.Config.ResolvePath(path)
}
-//// Service retrieves a currently running service registered of a specific type.
-//func (ctx *ServiceContext) Service(service interface{}) error {
-// element := reflect.ValueOf(service).Elem()
-// if running, ok := ctx.services[element.Type()]; ok {
-// element.Set(reflect.ValueOf(running))
-// return nil
-// }
-// return ErrServiceUnknown
-//}
+// Lifecycle retrieves a currently running lifecycle registered of a specific type.
+func (ctx *ServiceContext) Lifecycle(lifecycle interface{}) error {
+ element := reflect.ValueOf(lifecycle).Elem()
+ if running, ok := ctx.Lifecycles[element.Type()]; ok {
+ element.Set(reflect.ValueOf(running))
+ return nil
+ }
+ return ErrServiceUnknown
+}
// ExtRPCEnabled returns the indicator whether node enables the external
// RPC(http, ws or graphql).
diff --git a/node/service_test.go b/node/service_test.go
index 5da8e9e434f5..183ca4915330 100644
--- a/node/service_test.go
+++ b/node/service_test.go
@@ -17,7 +17,6 @@
package node
import (
- "fmt"
"io/ioutil"
"os"
"path/filepath"
@@ -61,38 +60,42 @@ func TestContextDatabases(t *testing.T) {
}
}
-// Tests that already constructed services can be retrieves by later ones.
-func TestContextServices(t *testing.T) {
+// Tests that already constructed Lifecycles can be retrieved by later ones.
+func TestContextLifecycles(t *testing.T) {
stack, err := New(testNodeConfig())
if err != nil {
t.Fatalf("failed to create protocol stack: %v", err)
}
defer stack.Close()
// Define a verifier that ensures a NoopA is before it and NoopB after
- verifier := func(ctx *ServiceContext) (Service, error) {
- var objA *NoopServiceA
- if ctx.Service(&objA) != nil {
- return nil, fmt.Errorf("former service not found")
- }
- var objB *NoopServiceB
- if err := ctx.Service(&objB); err != ErrServiceUnknown {
- return nil, fmt.Errorf("latters lookup error mismatch: have %v, want %v", err, ErrServiceUnknown)
- }
- return new(NoopService), nil
- }
- // Register the collection of services
- if err := stack.Register(NewNoopServiceA); err != nil {
- t.Fatalf("former failed to register service: %v", err)
+
+ noop := NewNoop()
+ stack.RegisterLifecycle(noop)
+
+ isC, err := NewInstrumentedService()
+ if err != nil {
+ t.Fatalf("could not create instrumented service %v", err)
}
- if err := stack.Register(verifier); err != nil {
- t.Fatalf("failed to register service verifier: %v", err)
+
+ isB, err := NewInstrumentedService()
+ if err != nil {
+ t.Fatalf("could not create instrumented service %v", err)
+
}
- if err := stack.Register(NewNoopServiceB); err != nil {
- t.Fatalf("latter failed to register service: %v", err)
+ isB.startHook = func() {
+ if err := stack.ServiceContext.Lifecycle(&noop); err != nil {
+ t.Errorf("former service not found: %v", err)
+ }
+ if err := stack.ServiceContext.Lifecycle(&isC); err != ErrServiceUnknown {
+ t.Errorf("latters lookup error mismatch: have %v, want %v", err, ErrServiceUnknown)
+ }
}
+ stack.RegisterLifecycle(isB)
+
// Start the protocol stack and ensure services are constructed in order
if err := stack.Start(); err != nil {
t.Fatalf("failed to start stack: %v", err)
}
+
defer stack.Stop()
}
diff --git a/node/utils_test.go b/node/utils_test.go
index 0484ee035708..0755e0411171 100644
--- a/node/utils_test.go
+++ b/node/utils_test.go
@@ -19,65 +19,47 @@
package node
-import (
- "github.com/ethereum/go-ethereum/p2p"
- "github.com/ethereum/go-ethereum/rpc"
-)
+import "github.com/ethereum/go-ethereum/p2p"
-// NoopService is a trivial implementation of the Service interface.
+// NoopLifecycle is a trivial implementation of the Service interface.
type NoopLifecycle struct{}
func (s *NoopLifecycle) Start() error { return nil }
func (s *NoopLifecycle) Stop() error { return nil }
-func NewNoop(stack *Node) (*Noop, error) {
+func NewNoop() *Noop {
noop := new(Noop)
- stack.RegisterLifecycle(noop)
- return noop, nil
+ return noop
}
-// Set of services all wrapping the base NoopService resulting in the same method
+// Set of services all wrapping the base NoopLifecycle resulting in the same method
// signatures but different outer types.
type Noop struct{ NoopLifecycle }
-//func NewNoopServiceA(*ServiceContext) (Lifecycle, error) { return new(NoopServiceA), nil }
-//func NewNoopServiceB(*ServiceContext) (Lifecycle, error) { return new(NoopServiceB), nil }
-//func NewNoopServiceC(*ServiceContext) (Lifecycle, error) { return new(NoopServiceC), nil }
-// InstrumentedService is an implementation of Service for which all interface
+// InstrumentedService is an implementation of Lifecycle for which all interface
// methods can be instrumented both return value as well as event hook wise.
type InstrumentedService struct {
- protocols []p2p.Protocol
- apis []rpc.API
start error
stop error
- server *p2p.Server
-
- protocolsHook func()
- startHook func(*p2p.Server)
+ startHook func()
stopHook func()
-}
-func NewInstrumentedService(server *p2p.Server) (Lifecycle, error) {
- is := &InstrumentedService{ server: server }
- return is, nil
+ protocols []p2p.Protocol
}
-func (s *InstrumentedService) Protocols() []p2p.Protocol {
- if s.protocolsHook != nil {
- s.protocolsHook()
- }
- return s.protocols
-}
+type InstrumentedServiceA struct { InstrumentedService }
+type InstrumentedServiceB struct { InstrumentedService }
+type InstrumentedServiceC struct { InstrumentedService }
-func (s *InstrumentedService) APIs() []rpc.API {
- return s.apis
+func NewInstrumentedService() (*InstrumentedService, error) {
+ return new(InstrumentedService), nil
}
func (s *InstrumentedService) Start() error {
if s.startHook != nil {
- s.startHook(s.server)
+ s.startHook()
}
return s.start
}
diff --git a/p2p/server.go b/p2p/server.go
index 2e7a9c0b14be..aae88260a91b 100644
--- a/p2p/server.go
+++ b/p2p/server.go
@@ -1120,6 +1120,6 @@ func (srv *Server) PeersInfo() []*PeerInfo {
return infos
}
-func (srv *Server) Listening() bool {
- return srv.listener != nil
+func (srv *Server) Running() bool {
+ return srv.running
}
From 1badd5daa62b6215f58282425f0bb799c85e59bd Mon Sep 17 00:00:00 2001
From: rene <41963722+renaynay@users.noreply.github.com>
Date: Mon, 25 May 2020 16:56:38 +0200
Subject: [PATCH 036/160] http server array now a map (#19)
---
cmd/geth/config.go | 2 +-
cmd/utils/flags.go | 4 ++--
graphql/service.go | 7 +++++--
node/api.go | 51 ++++++++++++++++++++++++++++++----------------
node/node.go | 38 +++++++++++++---------------------
5 files changed, 56 insertions(+), 46 deletions(-)
diff --git a/cmd/geth/config.go b/cmd/geth/config.go
index df452b8b4fd8..3a4da2710858 100644
--- a/cmd/geth/config.go
+++ b/cmd/geth/config.go
@@ -166,7 +166,7 @@ func makeFullNode(ctx *cli.Context) (*node.Node, *eth.Ethereum, *les.LightEthere
}
// Configure GraphQL if requested
if ctx.GlobalIsSet(utils.GraphQLEnabledFlag.Name) {
- utils.RegisterGraphQLService(stack, ethBackend, lesBackend, cfg.Node.GraphQLEndpoint(), cfg.Node.GraphQLCors, cfg.Node.GraphQLVirtualHosts, cfg.Node.HTTPTimeouts)
+ utils.RegisterGraphQLService(stack, ethBackend, lesBackend, cfg.Node.GraphQLHost, cfg.Node.GraphQLPort, cfg.Node.GraphQLCors, cfg.Node.GraphQLVirtualHosts, cfg.Node.HTTPTimeouts)
}
// Add the Ethereum Stats daemon if requested.
if cfg.Ethstats.URL != "" {
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index 25faf1b91ec2..33d7b12038ad 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -1727,8 +1727,8 @@ func RegisterEthStatsService(stack *node.Node, ethBackend *eth.Ethereum, lesBack
}
// RegisterGraphQLService is a utility function to construct a new service and register it against a node.
-func RegisterGraphQLService(stack *node.Node, ethBackend *eth.Ethereum, lesBackend *les.LightEthereum, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) {
- if err := graphql.New(stack, ethBackend, lesBackend, endpoint, cors, vhosts, timeouts); err != nil {
+func RegisterGraphQLService(stack *node.Node, ethBackend *eth.Ethereum, lesBackend *les.LightEthereum, host string, port int, cors, vhosts []string, timeouts rpc.HTTPTimeouts) {
+ if err := graphql.New(stack, ethBackend, lesBackend, host, port, cors, vhosts, timeouts); err != nil {
Fatalf("Failed to register the GraphQL service: %w", err)
}
}
diff --git a/graphql/service.go b/graphql/service.go
index b086315496aa..54f01c50ca96 100644
--- a/graphql/service.go
+++ b/graphql/service.go
@@ -18,6 +18,7 @@ package graphql
import (
"errors"
+ "fmt"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/les"
"net/http"
@@ -36,7 +37,7 @@ type Service struct {
}
// New constructs a new GraphQL service instance.
-func New(stack *node.Node, ethBackend *eth.Ethereum, lesBackend *les.LightEthereum, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) error {
+func New(stack *node.Node, ethBackend *eth.Ethereum, lesBackend *les.LightEthereum, host string, port int, cors, vhosts []string, timeouts rpc.HTTPTimeouts) error {
service := new(Service)
// add backend
if ethBackend != nil {
@@ -47,6 +48,8 @@ func New(stack *node.Node, ethBackend *eth.Ethereum, lesBackend *les.LightEthere
return errors.New("no Ethereum service")
}
+ endpoint := fmt.Sprintf("%s:%d", host, port)
+
// check if http server with given endpoint exists and enable graphQL on it
server := stack.ExistingHTTPServer(endpoint)
if server != nil {
@@ -78,7 +81,7 @@ func New(stack *node.Node, ethBackend *eth.Ethereum, lesBackend *les.LightEthere
Srv: rpc.NewServer(),
}
gqlServer.SetEndpoint(endpoint)
- stack.RegisterHTTPServer(gqlServer)
+ stack.RegisterHTTPServer(endpoint, gqlServer)
service.graphqlServer = gqlServer
diff --git a/node/api.go b/node/api.go
index 2effb4f2a48f..3badf6209073 100644
--- a/node/api.go
+++ b/node/api.go
@@ -146,13 +146,7 @@ func (api *PrivateAdminAPI) PeerEvents(ctx context.Context) (*rpc.Subscription,
func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis *string, vhosts *string) (bool, error) {
api.node.lock.Lock()
defer api.node.lock.Unlock()
- // check if HTTP server already exists
- for _, httpServer := range api.node.httpServers {
- if httpServer.RPCAllowed {
- return false, fmt.Errorf("HTTP RPC already running on %v", httpServer.Listener.Addr())
- }
- }
-
+ // set host, port, and endpoint
if host == nil {
h := DefaultHTTPHost
if api.node.config.HTTPHost != "" {
@@ -164,6 +158,12 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
port = &api.node.config.HTTPPort
}
endpoint := fmt.Sprintf("%s:%d", *host, *port)
+ // check if HTTP server already exists
+ if server, exists := api.node.httpServerMap[endpoint]; exists {
+ if server.RPCAllowed {
+ return false, fmt.Errorf("HTTP RPC already running on %v", server.Listener.Addr())
+ }
+ }
allowedOrigins := api.node.config.HTTPCors
if cors != nil {
@@ -210,7 +210,7 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
"cors", strings.Join(httpServer.CorsAllowedOrigins, ","),
"vhosts", strings.Join(httpServer.Vhosts, ","))
- api.node.RegisterHTTPServer(httpServer)
+ api.node.RegisterHTTPServer(endpoint, httpServer)
return true, nil
}
@@ -219,7 +219,7 @@ func (api *PrivateAdminAPI) StopRPC() (bool, error) {
api.node.lock.Lock()
defer api.node.lock.Unlock()
- for _, httpServer := range api.node.httpServers {
+ for _, httpServer := range api.node.httpServerMap {
if httpServer.RPCAllowed {
api.node.stopServer(httpServer)
return true, nil
@@ -233,10 +233,10 @@ func (api *PrivateAdminAPI) StopRPC() (bool, error) {
func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *string, apis *string) (bool, error) {
api.node.lock.Lock()
defer api.node.lock.Unlock()
- // check if an existing HTTP server already handles websocket
- for _, httpServer := range api.node.httpServers {
- if httpServer.WSAllowed {
- return false, fmt.Errorf("WebSocket RPC already running on %v", httpServer.Listener.Addr())
+ // check if an existing WS server already exists
+ for _, server := range api.node.httpServerMap {
+ if server.WSAllowed {
+ return false, fmt.Errorf("WebSocket RPC already running on %v", server.Listener.Addr())
}
}
// set host, port and endpoint
@@ -251,6 +251,24 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
port = &api.node.config.WSPort
}
endpoint := fmt.Sprintf("%s:%d", *host, *port)
+ // check if there is an existing server on the specified port, and if there is, enable ws on it
+ if server, exists := api.node.httpServerMap[endpoint]; exists {
+ // else configure ws on the existing server
+ server.WSAllowed = true
+ // configure origins
+ origins := api.node.config.WSOrigins
+ if allowedOrigins != nil {
+ origins = nil
+ for _, origin := range strings.Split(*allowedOrigins, ",") {
+ origins = append(origins, strings.TrimSpace(origin))
+ }
+ }
+ server.WsOrigins = origins
+
+ api.node.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", server.Listener.Addr()))
+ return true, nil
+ }
+
origins := api.node.config.WSOrigins
if allowedOrigins != nil {
@@ -264,8 +282,7 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
if existingServer != nil {
existingServer.WSAllowed = true
existingServer.WsOrigins = origins
- api.node.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", existingServer.Listener.Addr()))
- return true, nil
+
}
modules := api.node.config.WSModules
@@ -294,7 +311,7 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
wsServer.Start()
api.node.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", wsServer.Listener.Addr()))
- api.node.RegisterHTTPServer(wsServer)
+ api.node.RegisterHTTPServer(endpoint, wsServer)
return true, nil
}
@@ -303,7 +320,7 @@ func (api *PrivateAdminAPI) StopWS() (bool, error) {
api.node.lock.Lock()
defer api.node.lock.Unlock()
- for _, httpServer := range api.node.httpServers {
+ for _, httpServer := range api.node.httpServerMap {
if httpServer.WSAllowed {
httpServer.WSAllowed = false
// if RPC is not enabled on the WS http server, shut it down
diff --git a/node/node.go b/node/node.go
index 6a94f1c0dee7..e794d57721aa 100644
--- a/node/node.go
+++ b/node/node.go
@@ -58,7 +58,7 @@ type Node struct {
rpcAPIs []rpc.API // List of APIs currently provided by the node
inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
- httpServers []*HTTPServer // Stores information about all http servers (if any), including http, ws, and graphql
+ httpServerMap map[string]*HTTPServer // Stores information about all http servers (if any) by their port, including http, ws, and graphql
ipc *HTTPServer // Stores information about the ipc http server
@@ -112,7 +112,7 @@ func New(conf *Config) (*Node, error) {
Config: *conf,
Lifecycles: make(map[reflect.Type]Lifecycle),
},
- httpServers: make([]*HTTPServer, 0),
+ httpServerMap: make(map[string]*HTTPServer),
ipc: &HTTPServer{
endpoint: conf.IPCEndpoint(),
},
@@ -156,13 +156,13 @@ func New(conf *Config) (*Node, error) {
httpServ.WSAllowed = true
httpServ.WsOrigins = conf.WSOrigins
httpServ.Whitelist = append(httpServ.Whitelist, conf.WSModules...)
- node.httpServers = append(node.httpServers, httpServ)
+ node.httpServerMap[conf.HTTPEndpoint()] = httpServ
return node, nil
}
- node.httpServers = append(node.httpServers, httpServ)
+ node.httpServerMap[conf.HTTPEndpoint()] = httpServ
}
if conf.WSHost != "" {
- node.httpServers = append(node.httpServers, &HTTPServer{
+ node.httpServerMap[conf.WSEndpoint()] = &HTTPServer{
WsOrigins: conf.WSOrigins,
Whitelist: conf.WSModules,
Srv: rpc.NewServer(),
@@ -170,7 +170,7 @@ func New(conf *Config) (*Node, error) {
host: conf.WSHost,
port: conf.WSPort,
WSAllowed: true,
- })
+ }
}
return node, nil
@@ -221,16 +221,14 @@ func (n *Node) RegisterAPIs(apis []rpc.API) {
}
// RegisterHTTPServer registers the given HTTP server on the node
-func (n *Node) RegisterHTTPServer(server *HTTPServer) {
- n.httpServers = append(n.httpServers, server)
+func (n *Node) RegisterHTTPServer(endpoint string, server *HTTPServer) {
+ n.httpServerMap[endpoint] = server
}
// ExistingHTTPServer checks if an HTTP server is already configured on the given endpoint
func (n *Node) ExistingHTTPServer(endpoint string) *HTTPServer {
- for _, httpServer := range n.httpServers {
- if endpoint == httpServer.endpoint {
- return httpServer
- }
+ if server, exists := n.httpServerMap[endpoint]; exists {
+ return server
}
return nil
}
@@ -364,7 +362,7 @@ func (n *Node) configureRPC() error {
return err
}
- for _, server := range n.httpServers {
+ for _, server := range n.httpServerMap {
// configure the handlers
if server.RPCAllowed {
server.handler = NewHTTPHandlerStack(server.Srv, server.CorsAllowedOrigins, server.Vhosts)
@@ -467,15 +465,7 @@ func (n *Node) stopServer(server *HTTPServer) {
server.Srv = nil
}
// remove stopped http server from node's http servers // TODO is this preferable?
- remainingServers := make([]*HTTPServer, len(n.httpServers)-1)
- index := 0
- for _, remaining := range n.httpServers {
- if remaining.Server != nil && remaining.Srv != nil {
- remainingServers[index] = remaining
- index ++
- }
- }
- n.httpServers = remainingServers
+ delete(n.httpServerMap, server.endpoint)
// remove stopped http server from node's lifecycles
n.removeLifecycle(server)
}
@@ -609,7 +599,7 @@ func (n *Node) HTTPEndpoint() string {
n.lock.Lock()
defer n.lock.Unlock()
- for _, httpServer := range n.httpServers {
+ for _, httpServer := range n.httpServerMap {
if httpServer.RPCAllowed {
if httpServer.Listener != nil {
return httpServer.Listener.Addr().String()
@@ -627,7 +617,7 @@ func (n *Node) WSEndpoint() string {
n.lock.Lock()
defer n.lock.Unlock()
- for _, httpServer := range n.httpServers {
+ for _, httpServer := range n.httpServerMap {
if httpServer.WSAllowed {
if httpServer.Listener != nil {
return httpServer.Listener.Addr().String()
From fbc9a6495f4f537de49bb3353e63d11c970fc60a Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Mon, 25 May 2020 17:02:45 +0200
Subject: [PATCH 037/160] removed unnecessary change to pass host, port instead
of endpoint
---
cmd/geth/config.go | 2 +-
cmd/utils/flags.go | 4 ++--
graphql/service.go | 5 +----
3 files changed, 4 insertions(+), 7 deletions(-)
diff --git a/cmd/geth/config.go b/cmd/geth/config.go
index 3a4da2710858..df452b8b4fd8 100644
--- a/cmd/geth/config.go
+++ b/cmd/geth/config.go
@@ -166,7 +166,7 @@ func makeFullNode(ctx *cli.Context) (*node.Node, *eth.Ethereum, *les.LightEthere
}
// Configure GraphQL if requested
if ctx.GlobalIsSet(utils.GraphQLEnabledFlag.Name) {
- utils.RegisterGraphQLService(stack, ethBackend, lesBackend, cfg.Node.GraphQLHost, cfg.Node.GraphQLPort, cfg.Node.GraphQLCors, cfg.Node.GraphQLVirtualHosts, cfg.Node.HTTPTimeouts)
+ utils.RegisterGraphQLService(stack, ethBackend, lesBackend, cfg.Node.GraphQLEndpoint(), cfg.Node.GraphQLCors, cfg.Node.GraphQLVirtualHosts, cfg.Node.HTTPTimeouts)
}
// Add the Ethereum Stats daemon if requested.
if cfg.Ethstats.URL != "" {
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index 33d7b12038ad..25faf1b91ec2 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -1727,8 +1727,8 @@ func RegisterEthStatsService(stack *node.Node, ethBackend *eth.Ethereum, lesBack
}
// RegisterGraphQLService is a utility function to construct a new service and register it against a node.
-func RegisterGraphQLService(stack *node.Node, ethBackend *eth.Ethereum, lesBackend *les.LightEthereum, host string, port int, cors, vhosts []string, timeouts rpc.HTTPTimeouts) {
- if err := graphql.New(stack, ethBackend, lesBackend, host, port, cors, vhosts, timeouts); err != nil {
+func RegisterGraphQLService(stack *node.Node, ethBackend *eth.Ethereum, lesBackend *les.LightEthereum, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) {
+ if err := graphql.New(stack, ethBackend, lesBackend, endpoint, cors, vhosts, timeouts); err != nil {
Fatalf("Failed to register the GraphQL service: %w", err)
}
}
diff --git a/graphql/service.go b/graphql/service.go
index 54f01c50ca96..58897c9ffa24 100644
--- a/graphql/service.go
+++ b/graphql/service.go
@@ -18,7 +18,6 @@ package graphql
import (
"errors"
- "fmt"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/les"
"net/http"
@@ -37,7 +36,7 @@ type Service struct {
}
// New constructs a new GraphQL service instance.
-func New(stack *node.Node, ethBackend *eth.Ethereum, lesBackend *les.LightEthereum, host string, port int, cors, vhosts []string, timeouts rpc.HTTPTimeouts) error {
+func New(stack *node.Node, ethBackend *eth.Ethereum, lesBackend *les.LightEthereum, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) error {
service := new(Service)
// add backend
if ethBackend != nil {
@@ -48,8 +47,6 @@ func New(stack *node.Node, ethBackend *eth.Ethereum, lesBackend *les.LightEthere
return errors.New("no Ethereum service")
}
- endpoint := fmt.Sprintf("%s:%d", host, port)
-
// check if http server with given endpoint exists and enable graphQL on it
server := stack.ExistingHTTPServer(endpoint)
if server != nil {
From 60ced1c499c9bfd510900f04d73606f17c1bf28b Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Mon, 25 May 2020 17:39:15 +0200
Subject: [PATCH 038/160] added some more tests for http servers
---
graphql/graphql_test.go | 39 +++++++++++++++++++++++++++++++++++++++
node/node_test.go | 19 +++++++++++++++++--
node/rpcstack_test.go | 28 ++++++++++++++++++++++++++++
3 files changed, 84 insertions(+), 2 deletions(-)
diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go
index 40b13187f496..6523d1ccbc01 100644
--- a/graphql/graphql_test.go
+++ b/graphql/graphql_test.go
@@ -17,6 +17,11 @@
package graphql
import (
+ "fmt"
+ "github.com/ethereum/go-ethereum/eth"
+ "github.com/ethereum/go-ethereum/node"
+ "github.com/ethereum/go-ethereum/rpc"
+ "github.com/stretchr/testify/assert"
"testing"
)
@@ -26,3 +31,37 @@ func TestBuildSchema(t *testing.T) {
t.Errorf("Could not construct GraphQL handler: %v", err)
}
}
+
+// Tests that a graphql handler can be added to an existing HTTPServer
+func TestGQLAllowed(t *testing.T) {
+ stack, err := node.New(&node.Config{
+ HTTPHost: node.DefaultHTTPHost,
+ HTTPPort: 9393,
+ })
+ if err != nil {
+ t.Fatalf("could not create node: %v", err)
+ }
+ defer stack.Close()
+ // create backend
+ ethBackend, err := eth.New(stack, ð.DefaultConfig)
+ if err != nil {
+ t.Fatalf("could not create eth backend: %v", err)
+ }
+ // set endpoint and create new gql service
+ endpoint := fmt.Sprintf("%s:%d", node.DefaultHTTPHost, 9393)
+ err = New(stack,ethBackend,nil, endpoint, []string{}, []string{}, rpc.DefaultHTTPTimeouts)
+ if err != nil {
+ t.Fatalf("could not create graphql service: %v", err)
+ }
+ // start node
+ if err = stack.Start(); err != nil {
+ t.Fatalf("could not start node: %v", err)
+ }
+ // check that server was created
+ server := stack.ExistingHTTPServer(endpoint)
+ if server == nil {
+ t.Errorf("server was not created on the given endpoint: %v", err)
+ }
+ // assert that server allows GQL requests
+ assert.True(t, server.GQLAllowed)
+}
diff --git a/node/node_test.go b/node/node_test.go
index e8764f1ab383..c81dfe0d009f 100644
--- a/node/node_test.go
+++ b/node/node_test.go
@@ -362,7 +362,7 @@ func TestLifecycleRetrieval(t *testing.T) {
// Tests whether websocket requests can be handled on the same port as a regular http server
func TestWebsocketHTTPOnSamePort_WebsocketRequest(t *testing.T) {
node := startHTTP(t)
- defer node.Stop()
+ defer node.Close()
wsReq, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:7453", nil)
if err != nil {
@@ -377,10 +377,23 @@ func TestWebsocketHTTPOnSamePort_WebsocketRequest(t *testing.T) {
assert.Equal(t, "websocket", resp.Header.Get("Upgrade"))
}
+// Tests whether graphQL requests can be handled on the same port as a regular http server
+func TestGraphQLHTTPOnSamePort_GQLRequest(t *testing.T) {
+ node := startHTTP(t)
+ defer node.Close()
+
+ gqlReq, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:7453/graphql", nil)
+ if err != nil {
+ t.Error("could not issue new http request ", err)
+ }
+ resp := doHTTPRequest(t, gqlReq)
+ assert.Equal(t, resp.StatusCode, 200)
+}
+
// Tests whether http requests can be handled successfully
func TestWebsocketHTTPOnSamePort_HTTPRequest(t *testing.T) {
node := startHTTP(t)
- defer node.Stop()
+ defer node.Close()
httpReq, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:7453", nil)
if err != nil {
@@ -398,6 +411,8 @@ func startHTTP(t *testing.T) *Node {
HTTPPort: 7453,
WSHost: "127.0.0.1",
WSPort: 7453,
+ GraphQLHost: "127.0.0.1",
+ GraphQLPort: 7453,
}
node, err := New(conf)
if err != nil {
diff --git a/node/rpcstack_test.go b/node/rpcstack_test.go
index ff887738df33..364bceb54094 100644
--- a/node/rpcstack_test.go
+++ b/node/rpcstack_test.go
@@ -1,6 +1,7 @@
package node
import (
+ "fmt"
"net/http"
"net/http/httptest"
"testing"
@@ -38,3 +39,30 @@ func TestNewWebsocketUpgradeHandler_websocket(t *testing.T) {
response := <-responses
assert.Equal(t, "websocket", response.Header.Get("Upgrade"))
}
+
+// Tests that a ws handler can be added to and enabled on an existing HTTPServer
+func TestWSAllowed(t *testing.T) {
+ stack, err := New(&Config{
+ HTTPHost: DefaultHTTPHost,
+ HTTPPort: 9393,
+ WSHost: DefaultHTTPHost,
+ WSPort: 9393,
+ })
+ if err != nil {
+ t.Fatalf("could not create node: %v", err)
+ }
+ defer stack.Close()
+ // start node
+ err = stack.Start()
+ if err != nil {
+ t.Fatalf("could not start node: %v", err)
+ }
+ // check that server was configured on the given endpoint
+ server := stack.ExistingHTTPServer(fmt.Sprintf("%s:%d", DefaultHTTPHost, 9393))
+ if server == nil {
+ t.Fatalf("server was not started on the given endpoint: %v", err)
+ }
+ // assert that both RPC and WS are allowed on the HTTP Server
+ assert.True(t, server.RPCAllowed)
+ assert.True(t, server.WSAllowed)
+}
From 53a2c8f0f1fd5b3b6a6034cc0cc61bf9db077847 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Tue, 26 May 2020 14:12:03 +0200
Subject: [PATCH 039/160] moved some gql-specific tests to gql package
---
graphql/graphql_test.go | 130 +++++++++++++++++++++++++++++++++++-----
node/node_test.go | 17 +-----
2 files changed, 117 insertions(+), 30 deletions(-)
diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go
index 6523d1ccbc01..66a589829dfa 100644
--- a/graphql/graphql_test.go
+++ b/graphql/graphql_test.go
@@ -22,9 +22,14 @@ import (
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/rpc"
"github.com/stretchr/testify/assert"
+ "io/ioutil"
+ "net/http"
+ "strings"
"testing"
)
+var testEndpoint = "127.0.0.1:9393"
+
func TestBuildSchema(t *testing.T) {
// Make sure the schema can be parsed and matched up to the object model.
if _, err := newHandler(nil); err != nil {
@@ -34,34 +39,129 @@ func TestBuildSchema(t *testing.T) {
// Tests that a graphql handler can be added to an existing HTTPServer
func TestGQLAllowed(t *testing.T) {
+ stack := createNode(t, true)
+ defer stack.Close()
+ // start node
+ if err := stack.Start(); err != nil {
+ t.Fatalf("could not start node: %v", err)
+ }
+ // check that server was created
+ server := stack.ExistingHTTPServer(testEndpoint)
+ if server == nil {
+ t.Errorf("server was not created on the given endpoint")
+ }
+ // assert that server allows GQL requests
+ assert.True(t, server.GQLAllowed)
+}
+
+// Tests to make sure an HTTPServer is created that handles for http, ws, and graphQL
+func TestMultiplexedServer(t *testing.T) {
+ stack := createNode(t, true)
+ defer stack.Close()
+ // start the node
+ if err := stack.Start(); err != nil {
+ t.Error("could not start http service on node ", err)
+ }
+ server := stack.ExistingHTTPServer(testEndpoint)
+ if server == nil {
+ t.Fatalf("server was not configured on the given endpoint")
+ }
+ assert.True(t, server.RPCAllowed)
+ assert.True(t, server.WSAllowed)
+ assert.True(t, server.GQLAllowed)
+}
+
+// Tests that a graphQL request is successfully handled when graphql is enabled on the specified endpoint
+func TestGraphQLHTTPOnSamePort_GQLRequest_Successful(t *testing.T) {
+ stack := createNode(t,true)
+ defer stack.Close()
+ // start node
+ if err := stack.Start(); err != nil {
+ t.Fatalf("could not start node: %v", err)
+ }
+ // create http request
+ body := strings.NewReader("{\"query\": \"{block{number}}\",\"variables\": null}")
+ gqlReq, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s/graphql", testEndpoint), body)
+ if err != nil {
+ t.Error("could not issue new http request ", err)
+ }
+ gqlReq.Header.Set("Content-Type", "application/json")
+ // read from response
+ resp := doHTTPRequest(t, gqlReq)
+ bodyBytes, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ t.Fatalf("could not read from response body: %v", err)
+ }
+ expected := "{\"data\":{\"block\":{\"number\":\"0x0\"}}}"
+ assert.Equal(t, expected,string(bodyBytes))
+}
+
+// Tests that a graphQL request is not handled successfully when graphql is not enabled on the specified endpoint
+func TestGraphQLHTTPOnSamePort_GQLRequest_Unsuccessful(t *testing.T) {
+ stack := createNode(t, false)
+ defer stack.Close()
+ // start node
+ if err := stack.Start(); err != nil {
+ t.Fatalf("could not start node: %v", err)
+ }
+ // make sure GQL is not enabled
+ server := stack.ExistingHTTPServer(testEndpoint)
+ if server == nil {
+ t.Fatalf("server was not created on the given endpoint")
+ }
+ assert.False(t, server.GQLAllowed)
+ // create http request
+ body := strings.NewReader("{\"query\": \"{block{number}}\",\"variables\": null}")
+ gqlReq, err := http.NewRequest(http.MethodPost, fmt.Sprintf("http://%s/graphql", testEndpoint), body)
+ if err != nil {
+ t.Error("could not issue new http request ", err)
+ }
+ gqlReq.Header.Set("Content-Type", "application/json")
+ // read from response
+ resp := doHTTPRequest(t, gqlReq)
+ bodyBytes, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ t.Fatalf("could not read from response body: %v", err)
+ }
+ // make sure the request is not handled successfully
+ expected := "{\"jsonrpc\":\"2.0\",\"id\":null,\"error\":{\"code\":-32600,\"message\":\"invalid request\"}}\n"
+ assert.Equal(t, string(bodyBytes), expected)
+}
+
+func createNode(t *testing.T, gqlEnabled bool) *node.Node {
stack, err := node.New(&node.Config{
- HTTPHost: node.DefaultHTTPHost,
+ HTTPHost: "127.0.0.1",
HTTPPort: 9393,
+ WSHost: "127.0.0.1",
+ WSPort: 9393,
})
if err != nil {
t.Fatalf("could not create node: %v", err)
}
- defer stack.Close()
+ if !gqlEnabled {
+ return stack
+ }
// create backend
ethBackend, err := eth.New(stack, ð.DefaultConfig)
if err != nil {
t.Fatalf("could not create eth backend: %v", err)
}
- // set endpoint and create new gql service
- endpoint := fmt.Sprintf("%s:%d", node.DefaultHTTPHost, 9393)
- err = New(stack,ethBackend,nil, endpoint, []string{}, []string{}, rpc.DefaultHTTPTimeouts)
+
+ // create gql service
+ err = New(stack,ethBackend,nil, testEndpoint, []string{}, []string{}, rpc.DefaultHTTPTimeouts)
if err != nil {
t.Fatalf("could not create graphql service: %v", err)
}
- // start node
- if err = stack.Start(); err != nil {
- t.Fatalf("could not start node: %v", err)
- }
- // check that server was created
- server := stack.ExistingHTTPServer(endpoint)
- if server == nil {
- t.Errorf("server was not created on the given endpoint: %v", err)
+
+ return stack
+}
+
+func doHTTPRequest(t *testing.T, req *http.Request) *http.Response {
+ client := &http.Client{}
+ resp, err := client.Do(req)
+ if err != nil {
+ t.Fatal("could not issue a GET request to the given endpoint", err)
+
}
- // assert that server allows GQL requests
- assert.True(t, server.GQLAllowed)
+ return resp
}
diff --git a/node/node_test.go b/node/node_test.go
index c81dfe0d009f..6e53630d4571 100644
--- a/node/node_test.go
+++ b/node/node_test.go
@@ -377,19 +377,6 @@ func TestWebsocketHTTPOnSamePort_WebsocketRequest(t *testing.T) {
assert.Equal(t, "websocket", resp.Header.Get("Upgrade"))
}
-// Tests whether graphQL requests can be handled on the same port as a regular http server
-func TestGraphQLHTTPOnSamePort_GQLRequest(t *testing.T) {
- node := startHTTP(t)
- defer node.Close()
-
- gqlReq, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:7453/graphql", nil)
- if err != nil {
- t.Error("could not issue new http request ", err)
- }
- resp := doHTTPRequest(t, gqlReq)
- assert.Equal(t, resp.StatusCode, 200)
-}
-
// Tests whether http requests can be handled successfully
func TestWebsocketHTTPOnSamePort_HTTPRequest(t *testing.T) {
node := startHTTP(t)
@@ -405,14 +392,14 @@ func TestWebsocketHTTPOnSamePort_HTTPRequest(t *testing.T) {
assert.Equal(t, "gzip", resp.Header.Get("Content-Encoding"))
}
+// TODO why is GQL still served successfully if the server doesn't have GQL enabled
+
func startHTTP(t *testing.T) *Node {
conf := &Config{
HTTPHost: "127.0.0.1",
HTTPPort: 7453,
WSHost: "127.0.0.1",
WSPort: 7453,
- GraphQLHost: "127.0.0.1",
- GraphQLPort: 7453,
}
node, err := New(conf)
if err != nil {
From 331d0a64365de5ed7b9389ac3352da0f2a0c48d0 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Tue, 26 May 2020 14:12:17 +0200
Subject: [PATCH 040/160] removed todo
---
node/node_test.go | 2 --
1 file changed, 2 deletions(-)
diff --git a/node/node_test.go b/node/node_test.go
index 6e53630d4571..337b55525b6e 100644
--- a/node/node_test.go
+++ b/node/node_test.go
@@ -392,8 +392,6 @@ func TestWebsocketHTTPOnSamePort_HTTPRequest(t *testing.T) {
assert.Equal(t, "gzip", resp.Header.Get("Content-Encoding"))
}
-// TODO why is GQL still served successfully if the server doesn't have GQL enabled
-
func startHTTP(t *testing.T) *Node {
conf := &Config{
HTTPHost: "127.0.0.1",
From 45eecce340590acac9a77fa72988814b15ed86ee Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Wed, 3 Jun 2020 15:46:46 +0200
Subject: [PATCH 041/160] whisper tests working
---
whisper/whisperv6/api_test.go | 5 +-
whisper/whisperv6/filter_test.go | 31 ++++++--
whisper/whisperv6/whisper_test.go | 114 ++++++++++++++++++++++--------
3 files changed, 116 insertions(+), 34 deletions(-)
diff --git a/whisper/whisperv6/api_test.go b/whisper/whisperv6/api_test.go
index 6d7157f57fd2..9aceaf456d6b 100644
--- a/whisper/whisperv6/api_test.go
+++ b/whisper/whisperv6/api_test.go
@@ -23,7 +23,10 @@ import (
)
func TestMultipleTopicCopyInNewMessageFilter(t *testing.T) {
- w := New(nil)
+ stack := newNode(t)
+ defer stack.Close()
+
+ w := getWhisperFromNode(stack, t)
keyID, err := w.GenerateSymKey()
if err != nil {
diff --git a/whisper/whisperv6/filter_test.go b/whisper/whisperv6/filter_test.go
index 55f505291977..49c2b7688361 100644
--- a/whisper/whisperv6/filter_test.go
+++ b/whisper/whisperv6/filter_test.go
@@ -92,7 +92,12 @@ func TestInstallFilters(t *testing.T) {
InitSingleTest()
const SizeTestFilters = 256
- w := New(&Config{})
+
+ stack := newNode(t)
+ defer stack.Close()
+
+ w := getWhisperFromNode(stack, t)
+
filters := NewFilters(w)
tst := generateTestCases(t, SizeTestFilters)
@@ -130,7 +135,11 @@ func TestInstallFilters(t *testing.T) {
func TestInstallSymKeyGeneratesHash(t *testing.T) {
InitSingleTest()
- w := New(&Config{})
+ stack := newNode(t)
+ defer stack.Close()
+
+ w := getWhisperFromNode(stack, t)
+
filters := NewFilters(w)
filter, _ := generateFilter(t, true)
@@ -157,7 +166,11 @@ func TestInstallSymKeyGeneratesHash(t *testing.T) {
func TestInstallIdenticalFilters(t *testing.T) {
InitSingleTest()
- w := New(&Config{})
+ stack := newNode(t)
+ defer stack.Close()
+
+ w := getWhisperFromNode(stack, t)
+
filters := NewFilters(w)
filter1, _ := generateFilter(t, true)
@@ -227,7 +240,11 @@ func TestInstallIdenticalFilters(t *testing.T) {
func TestInstallFilterWithSymAndAsymKeys(t *testing.T) {
InitSingleTest()
- w := New(&Config{})
+ stack := newNode(t)
+ defer stack.Close()
+
+ w := getWhisperFromNode(stack, t)
+
filters := NewFilters(w)
filter1, _ := generateFilter(t, true)
@@ -641,7 +658,11 @@ func TestWatchers(t *testing.T) {
var x, firstID string
var err error
- w := New(&Config{})
+ stack := newNode(t)
+ defer stack.Close()
+
+ w := getWhisperFromNode(stack, t)
+
filters := NewFilters(w)
tst := generateTestCases(t, NumFilters)
for i = 0; i < NumFilters; i++ {
diff --git a/whisper/whisperv6/whisper_test.go b/whisper/whisperv6/whisper_test.go
index ba2db975d14b..f1fa4dfdd27d 100644
--- a/whisper/whisperv6/whisper_test.go
+++ b/whisper/whisperv6/whisper_test.go
@@ -20,6 +20,7 @@ import (
"bytes"
"crypto/ecdsa"
"crypto/sha256"
+ "github.com/ethereum/go-ethereum/node"
mrand "math/rand"
"testing"
"time"
@@ -29,9 +30,11 @@ import (
)
func TestWhisperBasic(t *testing.T) {
- w := New(&DefaultConfig)
- p := w.Protocols()
- shh := p[0]
+ stack := newNode(t)
+ defer stack.Close()
+ // get whisper service from node
+ w := getWhisperFromNode(stack, t)
+ shh := w.Protocols()[0]
if shh.Name != ProtocolName {
t.Fatalf("failed Protocol Name: %v.", shh.Name)
}
@@ -111,11 +114,11 @@ func TestWhisperBasic(t *testing.T) {
}
func TestWhisperAsymmetricKeyImport(t *testing.T) {
- var (
- w = New(&DefaultConfig)
- privateKeys []*ecdsa.PrivateKey
- )
+ stack := newNode(t)
+ defer stack.Close()
+ var privateKeys []*ecdsa.PrivateKey
+ w := getWhisperFromNode(stack, t)
for i := 0; i < 50; i++ {
id, err := w.NewKeyPair()
if err != nil {
@@ -142,7 +145,10 @@ func TestWhisperAsymmetricKeyImport(t *testing.T) {
}
func TestWhisperIdentityManagement(t *testing.T) {
- w := New(&DefaultConfig)
+ stack := newNode(t)
+ defer stack.Close()
+
+ w := getWhisperFromNode(stack, t)
id1, err := w.NewKeyPair()
if err != nil {
t.Fatalf("failed to generate new key pair: %s.", err)
@@ -261,12 +267,16 @@ func TestWhisperIdentityManagement(t *testing.T) {
func TestWhisperSymKeyManagement(t *testing.T) {
InitSingleTest()
-
var (
k1, k2 []byte
- w = New(&DefaultConfig)
id2 = string("arbitrary-string-2")
)
+
+ stack := newNode(t)
+ defer stack.Close()
+
+ w := getWhisperFromNode(stack, t)
+
id1, err := w.GenerateSymKey()
if err != nil {
t.Fatalf("failed GenerateSymKey with seed %d: %s.", seed, err)
@@ -365,7 +375,7 @@ func TestWhisperSymKeyManagement(t *testing.T) {
w.DeleteSymKey(id1)
k1, err = w.GetSymKey(id1)
if err == nil {
- t.Fatalf("failed w.GetSymKey(id1): false positive.")
+ t.Fatal("failed w.GetSymKey(id1): false positive.")
}
if k1 != nil {
t.Fatalf("failed GetSymKey(id1): false positive. key=%v", k1)
@@ -451,11 +461,14 @@ func TestWhisperSymKeyManagement(t *testing.T) {
func TestExpiry(t *testing.T) {
InitSingleTest()
- w := New(&DefaultConfig)
+ stack := newNode(t)
+ defer stack.Close()
+
+ w := getWhisperFromNode(stack, t)
+
w.SetMinimumPowTest(0.0000001)
defer w.SetMinimumPowTest(DefaultMinimumPoW)
- w.Start(nil)
- defer w.Stop()
+ w.Start()
params, err := generateMessageParams()
if err != nil {
@@ -517,11 +530,15 @@ func TestExpiry(t *testing.T) {
func TestCustomization(t *testing.T) {
InitSingleTest()
- w := New(&DefaultConfig)
+ stack := newNode(t)
+ defer stack.Close()
+
+ w := getWhisperFromNode(stack, t)
+
defer w.SetMinimumPowTest(DefaultMinimumPoW)
defer w.SetMaxMessageSize(DefaultMaxMessageSize)
- w.Start(nil)
- defer w.Stop()
+ w.Start()
+
const smallPoW = 0.00001
@@ -610,11 +627,15 @@ func TestCustomization(t *testing.T) {
func TestSymmetricSendCycle(t *testing.T) {
InitSingleTest()
- w := New(&DefaultConfig)
+ stack := newNode(t)
+ defer stack.Close()
+
+ w := getWhisperFromNode(stack, t)
+
defer w.SetMinimumPowTest(DefaultMinimumPoW)
defer w.SetMaxMessageSize(DefaultMaxMessageSize)
- w.Start(nil)
- defer w.Stop()
+ w.Start()
+
filter1, err := generateFilter(t, true)
if err != nil {
@@ -701,11 +722,15 @@ func TestSymmetricSendCycle(t *testing.T) {
func TestSymmetricSendWithoutAKey(t *testing.T) {
InitSingleTest()
- w := New(&DefaultConfig)
+ stack := newNode(t)
+ defer stack.Close()
+
+ w := getWhisperFromNode(stack, t)
+
defer w.SetMinimumPowTest(DefaultMinimumPoW)
defer w.SetMaxMessageSize(DefaultMaxMessageSize)
- w.Start(nil)
- defer w.Stop()
+ w.Start()
+
filter, err := generateFilter(t, true)
if err != nil {
@@ -771,11 +796,15 @@ func TestSymmetricSendWithoutAKey(t *testing.T) {
func TestSymmetricSendKeyMismatch(t *testing.T) {
InitSingleTest()
- w := New(&DefaultConfig)
+ stack := newNode(t)
+ defer stack.Close()
+
+ w := getWhisperFromNode(stack, t)
+
defer w.SetMinimumPowTest(DefaultMinimumPoW)
defer w.SetMaxMessageSize(DefaultMaxMessageSize)
- w.Start(nil)
- defer w.Stop()
+ w.Start()
+
filter, err := generateFilter(t, true)
if err != nil {
@@ -882,17 +911,46 @@ func TestBloom(t *testing.T) {
t.Fatal("bloomFilterMatch false negative")
}
- w := New(&DefaultConfig)
+ stack := newNode(t)
+ defer stack.Close()
+
+ w := getWhisperFromNode(stack, t)
+
f := w.BloomFilter()
if f != nil {
t.Fatal("wrong bloom on creation")
}
err = w.SetBloomFilter(x)
if err != nil {
- t.Fatalf("failed to set bloom filter: %s", err)
+ t.Fatalf("failed to set bloom filter: %v", err)
}
f = w.BloomFilter()
if !BloomFilterMatch(f, x) || !BloomFilterMatch(x, f) {
t.Fatal("retireved wrong bloom filter")
}
}
+
+func newNode(t *testing.T) *node.Node {
+ stack, err := node.New(&node.DefaultConfig)
+ if err != nil {
+ t.Fatalf("could not create new node: %v", err)
+ }
+ err = New(stack, &DefaultConfig)
+ if err != nil {
+ t.Fatalf("could not create new whisper service: %v", err)
+ }
+ err = stack.Start()
+ if err != nil {
+ t.Fatalf("could not start node: %v", err)
+ }
+ return stack
+}
+
+func getWhisperFromNode(stack *node.Node, t *testing.T) *Whisper {
+ var w *Whisper
+ err := stack.Lifecycle(&w)
+ if err != nil {
+ t.Fatalf("could not get whisper service from node: %v", err)
+ }
+ return w
+}
From a380ff658e25e16746bd289b4d60b38338d3fc2a Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Wed, 3 Jun 2020 16:03:46 +0200
Subject: [PATCH 042/160] create a standalone whisper service for wnode
purposes
---
cmd/wnode/main.go | 7 +++---
whisper/whisperv6/whisper.go | 42 +++++++++++++++++++++++++++++++
whisper/whisperv6/whisper_test.go | 2 ++
3 files changed, 47 insertions(+), 4 deletions(-)
diff --git a/cmd/wnode/main.go b/cmd/wnode/main.go
index 677cad7ef142..f20c00ceb183 100644
--- a/cmd/wnode/main.go
+++ b/cmd/wnode/main.go
@@ -221,8 +221,7 @@ func initialize() {
MaxMessageSize: uint32(*argMaxSize),
MinimumAcceptedPOW: *argPoW,
}
-
- shh = whisper.New(cfg)
+ shh = whisper.StandaloneWhisperService(cfg)
if *argPoW != whisper.DefaultMinimumPoW {
err := shh.SetMinimumPoW(*argPoW)
@@ -433,7 +432,7 @@ func run() {
return
}
defer server.Stop()
- shh.Start(nil)
+ shh.Start()
defer shh.Stop()
if !*forwarderMode {
@@ -771,4 +770,4 @@ func obfuscateBloom(bloom []byte) {
bloom[x/8] = 1 << uint(x%8) // set the bit number X
}
-}
+}
\ No newline at end of file
diff --git a/whisper/whisperv6/whisper.go b/whisper/whisperv6/whisper.go
index af848d2fdc79..3ded51010f63 100644
--- a/whisper/whisperv6/whisper.go
+++ b/whisper/whisperv6/whisper.go
@@ -1099,3 +1099,45 @@ func addBloom(a, b []byte) []byte {
}
return c
}
+
+func StandaloneWhisperService(cfg *Config) *Whisper {
+ if cfg == nil {
+ cfg = &DefaultConfig
+ }
+
+ whisper := &Whisper{
+ privateKeys: make(map[string]*ecdsa.PrivateKey),
+ symKeys: make(map[string][]byte),
+ envelopes: make(map[common.Hash]*Envelope),
+ expirations: make(map[uint32]mapset.Set),
+ peers: make(map[*Peer]struct{}),
+ messageQueue: make(chan *Envelope, messageQueueLimit),
+ p2pMsgQueue: make(chan *Envelope, messageQueueLimit),
+ quit: make(chan struct{}),
+ syncAllowance: DefaultSyncAllowance,
+ }
+
+ whisper.filters = NewFilters(whisper)
+
+ whisper.settings.Store(minPowIdx, cfg.MinimumAcceptedPOW)
+ whisper.settings.Store(maxMsgSizeIdx, cfg.MaxMessageSize)
+ whisper.settings.Store(overflowIdx, false)
+ whisper.settings.Store(restrictConnectionBetweenLightClientsIdx, cfg.RestrictConnectionBetweenLightClients)
+
+ // p2p whisper sub protocol handler
+ whisper.protocol = p2p.Protocol{
+ Name: ProtocolName,
+ Version: uint(ProtocolVersion),
+ Length: NumberOfMessageCodes,
+ Run: whisper.HandlePeer,
+ NodeInfo: func() interface{} {
+ return map[string]interface{}{
+ "version": ProtocolVersionStr,
+ "maxMessageSize": whisper.MaxMessageSize(),
+ "minimumPoW": whisper.MinPow(),
+ }
+ },
+ }
+
+ return whisper
+}
diff --git a/whisper/whisperv6/whisper_test.go b/whisper/whisperv6/whisper_test.go
index f1fa4dfdd27d..351ed6403ebe 100644
--- a/whisper/whisperv6/whisper_test.go
+++ b/whisper/whisperv6/whisper_test.go
@@ -930,6 +930,7 @@ func TestBloom(t *testing.T) {
}
}
+// newNode creates a new node using a default config.
func newNode(t *testing.T) *node.Node {
stack, err := node.New(&node.DefaultConfig)
if err != nil {
@@ -946,6 +947,7 @@ func newNode(t *testing.T) *node.Node {
return stack
}
+// getWhisperFromNode retrieves the Whisper service from the running node.
func getWhisperFromNode(stack *node.Node, t *testing.T) *Whisper {
var w *Whisper
err := stack.Lifecycle(&w)
From 076a9a5340f2e68a20525d5f67dfaf827e95a930 Mon Sep 17 00:00:00 2001
From: rene <41963722+renaynay@users.noreply.github.com>
Date: Thu, 4 Jun 2020 21:45:03 +0200
Subject: [PATCH 043/160] p2p/simulations uses `node.Lifecycle` instead of
`node.Service` (#21)
---
cmd/p2psim/main.go | 2 +-
les/api_test.go | 14 ++---
p2p/simulations/adapters/exec.go | 56 ++++++++-----------
p2p/simulations/adapters/inproc.go | 78 ++++++++++++---------------
p2p/simulations/adapters/types.go | 38 ++++++-------
p2p/simulations/connect_test.go | 4 +-
p2p/simulations/examples/ping-pong.go | 15 ++++--
p2p/simulations/http_test.go | 11 ++--
p2p/simulations/network.go | 12 ++---
p2p/simulations/network_test.go | 28 +++++-----
p2p/simulations/test.go | 2 +-
11 files changed, 125 insertions(+), 135 deletions(-)
diff --git a/cmd/p2psim/main.go b/cmd/p2psim/main.go
index f2c1bf970350..812954a68029 100644
--- a/cmd/p2psim/main.go
+++ b/cmd/p2psim/main.go
@@ -289,7 +289,7 @@ func createNode(ctx *cli.Context) error {
config.PrivateKey = privKey
}
if services := ctx.String("services"); services != "" {
- config.Services = strings.Split(services, ",")
+ config.Lifecycles = strings.Split(services, ",")
}
node, err := client.CreateNode(config)
if err != nil {
diff --git a/les/api_test.go b/les/api_test.go
index d6571fabe88f..72ed2f556ff3 100644
--- a/les/api_test.go
+++ b/les/api_test.go
@@ -55,7 +55,7 @@ func TestMain(m *testing.M) {
log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true))))
// register the Delivery service which will run as a devp2p
// protocol when using the exec adapter
- adapters.RegisterServices(services)
+ adapters.RegisterLifecycles(services)
os.Exit(m.Run())
}
@@ -392,7 +392,7 @@ func getCapacityInfo(ctx context.Context, t *testing.T, server *rpc.Client) (min
return
}
-var services = adapters.Services{
+var services = adapters.LifecycleConstructors{
"lesclient": newLesClientService,
"lesserver": newLesServerService,
}
@@ -414,7 +414,7 @@ func NewNetwork() (*simulations.Network, func(), error) {
return net, teardown, nil
}
-func NewAdapter(adapterType string, services adapters.Services) (adapter adapters.NodeAdapter, teardown func(), err error) {
+func NewAdapter(adapterType string, services adapters.LifecycleConstructors) (adapter adapters.NodeAdapter, teardown func(), err error) {
teardown = func() {}
switch adapterType {
case "sim":
@@ -454,7 +454,7 @@ func testSim(t *testing.T, serverCount, clientCount int, serverDir, clientDir []
for i := range clients {
clientconf := adapters.RandomNodeConfig()
- clientconf.Services = []string{"lesclient"}
+ clientconf.Lifecycles = []string{"lesclient"}
if len(clientDir) == clientCount {
clientconf.DataDir = clientDir[i]
}
@@ -467,7 +467,7 @@ func testSim(t *testing.T, serverCount, clientCount int, serverDir, clientDir []
for i := range servers {
serverconf := adapters.RandomNodeConfig()
- serverconf.Services = []string{"lesserver"}
+ serverconf.Lifecycles = []string{"lesserver"}
if len(serverDir) == serverCount {
serverconf.DataDir = serverDir[i]
}
@@ -492,14 +492,14 @@ func testSim(t *testing.T, serverCount, clientCount int, serverDir, clientDir []
return test(ctx, net, servers, clients)
}
-func newLesClientService(ctx *adapters.ServiceContext, stack *node.Node) (*LightEthereum, error) {
+func newLesClientService(stack *node.Node) (node.Lifecycle, error) {
config := eth.DefaultConfig
config.SyncMode = downloader.LightSync
config.Ethash.PowMode = ethash.ModeFake
return New(stack, &config)
}
-func newLesServerService(ctx *adapters.ServiceContext, stack *node.Node) (*eth.Ethereum, error) {
+func newLesServerService(stack *node.Node) (node.Lifecycle, error) {
config := eth.DefaultConfig
config.SyncMode = downloader.FullSync
config.LightServ = testServerCapacity
diff --git a/p2p/simulations/adapters/exec.go b/p2p/simulations/adapters/exec.go
index 18ec9c69b813..2a6d3aeaaa7e 100644
--- a/p2p/simulations/adapters/exec.go
+++ b/p2p/simulations/adapters/exec.go
@@ -75,11 +75,11 @@ func (e *ExecAdapter) Name() string {
// NewNode returns a new ExecNode using the given config
func (e *ExecAdapter) NewNode(config *NodeConfig) (Node, error) {
- if len(config.Services) == 0 {
- return nil, errors.New("node must have at least one service")
+ if len(config.Lifecycles) == 0 {
+ return nil, errors.New("node must have at least one service lifecycle")
}
- for _, service := range config.Services {
- if _, exists := serviceFuncs[service]; !exists {
+ for _, service := range config.Lifecycles {
+ if _, exists := lifecycleConstructorFuncs[service]; !exists {
return nil, fmt.Errorf("unknown node service %q", service)
}
}
@@ -263,7 +263,7 @@ func (n *ExecNode) waitForStartupJSON(ctx context.Context) (string, chan nodeSta
func (n *ExecNode) execCommand() *exec.Cmd {
return &exec.Cmd{
Path: reexec.Self(),
- Args: []string{"p2p-node", strings.Join(n.Config.Node.Services, ","), n.ID.String()},
+ Args: []string{"p2p-node", strings.Join(n.Config.Node.Lifecycles, ","), n.ID.String()},
}
}
@@ -436,40 +436,30 @@ func startExecNodeStack() (*node.Node, error) {
// register the services, collecting them into a map so we can wrap
// them in a snapshot service
- services := make(map[string]node.Service, len(serviceNames))
+ services := make(map[string]node.Lifecycle, len(serviceNames))
for _, name := range serviceNames {
- serviceFunc, exists := serviceFuncs[name]
+ lifecycleFunc, exists := lifecycleConstructorFuncs[name]
if !exists {
return nil, fmt.Errorf("unknown node service %q", err)
}
- constructor := func(nodeCtx *node.ServiceContext) (node.Service, error) {
- ctx := &ServiceContext{
- RPCDialer: &wsRPCDialer{addrs: conf.PeerAddrs},
- NodeContext: nodeCtx,
- Config: conf.Node,
- }
- if conf.Snapshots != nil {
- ctx.Snapshot = conf.Snapshots[name]
- }
- service, err := serviceFunc(ctx)
- if err != nil {
- return nil, err
- }
- services[name] = service
- return service, nil
+ ctx := &ServiceContext{
+ RPCDialer: &wsRPCDialer{addrs: conf.PeerAddrs},
+ NodeContext: stack.ServiceContext,
+ Config: conf.Node,
}
- if err := stack.Register(constructor); err != nil {
- return stack, fmt.Errorf("error registering service %q: %v", name, err)
+ if conf.Snapshots != nil {
+ ctx.Snapshot = conf.Snapshots[name]
}
+ service, err := lifecycleFunc(ctx, stack)
+ if err != nil {
+ return nil, err
+ }
+ services[name] = service
+ stack.RegisterLifecycle(service)
}
// register the snapshot service
- err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
- return &snapshotService{services}, nil
- })
- if err != nil {
- return stack, fmt.Errorf("error starting snapshot service: %v", err)
- }
+ stack.RegisterLifecycle(&snapshotService{services})
// start the stack
if err = stack.Start(); err != nil {
@@ -493,7 +483,7 @@ type nodeStartupJSON struct {
// snapshotService is a node.Service which wraps a list of services and
// exposes an API to generate a snapshot of those services
type snapshotService struct {
- services map[string]node.Service
+ services map[string]node.Lifecycle
}
func (s *snapshotService) APIs() []rpc.API {
@@ -508,7 +498,7 @@ func (s *snapshotService) Protocols() []p2p.Protocol {
return nil
}
-func (s *snapshotService) Start(*p2p.Server) error {
+func (s *snapshotService) Start() error {
return nil
}
@@ -518,7 +508,7 @@ func (s *snapshotService) Stop() error {
// SnapshotAPI provides an RPC method to create snapshots of services
type SnapshotAPI struct {
- services map[string]node.Service
+ services map[string]node.Lifecycle
}
func (api SnapshotAPI) Snapshot() (map[string][]byte, error) {
diff --git a/p2p/simulations/adapters/inproc.go b/p2p/simulations/adapters/inproc.go
index 651d9546aec2..48c5bd9753f2 100644
--- a/p2p/simulations/adapters/inproc.go
+++ b/p2p/simulations/adapters/inproc.go
@@ -37,29 +37,21 @@ import (
// SimAdapter is a NodeAdapter which creates in-memory simulation nodes and
// connects them using net.Pipe
type SimAdapter struct {
- pipe func() (net.Conn, net.Conn, error)
- mtx sync.RWMutex
- nodes map[enode.ID]*SimNode
- services map[string]ServiceFunc
+ pipe func() (net.Conn, net.Conn, error)
+ mtx sync.RWMutex
+ nodes map[enode.ID]*SimNode
+ lifecycles LifecycleConstructors
}
// NewSimAdapter creates a SimAdapter which is capable of running in-memory
// simulation nodes running any of the given services (the services to run on a
// particular node are passed to the NewNode function in the NodeConfig)
// the adapter uses a net.Pipe for in-memory simulated network connections
-func NewSimAdapter(services map[string]ServiceFunc) *SimAdapter {
+func NewSimAdapter(services LifecycleConstructors) *SimAdapter {
return &SimAdapter{
- pipe: pipes.NetPipe,
- nodes: make(map[enode.ID]*SimNode),
- services: services,
- }
-}
-
-func NewTCPAdapter(services map[string]ServiceFunc) *SimAdapter {
- return &SimAdapter{
- pipe: pipes.TCPPipe,
- nodes: make(map[enode.ID]*SimNode),
- services: services,
+ pipe: pipes.NetPipe,
+ nodes: make(map[enode.ID]*SimNode),
+ lifecycles: services,
}
}
@@ -85,11 +77,11 @@ func (s *SimAdapter) NewNode(config *NodeConfig) (Node, error) {
}
// check the services are valid
- if len(config.Services) == 0 {
+ if len(config.Lifecycles) == 0 {
return nil, errors.New("node must have at least one service")
}
- for _, service := range config.Services {
- if _, exists := s.services[service]; !exists {
+ for _, service := range config.Lifecycles {
+ if _, exists := s.lifecycles[service]; !exists {
return nil, fmt.Errorf("unknown node service %q", service)
}
}
@@ -119,7 +111,7 @@ func (s *SimAdapter) NewNode(config *NodeConfig) (Node, error) {
config: config,
node: n,
adapter: s,
- running: make(map[string]node.Service),
+ running: make(map[string]node.Lifecycle),
}
s.nodes[id] = simNode
return simNode, nil
@@ -179,7 +171,7 @@ type SimNode struct {
config *NodeConfig
adapter *SimAdapter
node *node.Node
- running map[string]node.Service
+ running map[string]node.Lifecycle
client *rpc.Client
registerOnce sync.Once
}
@@ -227,7 +219,7 @@ func (sn *SimNode) ServeRPC(conn *websocket.Conn) error {
// simulation_snapshot RPC method
func (sn *SimNode) Snapshots() (map[string][]byte, error) {
sn.lock.RLock()
- services := make(map[string]node.Service, len(sn.running))
+ services := make(map[string]node.Lifecycle, len(sn.running))
for name, service := range sn.running {
services[name] = service
}
@@ -252,35 +244,31 @@ func (sn *SimNode) Snapshots() (map[string][]byte, error) {
// Start registers the services and starts the underlying devp2p node
func (sn *SimNode) Start(snapshots map[string][]byte) error {
- newService := func(name string) func(ctx *node.ServiceContext) (node.Service, error) {
- return func(nodeCtx *node.ServiceContext) (node.Service, error) {
+ // ensure we only register the services once in the case of the node
+ // being stopped and then started again
+ var regErr error
+ sn.registerOnce.Do(func() {
+ for _, name := range sn.config.Lifecycles {
ctx := &ServiceContext{
RPCDialer: sn.adapter,
- NodeContext: nodeCtx,
+ NodeContext: sn.node.ServiceContext,
Config: sn.config,
}
if snapshots != nil {
ctx.Snapshot = snapshots[name]
}
- serviceFunc := sn.adapter.services[name]
- service, err := serviceFunc(ctx)
+ serviceFunc := sn.adapter.lifecycles[name]
+ service, err := serviceFunc(ctx, sn.node)
if err != nil {
- return nil, err
- }
- sn.running[name] = service
- return service, nil
- }
- }
-
- // ensure we only register the services once in the case of the node
- // being stopped and then started again
- var regErr error
- sn.registerOnce.Do(func() {
- for _, name := range sn.config.Services {
- if err := sn.node.Register(newService(name)); err != nil {
regErr = err
break
}
+ // if the service has already been registered, don't register it again.
+ if _, ok := sn.running[name]; ok {
+ continue
+ }
+ sn.running[name] = service
+ sn.node.RegisterLifecycle(service)
}
})
if regErr != nil {
@@ -316,17 +304,17 @@ func (sn *SimNode) Stop() error {
}
// Service returns a running service by name
-func (sn *SimNode) Service(name string) node.Service {
+func (sn *SimNode) Service(name string) node.Lifecycle {
sn.lock.RLock()
defer sn.lock.RUnlock()
return sn.running[name]
}
// Services returns a copy of the underlying services
-func (sn *SimNode) Services() []node.Service {
+func (sn *SimNode) Services() []node.Lifecycle {
sn.lock.RLock()
defer sn.lock.RUnlock()
- services := make([]node.Service, 0, len(sn.running))
+ services := make([]node.Lifecycle, 0, len(sn.running))
for _, service := range sn.running {
services = append(services, service)
}
@@ -334,10 +322,10 @@ func (sn *SimNode) Services() []node.Service {
}
// ServiceMap returns a map by names of the underlying services
-func (sn *SimNode) ServiceMap() map[string]node.Service {
+func (sn *SimNode) ServiceMap() map[string]node.Lifecycle {
sn.lock.RLock()
defer sn.lock.RUnlock()
- services := make(map[string]node.Service, len(sn.running))
+ services := make(map[string]node.Lifecycle, len(sn.running))
for name, service := range sn.running {
services[name] = service
}
diff --git a/p2p/simulations/adapters/types.go b/p2p/simulations/adapters/types.go
index 498723d1ac26..1ca60f4b9b58 100644
--- a/p2p/simulations/adapters/types.go
+++ b/p2p/simulations/adapters/types.go
@@ -96,11 +96,11 @@ type NodeConfig struct {
// Use an existing database instead of a temporary one if non-empty
DataDir string
- // Services are the names of the services which should be run when
- // starting the node (for SimNodes it should be the names of services
- // contained in SimAdapter.services, for other nodes it should be
- // services registered by calling the RegisterService function)
- Services []string
+ // Lifecycles are the names of the service lifecycles which should be run when
+ // starting the node (for SimNodes it should be the names of service lifecycles
+ // contained in SimAdapter.lifecycles, for other nodes it should be
+ // service lifecycles registered by calling the RegisterLifecycle function)
+ Lifecycles []string
// Properties are the names of the properties this node should hold
// within running services (e.g. "bootnode", "lightnode" or any custom values)
@@ -137,7 +137,7 @@ func (n *NodeConfig) MarshalJSON() ([]byte, error) {
confJSON := nodeConfigJSON{
ID: n.ID.String(),
Name: n.Name,
- Services: n.Services,
+ Services: n.Lifecycles,
Properties: n.Properties,
Port: n.Port,
EnableMsgEvents: n.EnableMsgEvents,
@@ -175,7 +175,7 @@ func (n *NodeConfig) UnmarshalJSON(data []byte) error {
}
n.Name = confJSON.Name
- n.Services = confJSON.Services
+ n.Lifecycles = confJSON.Services
n.Properties = confJSON.Properties
n.Port = confJSON.Port
n.EnableMsgEvents = confJSON.EnableMsgEvents
@@ -245,27 +245,29 @@ type RPCDialer interface {
DialRPC(id enode.ID) (*rpc.Client, error)
}
-// Services is a collection of services which can be run in a simulation
-type Services map[string]ServiceFunc
+// LifecycleConstructor allows a Lifecycle to be constructed during node start-up.
+// While the service-specific package usually takes care of Lifecycle creation and registration,
+// for testing purposes, it is useful to be able to construct a Lifecycle on spot.
+type LifecycleConstructor func(ctx *ServiceContext, stack *node.Node) (node.Lifecycle, error)
-// ServiceFunc returns a node.Service which can be used to boot a devp2p node
-type ServiceFunc func(ctx *ServiceContext) (node.Service, error)
+// LifecycleConstructors stores LifecycleConstructor functions to call during node start-up.
+type LifecycleConstructors map[string]LifecycleConstructor
-// serviceFuncs is a map of registered services which are used to boot devp2p
+// lifecycleConstructorFuncs is a map of registered services which are used to boot devp2p
// nodes
-var serviceFuncs = make(Services)
+var lifecycleConstructorFuncs = make(LifecycleConstructors)
-// RegisterServices registers the given Services which can then be used to
+// RegisterLifecycles registers the given Services which can then be used to
// start devp2p nodes using either the Exec or Docker adapters.
//
// It should be called in an init function so that it has the opportunity to
// execute the services before main() is called.
-func RegisterServices(services Services) {
- for name, f := range services {
- if _, exists := serviceFuncs[name]; exists {
+func RegisterLifecycles(lifecycles LifecycleConstructors) {
+ for name, f := range lifecycles {
+ if _, exists := lifecycleConstructorFuncs[name]; exists {
panic(fmt.Sprintf("node service already exists: %q", name))
}
- serviceFuncs[name] = f
+ lifecycleConstructorFuncs[name] = f
}
// now we have registered the services, run reexec.Init() which will
diff --git a/p2p/simulations/connect_test.go b/p2p/simulations/connect_test.go
index 32d18347d83a..0154a18b030f 100644
--- a/p2p/simulations/connect_test.go
+++ b/p2p/simulations/connect_test.go
@@ -26,8 +26,8 @@ import (
func newTestNetwork(t *testing.T, nodeCount int) (*Network, []enode.ID) {
t.Helper()
- adapter := adapters.NewSimAdapter(adapters.Services{
- "noopwoop": func(ctx *adapters.ServiceContext) (node.Service, error) {
+ adapter := adapters.NewSimAdapter(adapters.LifecycleConstructors{
+ "noopwoop": func(ctx *adapters.ServiceContext, stack *node.Node) (node.Lifecycle, error) {
return NewNoopService(nil), nil
},
})
diff --git a/p2p/simulations/examples/ping-pong.go b/p2p/simulations/examples/ping-pong.go
index cde2f3a677e2..678236f3552a 100644
--- a/p2p/simulations/examples/ping-pong.go
+++ b/p2p/simulations/examples/ping-pong.go
@@ -45,12 +45,17 @@ func main() {
log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(false))))
// register a single ping-pong service
- services := map[string]adapters.ServiceFunc{
- "ping-pong": func(ctx *adapters.ServiceContext) (node.Service, error) {
- return newPingPongService(ctx.Config.ID), nil
+ services := map[string]adapters.LifecycleConstructor{
+ "ping-pong": func(ctx *adapters.ServiceContext, stack *node.Node) (node.Lifecycle, error) {
+ pps := newPingPongService(ctx.Config.ID)
+ if err := stack.RegisterProtocols(pps.Protocols()); err != nil {
+ return nil, err
+ }
+ stack.RegisterAPIs(pps.APIs())
+ return pps, nil
},
}
- adapters.RegisterServices(services)
+ adapters.RegisterLifecycles(services)
// create the NodeAdapter
var adapter adapters.NodeAdapter
@@ -114,7 +119,7 @@ func (p *pingPongService) APIs() []rpc.API {
return nil
}
-func (p *pingPongService) Start(server *p2p.Server) error {
+func (p *pingPongService) Start() error {
p.log.Info("ping-pong service starting")
return nil
}
diff --git a/p2p/simulations/http_test.go b/p2p/simulations/http_test.go
index e88999f48b8c..1ecfb719fb96 100644
--- a/p2p/simulations/http_test.go
+++ b/p2p/simulations/http_test.go
@@ -64,12 +64,17 @@ type testService struct {
state atomic.Value
}
-func newTestService(ctx *adapters.ServiceContext) (node.Service, error) {
+func newTestService(ctx *adapters.ServiceContext, stack *node.Node) (node.Lifecycle, error) {
svc := &testService{
id: ctx.Config.ID,
peers: make(map[enode.ID]*testPeer),
}
svc.state.Store(ctx.Snapshot)
+
+ if err := stack.RegisterProtocols(svc.Protocols()); err != nil {
+ return nil, err
+ }
+ stack.RegisterAPIs(svc.APIs())
return svc, nil
}
@@ -126,7 +131,7 @@ func (t *testService) APIs() []rpc.API {
}}
}
-func (t *testService) Start(server *p2p.Server) error {
+func (t *testService) Start() error {
return nil
}
@@ -288,7 +293,7 @@ func (t *TestAPI) Events(ctx context.Context) (*rpc.Subscription, error) {
return rpcSub, nil
}
-var testServices = adapters.Services{
+var testServices = adapters.LifecycleConstructors{
"test": newTestService,
}
diff --git a/p2p/simulations/network.go b/p2p/simulations/network.go
index ef5451e77ec4..a54db4ea68d3 100644
--- a/p2p/simulations/network.go
+++ b/p2p/simulations/network.go
@@ -110,8 +110,8 @@ func (net *Network) NewNodeWithConfig(conf *adapters.NodeConfig) (*Node, error)
}
// if no services are configured, use the default service
- if len(conf.Services) == 0 {
- conf.Services = []string{net.DefaultService}
+ if len(conf.Lifecycles) == 0 {
+ conf.Lifecycles = []string{net.DefaultService}
}
// use the NodeAdapter to create the node
@@ -913,19 +913,19 @@ func (net *Network) snapshot(addServices []string, removeServices []string) (*Sn
snap.Nodes[i].Snapshots = snapshots
for _, addSvc := range addServices {
haveSvc := false
- for _, svc := range snap.Nodes[i].Node.Config.Services {
+ for _, svc := range snap.Nodes[i].Node.Config.Lifecycles {
if svc == addSvc {
haveSvc = true
break
}
}
if !haveSvc {
- snap.Nodes[i].Node.Config.Services = append(snap.Nodes[i].Node.Config.Services, addSvc)
+ snap.Nodes[i].Node.Config.Lifecycles = append(snap.Nodes[i].Node.Config.Lifecycles, addSvc)
}
}
if len(removeServices) > 0 {
var cleanedServices []string
- for _, svc := range snap.Nodes[i].Node.Config.Services {
+ for _, svc := range snap.Nodes[i].Node.Config.Lifecycles {
haveSvc := false
for _, rmSvc := range removeServices {
if rmSvc == svc {
@@ -938,7 +938,7 @@ func (net *Network) snapshot(addServices []string, removeServices []string) (*Sn
}
}
- snap.Nodes[i].Node.Config.Services = cleanedServices
+ snap.Nodes[i].Node.Config.Lifecycles = cleanedServices
}
}
for _, conn := range net.Conns {
diff --git a/p2p/simulations/network_test.go b/p2p/simulations/network_test.go
index ac1b06a80ca5..d5651441a2fe 100644
--- a/p2p/simulations/network_test.go
+++ b/p2p/simulations/network_test.go
@@ -41,8 +41,8 @@ func TestSnapshot(t *testing.T) {
// create snapshot from ring network
// this is a minimal service, whose protocol will take exactly one message OR close of connection before quitting
- adapter := adapters.NewSimAdapter(adapters.Services{
- "noopwoop": func(ctx *adapters.ServiceContext) (node.Service, error) {
+ adapter := adapters.NewSimAdapter(adapters.LifecycleConstructors{
+ "noopwoop": func(ctx *adapters.ServiceContext, stack *node.Node) (node.Lifecycle, error) {
return NewNoopService(nil), nil
},
})
@@ -165,8 +165,8 @@ OUTER:
// PART II
// load snapshot and verify that exactly same connections are formed
- adapter = adapters.NewSimAdapter(adapters.Services{
- "noopwoop": func(ctx *adapters.ServiceContext) (node.Service, error) {
+ adapter = adapters.NewSimAdapter(adapters.LifecycleConstructors{
+ "noopwoop": func(ctx *adapters.ServiceContext, stack *node.Node) (node.Lifecycle, error) {
return NewNoopService(nil), nil
},
})
@@ -256,8 +256,8 @@ OuterTwo:
t.Run("conns after load", func(t *testing.T) {
// Create new network.
n := NewNetwork(
- adapters.NewSimAdapter(adapters.Services{
- "noopwoop": func(ctx *adapters.ServiceContext) (node.Service, error) {
+ adapters.NewSimAdapter(adapters.LifecycleConstructors{
+ "noopwoop": func(ctx *adapters.ServiceContext, stack *node.Node) (node.Lifecycle, error) {
return NewNoopService(nil), nil
},
}),
@@ -288,7 +288,7 @@ OuterTwo:
// with each other and that a snapshot fully represents the desired topology
func TestNetworkSimulation(t *testing.T) {
// create simulation network with 20 testService nodes
- adapter := adapters.NewSimAdapter(adapters.Services{
+ adapter := adapters.NewSimAdapter(adapters.LifecycleConstructors{
"test": newTestService,
})
network := NewNetwork(adapter, &NetworkConfig{
@@ -437,7 +437,7 @@ func createTestNodesWithProperty(property string, count int, network *Network) (
// It then tests again whilst excluding a node ID from being returned.
// If a node ID is not returned, or more node IDs than expected are returned, the test fails.
func TestGetNodeIDs(t *testing.T) {
- adapter := adapters.NewSimAdapter(adapters.Services{
+ adapter := adapters.NewSimAdapter(adapters.LifecycleConstructors{
"test": newTestService,
})
network := NewNetwork(adapter, &NetworkConfig{
@@ -486,7 +486,7 @@ func TestGetNodeIDs(t *testing.T) {
// It then tests again whilst excluding a node from being returned.
// If a node is not returned, or more nodes than expected are returned, the test fails.
func TestGetNodes(t *testing.T) {
- adapter := adapters.NewSimAdapter(adapters.Services{
+ adapter := adapters.NewSimAdapter(adapters.LifecycleConstructors{
"test": newTestService,
})
network := NewNetwork(adapter, &NetworkConfig{
@@ -534,7 +534,7 @@ func TestGetNodes(t *testing.T) {
// TestGetNodesByID creates a set of nodes and attempts to retrieve a subset of them by ID
// If a node is not returned, or more nodes than expected are returned, the test fails.
func TestGetNodesByID(t *testing.T) {
- adapter := adapters.NewSimAdapter(adapters.Services{
+ adapter := adapters.NewSimAdapter(adapters.LifecycleConstructors{
"test": newTestService,
})
network := NewNetwork(adapter, &NetworkConfig{
@@ -579,7 +579,7 @@ func TestGetNodesByID(t *testing.T) {
// GetNodesByProperty is then checked for correctness by comparing the nodes returned to those initially created.
// If a node with a property is not found, or more nodes than expected are returned, the test fails.
func TestGetNodesByProperty(t *testing.T) {
- adapter := adapters.NewSimAdapter(adapters.Services{
+ adapter := adapters.NewSimAdapter(adapters.LifecycleConstructors{
"test": newTestService,
})
network := NewNetwork(adapter, &NetworkConfig{
@@ -624,7 +624,7 @@ func TestGetNodesByProperty(t *testing.T) {
// GetNodeIDsByProperty is then checked for correctness by comparing the node IDs returned to those initially created.
// If a node ID with a property is not found, or more nodes IDs than expected are returned, the test fails.
func TestGetNodeIDsByProperty(t *testing.T) {
- adapter := adapters.NewSimAdapter(adapters.Services{
+ adapter := adapters.NewSimAdapter(adapters.LifecycleConstructors{
"test": newTestService,
})
network := NewNetwork(adapter, &NetworkConfig{
@@ -705,8 +705,8 @@ func benchmarkMinimalServiceTmp(b *testing.B) {
// this is a minimal service, whose protocol will close a channel upon run of protocol
// making it possible to bench the time it takes for the service to start and protocol actually to be run
protoCMap := make(map[enode.ID]map[enode.ID]chan struct{})
- adapter := adapters.NewSimAdapter(adapters.Services{
- "noopwoop": func(ctx *adapters.ServiceContext) (node.Service, error) {
+ adapter := adapters.NewSimAdapter(adapters.LifecycleConstructors{
+ "noopwoop": func(ctx *adapters.ServiceContext, stack *node.Node) (node.Lifecycle, error) {
protoCMap[ctx.Config.ID] = make(map[enode.ID]chan struct{})
svc := NewNoopService(protoCMap[ctx.Config.ID])
return svc, nil
diff --git a/p2p/simulations/test.go b/p2p/simulations/test.go
index 687be6d0b8e3..0edb07b127f8 100644
--- a/p2p/simulations/test.go
+++ b/p2p/simulations/test.go
@@ -66,7 +66,7 @@ func (t *NoopService) APIs() []rpc.API {
return []rpc.API{}
}
-func (t *NoopService) Start(server *p2p.Server) error {
+func (t *NoopService) Start() error {
return nil
}
From 3eb4fc8a97607bb4442efabd8ac2037d2229cd9d Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Fri, 5 Jun 2020 13:56:33 +0200
Subject: [PATCH 044/160] fixed mailserver tests
---
whisper/mailserver/server_test.go | 35 ++++++++++++++++++++++++++++++-
whisper/whisperv6/whisper_test.go | 3 ++-
2 files changed, 36 insertions(+), 2 deletions(-)
diff --git a/whisper/mailserver/server_test.go b/whisper/mailserver/server_test.go
index 4f80e550aa22..c9820f5974f7 100644
--- a/whisper/mailserver/server_test.go
+++ b/whisper/mailserver/server_test.go
@@ -20,6 +20,7 @@ import (
"bytes"
"crypto/ecdsa"
"encoding/binary"
+ "github.com/ethereum/go-ethereum/node"
"io/ioutil"
"math/rand"
"testing"
@@ -89,7 +90,11 @@ func TestMailServer(t *testing.T) {
}
var server WMailServer
- shh = whisper.New(&whisper.DefaultConfig)
+
+ stack := newNode(t)
+ defer stack.Close()
+
+ shh = getWhisperFromNode(stack, t)
shh.RegisterServer(&server)
err = server.Init(shh, dir, password, powRequirement)
@@ -210,3 +215,31 @@ func createRequest(t *testing.T, p *ServerTestParams) *whisper.Envelope {
}
return env
}
+
+// newNode creates a new node using a default config and
+// creates and registers a new Whisper service on it.
+func newNode(t *testing.T) *node.Node {
+ stack, err := node.New(&node.DefaultConfig)
+ if err != nil {
+ t.Fatalf("could not create new node: %v", err)
+ }
+ err = whisper.New(stack, &whisper.DefaultConfig)
+ if err != nil {
+ t.Fatalf("could not create new whisper service: %v", err)
+ }
+ err = stack.Start()
+ if err != nil {
+ t.Fatalf("could not start node: %v", err)
+ }
+ return stack
+}
+
+// getWhisperFromNode retrieves the Whisper service from the running node.
+func getWhisperFromNode(stack *node.Node, t *testing.T) *whisper.Whisper {
+ var w *whisper.Whisper
+ err := stack.Lifecycle(&w)
+ if err != nil {
+ t.Fatalf("could not get whisper service from node: %v", err)
+ }
+ return w
+}
diff --git a/whisper/whisperv6/whisper_test.go b/whisper/whisperv6/whisper_test.go
index 351ed6403ebe..27873ca6917c 100644
--- a/whisper/whisperv6/whisper_test.go
+++ b/whisper/whisperv6/whisper_test.go
@@ -930,7 +930,8 @@ func TestBloom(t *testing.T) {
}
}
-// newNode creates a new node using a default config.
+// newNode creates a new node using a default config and
+// creates and registers a new Whisper service on it.
func newNode(t *testing.T) *node.Node {
stack, err := node.New(&node.DefaultConfig)
if err != nil {
From 6e41e4143067d23d1365ddac7e055351007852ff Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Fri, 5 Jun 2020 14:06:28 +0200
Subject: [PATCH 045/160] les tests passing
---
les/api_test.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/les/api_test.go b/les/api_test.go
index 72ed2f556ff3..1fcef8edacc2 100644
--- a/les/api_test.go
+++ b/les/api_test.go
@@ -492,14 +492,14 @@ func testSim(t *testing.T, serverCount, clientCount int, serverDir, clientDir []
return test(ctx, net, servers, clients)
}
-func newLesClientService(stack *node.Node) (node.Lifecycle, error) {
+func newLesClientService(ctx *adapters.ServiceContext, stack *node.Node) (node.Lifecycle, error) {
config := eth.DefaultConfig
config.SyncMode = downloader.LightSync
config.Ethash.PowMode = ethash.ModeFake
return New(stack, &config)
}
-func newLesServerService(stack *node.Node) (node.Lifecycle, error) {
+func newLesServerService(ctx *adapters.ServiceContext, stack *node.Node) (node.Lifecycle, error) {
config := eth.DefaultConfig
config.SyncMode = downloader.FullSync
config.LightServ = testServerCapacity
From 2df58f7250004a8eca9fc50da36eb67945b07b85 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Fri, 5 Jun 2020 14:54:59 +0200
Subject: [PATCH 046/160] changes after rebasing on master, likely bc of
serverpool pr
---
eth/backend.go | 2 +-
les/client.go | 5 +----
node/node.go | 10 ++++------
3 files changed, 6 insertions(+), 11 deletions(-)
diff --git a/eth/backend.go b/eth/backend.go
index 82e5fb6bcd74..46d5fedcbede 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -232,7 +232,7 @@ func New(stack *node.Node, config *Config) (*Ethereum, error) {
}
eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, gpoParams)
- eth.dialCandiates, err = eth.setupDiscovery(&stack.ServiceContext.Config.P2P)
+ eth.dialCandidates, err = eth.setupDiscovery(&stack.ServiceContext.Config.P2P)
if err != nil {
return nil, err
}
diff --git a/les/client.go b/les/client.go
index 58d5606ae903..c25b505c08e3 100644
--- a/les/client.go
+++ b/les/client.go
@@ -114,7 +114,7 @@ func New(stack *node.Node, config *eth.Config) (*LightEthereum, error) {
}
peers.subscribe((*vtSubscription)(leth.valueTracker))
- dnsdisc, err := leth.setupDiscovery(&ctx.Config.P2P)
+ dnsdisc, err := leth.setupDiscovery(&stack.ServiceContext.Config.P2P)
if err != nil {
return nil, err
}
@@ -304,9 +304,6 @@ func (s *LightEthereum) Start() error {
s.netRPCService = ethapi.NewPublicNetAPI(s.p2pServer, s.config.NetworkId)
- // clients are searching for the first advertised protocol in the list
- protocolVersion := AdvertiseProtocolVersions[0]
- s.serverPool.start(s.p2pServer, lesTopic(s.blockchain.Genesis().Hash(), protocolVersion))
return nil
}
diff --git a/node/node.go b/node/node.go
index e794d57721aa..692b10846ac2 100644
--- a/node/node.go
+++ b/node/node.go
@@ -17,6 +17,7 @@
package node
import (
+ "context"
"errors"
"fmt"
"io"
@@ -51,7 +52,7 @@ type Node struct {
server *p2p.Server // Currently running P2P networking layer
- ServiceContext *ServiceContext
+ ServiceContext *ServiceContext // TODO
lifecycles map[reflect.Type]Lifecycle // All registered backends, services, and auxiliary services that have a lifecycle
@@ -109,7 +110,7 @@ func New(conf *Config) (*Node, error) {
config: conf,
lifecycles: make(map[reflect.Type]Lifecycle),
ServiceContext: &ServiceContext{
- Config: *conf,
+ Config: *conf,
Lifecycles: make(map[reflect.Type]Lifecycle),
},
httpServerMap: make(map[string]*HTTPServer),
@@ -392,10 +393,7 @@ func (n *Node) configureRPC() error {
return err
}
// start HTTP server
- if err := n.RegisterLifecycle(server); err != nil {
- return err
- }
- n.log.Info("HTTP endpoint successfully opened", "url", fmt.Sprintf("http://%v/", server.ListenerAddr))
+ n.RegisterLifecycle(server)
}
// All API endpoints started successfully
return nil
From fd6623e10c338ed7807f8d8f64dbf915f0edaa9c Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Fri, 5 Jun 2020 15:27:00 +0200
Subject: [PATCH 047/160] fixed p2p testing package
---
p2p/testing/protocoltester.go | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/p2p/testing/protocoltester.go b/p2p/testing/protocoltester.go
index b80abcc264f5..159cd7d16d5e 100644
--- a/p2p/testing/protocoltester.go
+++ b/p2p/testing/protocoltester.go
@@ -53,11 +53,11 @@ type ProtocolTester struct {
// it takes as argument the pivot node id, the number of dummy peers and the
// protocol run function called on a peer connection by the p2p server
func NewProtocolTester(prvkey *ecdsa.PrivateKey, nodeCount int, run func(*p2p.Peer, p2p.MsgReadWriter) error) *ProtocolTester {
- services := adapters.Services{
- "test": func(ctx *adapters.ServiceContext) (node.Service, error) {
+ services := adapters.LifecycleConstructors{
+ "test": func(ctx *adapters.ServiceContext, stack *node.Node) (node.Lifecycle, error) {
return &testNode{run}, nil
},
- "mock": func(ctx *adapters.ServiceContext) (node.Service, error) {
+ "mock": func(ctx *adapters.ServiceContext, stack *node.Node) (node.Lifecycle, error) {
return newMockNode(), nil
},
}
@@ -66,7 +66,7 @@ func NewProtocolTester(prvkey *ecdsa.PrivateKey, nodeCount int, run func(*p2p.Pe
nodeConfig := &adapters.NodeConfig{
PrivateKey: prvkey,
EnableMsgEvents: true,
- Services: []string{"test"},
+ Lifecycles: []string{"test"},
}
if _, err := net.NewNodeWithConfig(nodeConfig); err != nil {
panic(err.Error())
@@ -80,7 +80,7 @@ func NewProtocolTester(prvkey *ecdsa.PrivateKey, nodeCount int, run func(*p2p.Pe
nodes := make([]*enode.Node, nodeCount)
for i := 0; i < nodeCount; i++ {
peers[i] = adapters.RandomNodeConfig()
- peers[i].Services = []string{"mock"}
+ peers[i].Lifecycles = []string{"mock"}
if _, err := net.NewNodeWithConfig(peers[i]); err != nil {
panic(fmt.Sprintf("error initializing peer %v: %v", peers[i].ID, err))
}
@@ -142,7 +142,7 @@ func (t *testNode) APIs() []rpc.API {
return nil
}
-func (t *testNode) Start(server *p2p.Server) error {
+func (t *testNode) Start() error {
return nil
}
From ebde331dc90987adcec9ff791a71b7174f12d36f Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Mon, 8 Jun 2020 08:51:53 +0200
Subject: [PATCH 048/160] removing unnecessary methods and fixing todos
---
cmd/geth/main.go | 6 +++++-
node/node.go | 10 +++++-----
node/rpcstack.go | 17 ++++-------------
3 files changed, 14 insertions(+), 19 deletions(-)
diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index 5f71eb5324ca..dfc928f5946a 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -365,6 +365,10 @@ func geth(ctx *cli.Context) error {
func startNode(ctx *cli.Context, stack *node.Node, ethBackend *eth.Ethereum, lesBackend *les.LightEthereum) {
debug.Memsize.Add("node", stack)
+ if ethBackend == nil && lesBackend == nil {
+ utils.Fatalf("No backend service found") // TODO is this error okay?
+ }
+
// Start up the node itself
utils.StartNode(stack)
@@ -462,7 +466,7 @@ func startNode(ctx *cli.Context, stack *node.Node, ethBackend *eth.Ethereum, les
if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" {
utils.Fatalf("Light clients do not support mining")
}
- // Check if node's backend is eth and that it exists // TODO fix this section up -- not sure if it's doing what it's supposed to.
+ // Check if node's backend is eth and that it exists
if ethBackend == nil {
utils.Fatalf("Ethereum service not running: backend is not an eth backend")
}
diff --git a/node/node.go b/node/node.go
index 692b10846ac2..de74545281ec 100644
--- a/node/node.go
+++ b/node/node.go
@@ -423,16 +423,16 @@ func (n *Node) stopInProc() {
// startIPC initializes and starts the IPC RPC endpoint.
func (n *Node) startIPC() error {
- if n.ipc.Endpoint() == "" {
+ if n.ipc.endpoint == "" {
return nil // IPC disabled.
}
- listener, handler, err := rpc.StartIPCEndpoint(n.ipc.Endpoint(), n.rpcAPIs)
+ listener, handler, err := rpc.StartIPCEndpoint(n.ipc.endpoint, n.rpcAPIs)
if err != nil {
return err
}
n.ipc.Listener = listener
n.ipc.handler = handler
- n.log.Info("IPC endpoint opened", "url", n.ipc.Endpoint())
+ n.log.Info("IPC endpoint opened", "url", n.ipc.endpoint)
return nil
}
@@ -442,7 +442,7 @@ func (n *Node) stopIPC() {
n.ipc.Listener.Close()
n.ipc.Listener = nil
- n.log.Info("IPC endpoint closed", "url", n.ipc.Endpoint())
+ n.log.Info("IPC endpoint closed", "url", n.ipc.endpoint)
}
if n.ipc.Srv != nil {
n.ipc.Srv.Stop()
@@ -589,7 +589,7 @@ func (n *Node) AccountManager() *accounts.Manager {
// IPCEndpoint retrieves the current IPC endpoint used by the protocol stack.
func (n *Node) IPCEndpoint() string {
- return n.ipc.Endpoint()
+ return n.ipc.endpoint
}
// HTTPEndpoint retrieves the current HTTP endpoint used by the protocol stack.
diff --git a/node/rpcstack.go b/node/rpcstack.go
index 3b439134a64d..1020a0d043bd 100644
--- a/node/rpcstack.go
+++ b/node/rpcstack.go
@@ -57,13 +57,14 @@ type HTTPServer struct {
GQLHandler http.Handler
}
-// TODO document
+// Start starts the HTTPServer's HTTP server. // TODO I don't like the way this is written
func (h *HTTPServer) Start() error {
go h.Server.Serve(h.Listener)
log.Info("HTTP endpoint successfully opened", "url", fmt.Sprintf("http://%v/", h.Listener.Addr()))
return nil
}
+// Stop shuts down the HTTPServer's HTTP server. // TODO I don't like the way this is written
func (h *HTTPServer) Stop() error {
if h.Server != nil {
url := fmt.Sprintf("http://%v/", h.Listener.Addr())
@@ -79,22 +80,12 @@ func (h *HTTPServer) Stop() error {
return nil
}
-// Handler returns the handler of the HTTPServer
-func (h *HTTPServer) Handler() http.Handler {
- return h.handler
-}
-
-// TODO document
+// SetHandler assigns the given handler to the HTTPServer.
func (h *HTTPServer) SetHandler(handler http.Handler) {
h.handler = handler
}
-// TODO is this really necessary?
-func (h *HTTPServer) Endpoint() string {
- return h.endpoint
-}
-
-// TODO is this necessary?
+// SetEndpoints assigns the given endpoint to the HTTPServer.
func (h *HTTPServer) SetEndpoint(endpoint string) {
h.endpoint = endpoint
}
From 06bf009fb97913102f0995328e69496b7a4d4638 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Mon, 8 Jun 2020 09:00:52 +0200
Subject: [PATCH 049/160] removing more unnecessary methods
---
node/node.go | 60 ++++++++++++++++++----------------------------------
1 file changed, 21 insertions(+), 39 deletions(-)
diff --git a/node/node.go b/node/node.go
index de74545281ec..ccb80abf7606 100644
--- a/node/node.go
+++ b/node/node.go
@@ -52,7 +52,7 @@ type Node struct {
server *p2p.Server // Currently running P2P networking layer
- ServiceContext *ServiceContext // TODO
+ ServiceContext *ServiceContext // TODO rename to LifecycleContext or just NodeContext?
lifecycles map[reflect.Type]Lifecycle // All registered backends, services, and auxiliary services that have a lifecycle
@@ -592,25 +592,7 @@ func (n *Node) IPCEndpoint() string {
return n.ipc.endpoint
}
-// HTTPEndpoint retrieves the current HTTP endpoint used by the protocol stack.
-func (n *Node) HTTPEndpoint() string {
- n.lock.Lock()
- defer n.lock.Unlock()
-
- for _, httpServer := range n.httpServerMap {
- if httpServer.RPCAllowed {
- if httpServer.Listener != nil {
- return httpServer.Listener.Addr().String()
- }
- return httpServer.endpoint
- }
- }
-
- return "" // TODO should return an empty string if http server not configured?
-}
-
-// WSEndpoint retrieves the current WS endpoint
-// used by the protocol stack.
+// WSEndpoint retrieves the current WS endpoint used by the protocol stack.
func (n *Node) WSEndpoint() string {
n.lock.Lock()
defer n.lock.Unlock()
@@ -624,7 +606,7 @@ func (n *Node) WSEndpoint() string {
}
}
- return "" // TODO should return an empty string if ws server not configured?
+ return n.config.WSEndpoint() // TODO should it return the endpoint from the node's config? Or just an empty string?
}
// EventMux retrieves the event multiplexer used by all the network services in
@@ -633,6 +615,24 @@ func (n *Node) EventMux() *event.TypeMux {
return n.eventmux
}
+// Lifecycle retrieves a currently running Lifecycle registered of a specific type.
+func (n *Node) Lifecycle(lifecycle interface{}) error {
+ n.lock.RLock()
+ defer n.lock.RUnlock()
+
+ // Short circuit if the node's not running
+ if !n.running() {
+ return ErrNodeStopped
+ }
+ // Otherwise try to find the service to return
+ element := reflect.ValueOf(lifecycle).Elem()
+ if running, ok := n.lifecycles[element.Type()]; ok {
+ element.Set(reflect.ValueOf(running))
+ return nil
+ }
+ return ErrServiceUnknown
+}
+
// OpenDatabase opens an existing database with the given name (or creates one if no
// previous can be found) from within the node's instance directory. If the node is
// ephemeral, a memory database is returned.
@@ -668,24 +668,6 @@ func (n *Node) ResolvePath(x string) string {
return n.config.ResolvePath(x)
}
-// Lifecycle retrieves a currently running Lifecycle registered of a specific type.
-func (n *Node) Lifecycle(lifecycle interface{}) error {
- n.lock.RLock()
- defer n.lock.RUnlock()
-
- // Short circuit if the node's not running
- if !n.running() {
- return ErrNodeStopped
- }
- // Otherwise try to find the service to return
- element := reflect.ValueOf(lifecycle).Elem()
- if running, ok := n.lifecycles[element.Type()]; ok {
- element.Set(reflect.ValueOf(running))
- return nil
- }
- return ErrServiceUnknown
-}
-
// apis returns the collection of RPC descriptors this node offers.
func (n *Node) apis() []rpc.API {
return []rpc.API{
From 4ce4c4097240952017cefc51593f564430a06fe2 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Mon, 8 Jun 2020 14:23:57 +0200
Subject: [PATCH 050/160] instead of passing both les and eth explicitly, fetch
backend from node
---
cmd/geth/chaincmd.go | 14 +++++++-------
cmd/geth/config.go | 11 +++++------
cmd/geth/consolecmd.go | 30 ++++++++++++++++++++++--------
cmd/geth/main.go | 14 ++++++++++----
cmd/utils/flags.go | 28 +++++++++++++++++++---------
ethstats/ethstats.go | 25 +++++++++++++++----------
graphql/graphql_test.go | 2 +-
graphql/service.go | 15 ++++-----------
node/node.go | 4 ++--
9 files changed, 85 insertions(+), 58 deletions(-)
diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go
index 07485306492e..247c202bca17 100644
--- a/cmd/geth/chaincmd.go
+++ b/cmd/geth/chaincmd.go
@@ -240,7 +240,7 @@ func initGenesis(ctx *cli.Context) error {
utils.Fatalf("invalid genesis file: %v", err)
}
// Open an initialise both full and light databases
- stack, _, _ := makeFullNode(ctx)
+ stack := makeFullNode(ctx)
defer stack.Close()
for _, name := range []string{"chaindata", "lightchaindata"} {
@@ -277,7 +277,7 @@ func importChain(ctx *cli.Context) error {
utils.SetupMetrics(ctx)
// Start system runtime metrics collection
go metrics.CollectProcessMetrics(3 * time.Second)
- stack, _, _ := makeFullNode(ctx)
+ stack := makeFullNode(ctx)
defer stack.Close()
chain, db := utils.MakeChain(ctx, stack, false)
@@ -371,7 +371,7 @@ func exportChain(ctx *cli.Context) error {
if len(ctx.Args()) < 1 {
utils.Fatalf("This command requires an argument.")
}
- stack, _, _ := makeFullNode(ctx)
+ stack := makeFullNode(ctx)
defer stack.Close()
chain, _ := utils.MakeChain(ctx, stack, true)
@@ -406,7 +406,7 @@ func importPreimages(ctx *cli.Context) error {
if len(ctx.Args()) < 1 {
utils.Fatalf("This command requires an argument.")
}
- stack, _, _ := makeFullNode(ctx)
+ stack := makeFullNode(ctx)
defer stack.Close()
db := utils.MakeChainDatabase(ctx, stack)
@@ -424,7 +424,7 @@ func exportPreimages(ctx *cli.Context) error {
if len(ctx.Args()) < 1 {
utils.Fatalf("This command requires an argument.")
}
- stack, _, _ := makeFullNode(ctx)
+ stack := makeFullNode(ctx)
defer stack.Close()
db := utils.MakeChainDatabase(ctx, stack)
@@ -446,7 +446,7 @@ func copyDb(ctx *cli.Context) error {
utils.Fatalf("Source ancient chain directory path argument missing")
}
// Initialize a new chain for the running node to sync into
- stack, _, _ := makeFullNode(ctx)
+ stack := makeFullNode(ctx)
defer stack.Close()
chain, chainDb := utils.MakeChain(ctx, stack, false)
@@ -554,7 +554,7 @@ func confirmAndRemoveDB(database string, kind string) {
}
func dump(ctx *cli.Context) error {
- stack, _, _ := makeFullNode(ctx)
+ stack := makeFullNode(ctx)
defer stack.Close()
chain, chainDb := utils.MakeChain(ctx, stack, true)
diff --git a/cmd/geth/config.go b/cmd/geth/config.go
index df452b8b4fd8..60d9d0006689 100644
--- a/cmd/geth/config.go
+++ b/cmd/geth/config.go
@@ -20,7 +20,6 @@ import (
"bufio"
"errors"
"fmt"
- "github.com/ethereum/go-ethereum/les"
"os"
"reflect"
"unicode"
@@ -145,9 +144,9 @@ func enableWhisper(ctx *cli.Context) bool {
return false
}
-func makeFullNode(ctx *cli.Context) (*node.Node, *eth.Ethereum, *les.LightEthereum) {
+func makeFullNode(ctx *cli.Context) *node.Node {
stack, cfg := makeConfigNode(ctx)
- ethBackend, lesBackend := utils.RegisterEthService(stack, &cfg.Eth)
+ utils.RegisterEthService(stack, &cfg.Eth)
// Whisper must be explicitly enabled by specifying at least 1 whisper flag or in dev mode
shhEnabled := enableWhisper(ctx)
@@ -166,14 +165,14 @@ func makeFullNode(ctx *cli.Context) (*node.Node, *eth.Ethereum, *les.LightEthere
}
// Configure GraphQL if requested
if ctx.GlobalIsSet(utils.GraphQLEnabledFlag.Name) {
- utils.RegisterGraphQLService(stack, ethBackend, lesBackend, cfg.Node.GraphQLEndpoint(), cfg.Node.GraphQLCors, cfg.Node.GraphQLVirtualHosts, cfg.Node.HTTPTimeouts)
+ utils.RegisterGraphQLService(stack, cfg.Node.GraphQLEndpoint(), cfg.Node.GraphQLCors, cfg.Node.GraphQLVirtualHosts, cfg.Node.HTTPTimeouts)
}
// Add the Ethereum Stats daemon if requested.
if cfg.Ethstats.URL != "" {
- utils.RegisterEthStatsService(stack, ethBackend, lesBackend, cfg.Ethstats.URL)
+ utils.RegisterEthStatsService(stack, cfg.Ethstats.URL)
}
- return stack, ethBackend, lesBackend
+ return stack
}
// dumpConfig is the dumpconfig command.
diff --git a/cmd/geth/consolecmd.go b/cmd/geth/consolecmd.go
index 226a2537bac4..7df26ff20f3b 100644
--- a/cmd/geth/consolecmd.go
+++ b/cmd/geth/consolecmd.go
@@ -18,6 +18,8 @@ package main
import (
"fmt"
+ "github.com/ethereum/go-ethereum/eth"
+ "github.com/ethereum/go-ethereum/les"
"os"
"os/signal"
"path/filepath"
@@ -78,12 +80,18 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/JavaScript-Cons
func localConsole(ctx *cli.Context) error {
// Create and start the node based on the CLI flags
prepare(ctx)
- node, ethBackend, lesBackend := makeFullNode(ctx)
- startNode(ctx, node, ethBackend, lesBackend)
- defer node.Close()
+ stack := makeFullNode(ctx)
+ // fetch backends
+ var ethBackend *eth.Ethereum
+ stack.Lifecycle(ðBackend)
+ var lesBackend *les.LightEthereum
+ stack.Lifecycle(&lesBackend)
+
+ startNode(ctx, stack, ethBackend, lesBackend)
+ defer stack.Close()
// Attach to the newly started node and start the JavaScript console
- client, err := node.Attach()
+ client, err := stack.Attach()
if err != nil {
utils.Fatalf("Failed to attach to the inproc geth: %v", err)
}
@@ -190,12 +198,18 @@ func dialRPC(endpoint string) (*rpc.Client, error) {
// everything down.
func ephemeralConsole(ctx *cli.Context) error {
// Create and start the node based on the CLI flags
- node, ethBackend, lesBackend := makeFullNode(ctx)
- startNode(ctx, node, ethBackend, lesBackend)
- defer node.Close()
+ stack := makeFullNode(ctx)
+ // fetch backends
+ var ethBackend *eth.Ethereum
+ stack.Lifecycle(ðBackend)
+ var lesBackend *les.LightEthereum
+ stack.Lifecycle(&lesBackend)
+
+ startNode(ctx, stack, ethBackend, lesBackend)
+ defer stack.Close()
// Attach to the newly started node and start the JavaScript console
- client, err := node.Attach()
+ client, err := stack.Attach()
if err != nil {
utils.Fatalf("Failed to attach to the inproc geth: %v", err)
}
diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index dfc928f5946a..4cd0b53bcb69 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -351,11 +351,17 @@ func geth(ctx *cli.Context) error {
return fmt.Errorf("invalid command: %q", args[0])
}
prepare(ctx)
- node, ethBackend, lesBackend := makeFullNode(ctx)
- defer node.Close()
- startNode(ctx, node, ethBackend, lesBackend)
+ stack := makeFullNode(ctx)
+ // fetch backends
+ var ethBackend *eth.Ethereum
+ stack.ServiceContext.Lifecycle(ðBackend)
+ var lesBackend *les.LightEthereum
+ stack.ServiceContext.Lifecycle(&lesBackend)
- node.Wait()
+ defer stack.Close()
+ startNode(ctx, stack, ethBackend, lesBackend)
+
+ stack.Wait()
return nil
}
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index 25faf1b91ec2..e88d6a5b4300 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -20,6 +20,7 @@ package utils
import (
"crypto/ecdsa"
"fmt"
+ "github.com/ethereum/go-ethereum/internal/ethapi"
"io"
"io/ioutil"
"math/big"
@@ -1691,13 +1692,12 @@ func setDNSDiscoveryDefaults(cfg *eth.Config, genesis common.Hash) {
}
// RegisterEthService adds an Ethereum client to the stack.
-func RegisterEthService(stack *node.Node, cfg *eth.Config) (*eth.Ethereum, *les.LightEthereum) {
+func RegisterEthService(stack *node.Node, cfg *eth.Config) {
if cfg.SyncMode == downloader.LightSync {
- backend, err := les.New(stack, cfg)
+ _, err := les.New(stack, cfg)
if err != nil {
Fatalf("Failed to register the Ethereum service: %w", err)
}
- return nil, backend
} else {
backend, err := eth.New(stack, cfg)
if err != nil {
@@ -1707,7 +1707,6 @@ func RegisterEthService(stack *node.Node, cfg *eth.Config) (*eth.Ethereum, *les.
ls, _ := les.NewLesServer(backend, cfg)
backend.AddLesServer(ls)
}
- return backend, nil
}
}
@@ -1720,16 +1719,27 @@ func RegisterShhService(stack *node.Node, cfg *whisper.Config) {
// RegisterEthStatsService configures the Ethereum Stats daemon and adds it to
// the given node.
-func RegisterEthStatsService(stack *node.Node, ethBackend *eth.Ethereum, lesBackend *les.LightEthereum, url string) {
- if err := ethstats.New(stack, ethBackend, lesBackend, url); err != nil {
+func RegisterEthStatsService(stack *node.Node, url string) {
+ if err := ethstats.New(stack, url); err != nil {
Fatalf("Failed to register the Ethereum Stats service: %w", err)
}
}
// RegisterGraphQLService is a utility function to construct a new service and register it against a node.
-func RegisterGraphQLService(stack *node.Node, ethBackend *eth.Ethereum, lesBackend *les.LightEthereum, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) {
- if err := graphql.New(stack, ethBackend, lesBackend, endpoint, cors, vhosts, timeouts); err != nil {
- Fatalf("Failed to register the GraphQL service: %w", err)
+func RegisterGraphQLService(stack *node.Node, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) {
+ var backend ethapi.Backend
+ // fetch backend
+ var ethServ *eth.Ethereum
+ if err := stack.ServiceContext.Lifecycle(ðServ); err == nil {
+ backend = ethServ.APIBackend
+ }
+ var lesServ *les.LightEthereum
+ if err := stack.ServiceContext.Lifecycle(&lesServ); err == nil {
+ backend = lesServ.ApiBackend
+ }
+ // create new graphQL service
+ if err := graphql.New(stack, backend, endpoint, cors, vhosts, timeouts); err != nil {
+ Fatalf("Failed to register the GraphQL service: %v", err)
}
}
diff --git a/ethstats/ethstats.go b/ethstats/ethstats.go
index 594c844d1e59..72c63cf33e49 100644
--- a/ethstats/ethstats.go
+++ b/ethstats/ethstats.go
@@ -83,31 +83,36 @@ type Service struct {
}
// New returns a monitoring service ready for stats reporting.
-func New(node *node.Node, ethBackend *eth.Ethereum, lesBackend *les.LightEthereum, url string) error { // TODO, this thing receives the backend explicitly, does whatever, registers itself
+func New(node *node.Node, url string) error {
// Parse the netstats connection url
re := regexp.MustCompile("([^:@]*)(:([^@]*))?@(.+)")
parts := re.FindStringSubmatch(url)
if len(parts) != 5 {
return fmt.Errorf("invalid netstats url: \"%s\", should be nodename:secret@host:port", url)
}
-
- // fetch type of Backend
- if ethBackend == nil && lesBackend == nil {
- return errors.New("no Ethereum service") // TODO is this okay to return?
- }
ethstats := &Service{
server: node.Server(),
- eth: ethBackend,
- les: lesBackend,
- engine: ethBackend.Engine(),
node: parts[1],
pass: parts[3],
host: parts[4],
pongCh: make(chan struct{}),
histCh: make(chan []uint64, 1),
}
- node.RegisterLifecycle(ethstats)
+ // fetch backend
+ var ethServ *eth.Ethereum
+ if err := node.ServiceContext.Lifecycle(ðServ); err == nil {
+ ethstats.eth = ethServ
+ ethstats.engine = ethServ.Engine()
+ }
+ var lesServ *les.LightEthereum
+ if err := node.ServiceContext.Lifecycle(&lesServ); err == nil {
+ ethstats.les = lesServ
+ ethstats.engine = lesServ.Engine()
+ }
+ // TODO check to make sure at least one backend is not nil?
+
+ node.RegisterLifecycle(ethstats)
return nil
}
diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go
index 66a589829dfa..3a56f9556f88 100644
--- a/graphql/graphql_test.go
+++ b/graphql/graphql_test.go
@@ -148,7 +148,7 @@ func createNode(t *testing.T, gqlEnabled bool) *node.Node {
}
// create gql service
- err = New(stack,ethBackend,nil, testEndpoint, []string{}, []string{}, rpc.DefaultHTTPTimeouts)
+ err = New(stack, ethBackend.APIBackend, testEndpoint, []string{}, []string{}, rpc.DefaultHTTPTimeouts)
if err != nil {
t.Fatalf("could not create graphql service: %v", err)
}
diff --git a/graphql/service.go b/graphql/service.go
index 58897c9ffa24..52c8ab1a7bc8 100644
--- a/graphql/service.go
+++ b/graphql/service.go
@@ -18,8 +18,6 @@ package graphql
import (
"errors"
- "github.com/ethereum/go-ethereum/eth"
- "github.com/ethereum/go-ethereum/les"
"net/http"
"github.com/ethereum/go-ethereum/internal/ethapi"
@@ -36,17 +34,12 @@ type Service struct {
}
// New constructs a new GraphQL service instance.
-func New(stack *node.Node, ethBackend *eth.Ethereum, lesBackend *les.LightEthereum, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) error {
+func New(stack *node.Node, backend ethapi.Backend, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) error {
service := new(Service)
- // add backend
- if ethBackend != nil {
- service.backend = ethBackend.APIBackend
- } else if lesBackend != nil {
- service.backend = lesBackend.ApiBackend
- } else {
- return errors.New("no Ethereum service")
+ if backend == nil {
+ return errors.New("No backend found") // TODO should this be a fatal error?
}
-
+ service.backend = backend
// check if http server with given endpoint exists and enable graphQL on it
server := stack.ExistingHTTPServer(endpoint)
if server != nil {
diff --git a/node/node.go b/node/node.go
index ccb80abf7606..b6fdf7404292 100644
--- a/node/node.go
+++ b/node/node.go
@@ -208,6 +208,7 @@ func (n *Node) RegisterLifecycle(lifecycle Lifecycle) {
}
n.lifecycles[kind] = lifecycle
+ n.ServiceContext.Lifecycles[kind] = lifecycle
}
// RegisterProtocols adds backend's protocols to the node's p2p server
@@ -305,7 +306,6 @@ func (n *Node) Start() error {
return err
}
started = append(started, lifecycle)
- n.ServiceContext.Lifecycles[reflect.TypeOf(lifecycle)] = lifecycle
}
// Finish initializing the service context
@@ -620,7 +620,7 @@ func (n *Node) Lifecycle(lifecycle interface{}) error {
n.lock.RLock()
defer n.lock.RUnlock()
- // Short circuit if the node's not running
+ // Short circuit if the node's not running // TODO can i ignore this?
if !n.running() {
return ErrNodeStopped
}
From cc3daf688fafec04bd10da20d3ed102e8bc28875 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Mon, 8 Jun 2020 15:19:43 +0200
Subject: [PATCH 051/160] typo
---
cmd/geth/consolecmd.go | 4 ++--
cmd/geth/main.go | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/cmd/geth/consolecmd.go b/cmd/geth/consolecmd.go
index 7df26ff20f3b..1e06b4a8b3ca 100644
--- a/cmd/geth/consolecmd.go
+++ b/cmd/geth/consolecmd.go
@@ -81,7 +81,7 @@ func localConsole(ctx *cli.Context) error {
// Create and start the node based on the CLI flags
prepare(ctx)
stack := makeFullNode(ctx)
- // fetch backends
+ // fetch backend
var ethBackend *eth.Ethereum
stack.Lifecycle(ðBackend)
var lesBackend *les.LightEthereum
@@ -199,7 +199,7 @@ func dialRPC(endpoint string) (*rpc.Client, error) {
func ephemeralConsole(ctx *cli.Context) error {
// Create and start the node based on the CLI flags
stack := makeFullNode(ctx)
- // fetch backends
+ // fetch backend
var ethBackend *eth.Ethereum
stack.Lifecycle(ðBackend)
var lesBackend *les.LightEthereum
diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index 4cd0b53bcb69..8cfbc4de310e 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -352,7 +352,7 @@ func geth(ctx *cli.Context) error {
}
prepare(ctx)
stack := makeFullNode(ctx)
- // fetch backends
+ // fetch backend
var ethBackend *eth.Ethereum
stack.ServiceContext.Lifecycle(ðBackend)
var lesBackend *les.LightEthereum
From 3f132b5d8695223594ceff2b008c139efc2684b2 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Mon, 8 Jun 2020 15:28:38 +0200
Subject: [PATCH 052/160] fetch backend from service context rather than node
since node isnt started yet
---
cmd/geth/consolecmd.go | 8 ++++----
miner/stress_clique.go | 2 +-
miner/stress_ethash.go | 2 +-
node/node.go | 2 +-
4 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/cmd/geth/consolecmd.go b/cmd/geth/consolecmd.go
index 1e06b4a8b3ca..464a6cc7732e 100644
--- a/cmd/geth/consolecmd.go
+++ b/cmd/geth/consolecmd.go
@@ -83,9 +83,9 @@ func localConsole(ctx *cli.Context) error {
stack := makeFullNode(ctx)
// fetch backend
var ethBackend *eth.Ethereum
- stack.Lifecycle(ðBackend)
+ stack.ServiceContext.Lifecycle(ðBackend)
var lesBackend *les.LightEthereum
- stack.Lifecycle(&lesBackend)
+ stack.ServiceContext.Lifecycle(&lesBackend)
startNode(ctx, stack, ethBackend, lesBackend)
defer stack.Close()
@@ -201,9 +201,9 @@ func ephemeralConsole(ctx *cli.Context) error {
stack := makeFullNode(ctx)
// fetch backend
var ethBackend *eth.Ethereum
- stack.Lifecycle(ðBackend)
+ stack.ServiceContext.Lifecycle(ðBackend)
var lesBackend *les.LightEthereum
- stack.Lifecycle(&lesBackend)
+ stack.ServiceContext.Lifecycle(&lesBackend)
startNode(ctx, stack, ethBackend, lesBackend)
defer stack.Close()
diff --git a/miner/stress_clique.go b/miner/stress_clique.go
index a3a63e38c45a..a69dfbd69d9d 100644
--- a/miner/stress_clique.go
+++ b/miner/stress_clique.go
@@ -96,7 +96,7 @@ func main() {
for _, node := range nodes {
var ethereum *eth.Ethereum
- if err := node.Lifecycle(ðereum); err != nil { // TODO does this work?
+ if err := node.ServiceContext.Lifecycle(ðereum); err != nil {
panic(err)
}
if err := ethereum.StartMining(1); err != nil {
diff --git a/miner/stress_ethash.go b/miner/stress_ethash.go
index ed999f90cec4..1cb5396ce323 100644
--- a/miner/stress_ethash.go
+++ b/miner/stress_ethash.go
@@ -94,7 +94,7 @@ func main() {
for _, node := range nodes {
var ethereum *eth.Ethereum
- if err := node.Lifecycle(ðereum); err != nil { // TODO does this work?
+ if err := node.ServiceContext.Lifecycle(ðereum); err != nil {
panic(err)
}
if err := ethereum.StartMining(1); err != nil {
diff --git a/node/node.go b/node/node.go
index b6fdf7404292..f5716f56916b 100644
--- a/node/node.go
+++ b/node/node.go
@@ -620,7 +620,7 @@ func (n *Node) Lifecycle(lifecycle interface{}) error {
n.lock.RLock()
defer n.lock.RUnlock()
- // Short circuit if the node's not running // TODO can i ignore this?
+ // Short circuit if the node's not running
if !n.running() {
return ErrNodeStopped
}
From 306f390247d773e7e83cea1bd394c01b59ea628b Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Mon, 8 Jun 2020 16:07:55 +0200
Subject: [PATCH 053/160] fixing some broken tests
---
cmd/faucet/faucet.go | 4 ++--
mobile/geth.go | 4 ++--
node/service_test.go | 14 +++-----------
3 files changed, 7 insertions(+), 15 deletions(-)
diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go
index 7f66eae87fe7..6f6cb39069f0 100644
--- a/cmd/faucet/faucet.go
+++ b/cmd/faucet/faucet.go
@@ -241,14 +241,14 @@ func newFaucet(genesis *core.Genesis, port int, enodes []*discv5.Node, network u
cfg.SyncMode = downloader.LightSync
cfg.NetworkId = network
cfg.Genesis = genesis
- lesBackend, err := les.New(stack, &cfg)
+ _, err = les.New(stack, &cfg)
if err != nil {
return nil, fmt.Errorf("Failed to register the Ethereum service: %w", err)
}
// Assemble the ethstats monitoring and reporting service'
if stats != "" {
- if err := ethstats.New(stack, nil, lesBackend, stats); err != nil {
+ if err := ethstats.New(stack, stats); err != nil {
return nil, err
}
}
diff --git a/mobile/geth.go b/mobile/geth.go
index d93b9f1cd0cc..053c304f6738 100644
--- a/mobile/geth.go
+++ b/mobile/geth.go
@@ -175,13 +175,13 @@ func NewNode(datadir string, config *NodeConfig) (stack *Node, _ error) {
ethConf.SyncMode = downloader.LightSync
ethConf.NetworkId = uint64(config.EthereumNetworkID)
ethConf.DatabaseCache = config.EthereumDatabaseCache
- lesBackend, err := les.New(rawStack, ðConf)
+ _, err = les.New(rawStack, ðConf)
if err != nil {
return nil, fmt.Errorf("ethereum init: %v", err)
}
// If netstats reporting is requested, do it
if config.EthereumNetStats != "" {
- if err := ethstats.New(rawStack, nil, lesBackend, config.EthereumNetStats); err != nil {
+ if err := ethstats.New(rawStack, config.EthereumNetStats); err != nil {
return nil, fmt.Errorf("netstats init: %v", err)
}
}
diff --git a/node/service_test.go b/node/service_test.go
index 183ca4915330..80f40aeeb68b 100644
--- a/node/service_test.go
+++ b/node/service_test.go
@@ -72,25 +72,17 @@ func TestContextLifecycles(t *testing.T) {
noop := NewNoop()
stack.RegisterLifecycle(noop)
- isC, err := NewInstrumentedService()
- if err != nil {
- t.Fatalf("could not create instrumented service %v", err)
- }
-
- isB, err := NewInstrumentedService()
+ is, err := NewInstrumentedService()
if err != nil {
t.Fatalf("could not create instrumented service %v", err)
}
- isB.startHook = func() {
+ is.startHook = func() {
if err := stack.ServiceContext.Lifecycle(&noop); err != nil {
t.Errorf("former service not found: %v", err)
}
- if err := stack.ServiceContext.Lifecycle(&isC); err != ErrServiceUnknown {
- t.Errorf("latters lookup error mismatch: have %v, want %v", err, ErrServiceUnknown)
- }
}
- stack.RegisterLifecycle(isB)
+ stack.RegisterLifecycle(is)
// Start the protocol stack and ensure services are constructed in order
if err := stack.Start(); err != nil {
From fddc6bd4228578b5a3d344b72284d1aae03c60ae Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Mon, 8 Jun 2020 17:40:16 +0200
Subject: [PATCH 054/160] linted
---
cmd/geth/consolecmd.go | 4 ++--
cmd/utils/flags.go | 2 +-
cmd/wnode/main.go | 2 +-
console/console_test.go | 1 -
ethstats/ethstats.go | 2 +-
graphql/graphql_test.go | 24 ++++++++++++-----------
graphql/service.go | 12 ++++++------
les/client.go | 3 +--
miner/miner.go | 2 +-
node/api.go | 27 +++++++++++++-------------
node/endpoints.go | 15 ---------------
node/node_example_test.go | 4 ++--
node/node_test.go | 32 +++++++++++++++----------------
node/rpcstack.go | 6 +++---
node/rpcstack_test.go | 10 +++++-----
node/service.go | 6 +++---
node/utils_test.go | 19 +++++++++---------
p2p/testing/protocoltester.go | 2 +-
whisper/mailserver/server_test.go | 2 +-
whisper/whisperv6/whisper.go | 2 +-
whisper/whisperv6/whisper_test.go | 6 +-----
21 files changed, 81 insertions(+), 102 deletions(-)
diff --git a/cmd/geth/consolecmd.go b/cmd/geth/consolecmd.go
index 464a6cc7732e..c35863a1e157 100644
--- a/cmd/geth/consolecmd.go
+++ b/cmd/geth/consolecmd.go
@@ -18,8 +18,6 @@ package main
import (
"fmt"
- "github.com/ethereum/go-ethereum/eth"
- "github.com/ethereum/go-ethereum/les"
"os"
"os/signal"
"path/filepath"
@@ -28,6 +26,8 @@ import (
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/console"
+ "github.com/ethereum/go-ethereum/eth"
+ "github.com/ethereum/go-ethereum/les"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/rpc"
"gopkg.in/urfave/cli.v1"
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index e88d6a5b4300..fa7b13af45ba 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -20,7 +20,6 @@ package utils
import (
"crypto/ecdsa"
"fmt"
- "github.com/ethereum/go-ethereum/internal/ethapi"
"io"
"io/ioutil"
"math/big"
@@ -50,6 +49,7 @@ import (
"github.com/ethereum/go-ethereum/ethstats"
"github.com/ethereum/go-ethereum/graphql"
"github.com/ethereum/go-ethereum/internal/flags"
+ "github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/les"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
diff --git a/cmd/wnode/main.go b/cmd/wnode/main.go
index f20c00ceb183..bdb0d306b760 100644
--- a/cmd/wnode/main.go
+++ b/cmd/wnode/main.go
@@ -770,4 +770,4 @@ func obfuscateBloom(bloom []byte) {
bloom[x/8] = 1 << uint(x%8) // set the bit number X
}
-}
\ No newline at end of file
+}
diff --git a/console/console_test.go b/console/console_test.go
index c6fd90be7f14..80a2253997c0 100644
--- a/console/console_test.go
+++ b/console/console_test.go
@@ -114,7 +114,6 @@ func newTester(t *testing.T, confOverride func(*eth.Config)) *tester {
t.Fatalf("failed to register Ethereum protocol: %v", err)
}
-
// Start the node and assemble the JavaScript console around it
if err = stack.Start(); err != nil {
t.Fatalf("failed to start test stack: %v", err)
diff --git a/ethstats/ethstats.go b/ethstats/ethstats.go
index 72c63cf33e49..e40e973cbb13 100644
--- a/ethstats/ethstats.go
+++ b/ethstats/ethstats.go
@@ -22,7 +22,6 @@ import (
"encoding/json"
"errors"
"fmt"
- "github.com/ethereum/go-ethereum/node"
"math/big"
"net/http"
"regexp"
@@ -40,6 +39,7 @@ import (
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/les"
"github.com/ethereum/go-ethereum/log"
+ "github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p"
"github.com/gorilla/websocket"
)
diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go
index 3a56f9556f88..29b8c469cebf 100644
--- a/graphql/graphql_test.go
+++ b/graphql/graphql_test.go
@@ -18,14 +18,16 @@ package graphql
import (
"fmt"
- "github.com/ethereum/go-ethereum/eth"
- "github.com/ethereum/go-ethereum/node"
- "github.com/ethereum/go-ethereum/rpc"
- "github.com/stretchr/testify/assert"
"io/ioutil"
"net/http"
"strings"
"testing"
+
+ "github.com/ethereum/go-ethereum/eth"
+ "github.com/ethereum/go-ethereum/node"
+ "github.com/ethereum/go-ethereum/rpc"
+
+ "github.com/stretchr/testify/assert"
)
var testEndpoint = "127.0.0.1:9393"
@@ -73,7 +75,7 @@ func TestMultiplexedServer(t *testing.T) {
// Tests that a graphQL request is successfully handled when graphql is enabled on the specified endpoint
func TestGraphQLHTTPOnSamePort_GQLRequest_Successful(t *testing.T) {
- stack := createNode(t,true)
+ stack := createNode(t, true)
defer stack.Close()
// start node
if err := stack.Start(); err != nil {
@@ -93,7 +95,7 @@ func TestGraphQLHTTPOnSamePort_GQLRequest_Successful(t *testing.T) {
t.Fatalf("could not read from response body: %v", err)
}
expected := "{\"data\":{\"block\":{\"number\":\"0x0\"}}}"
- assert.Equal(t, expected,string(bodyBytes))
+ assert.Equal(t, expected, string(bodyBytes))
}
// Tests that a graphQL request is not handled successfully when graphql is not enabled on the specified endpoint
@@ -130,10 +132,10 @@ func TestGraphQLHTTPOnSamePort_GQLRequest_Unsuccessful(t *testing.T) {
func createNode(t *testing.T, gqlEnabled bool) *node.Node {
stack, err := node.New(&node.Config{
- HTTPHost: "127.0.0.1",
- HTTPPort: 9393,
- WSHost: "127.0.0.1",
- WSPort: 9393,
+ HTTPHost: "127.0.0.1",
+ HTTPPort: 9393,
+ WSHost: "127.0.0.1",
+ WSPort: 9393,
})
if err != nil {
t.Fatalf("could not create node: %v", err)
@@ -142,7 +144,7 @@ func createNode(t *testing.T, gqlEnabled bool) *node.Node {
return stack
}
// create backend
- ethBackend, err := eth.New(stack, ð.DefaultConfig)
+ ethBackend, err := eth.New(stack, ð.DefaultConfig)
if err != nil {
t.Fatalf("could not create eth backend: %v", err)
}
diff --git a/graphql/service.go b/graphql/service.go
index 52c8ab1a7bc8..eb62f2f0695a 100644
--- a/graphql/service.go
+++ b/graphql/service.go
@@ -29,7 +29,7 @@ import (
// Service encapsulates a GraphQL service.
type Service struct {
- backend ethapi.Backend // The backend that queries will operate on.
+ backend ethapi.Backend // The backend that queries will operate on.
graphqlServer *node.HTTPServer
}
@@ -63,12 +63,12 @@ func New(stack *node.Node, backend ethapi.Backend, endpoint string, cors, vhosts
}
// create the http server
gqlServer := &node.HTTPServer{
- Vhosts: vhosts,
+ Vhosts: vhosts,
CorsAllowedOrigins: cors,
- Timeouts: timeouts,
- GQLAllowed: true,
- GQLHandler: handler,
- Srv: rpc.NewServer(),
+ Timeouts: timeouts,
+ GQLAllowed: true,
+ GQLHandler: handler,
+ Srv: rpc.NewServer(),
}
gqlServer.SetEndpoint(endpoint)
stack.RegisterHTTPServer(endpoint, gqlServer)
diff --git a/les/client.go b/les/client.go
index c25b505c08e3..dd62aa82bcb7 100644
--- a/les/client.go
+++ b/les/client.go
@@ -110,7 +110,7 @@ func New(stack *node.Node, config *eth.Config) (*LightEthereum, error) {
bloomRequests: make(chan chan *bloombits.Retrieval),
bloomIndexer: eth.NewBloomIndexer(chainDb, params.BloomBitsBlocksClient, params.HelperTrieConfirmations),
valueTracker: lpc.NewValueTracker(lespayDb, &mclock.System{}, requestList, time.Minute, 1/float64(time.Hour), 1/float64(time.Hour*100), 1/float64(time.Hour*1000)),
- p2pServer: stack.Server(),
+ p2pServer: stack.Server(),
}
peers.subscribe((*vtSubscription)(leth.valueTracker))
@@ -171,7 +171,6 @@ func New(stack *node.Node, config *eth.Config) (*LightEthereum, error) {
}
leth.ApiBackend.gpo = gasprice.NewOracle(leth.ApiBackend, gpoParams)
-
// Register the backend on the node
stack.RegisterAPIs(leth.APIs())
if err := stack.RegisterProtocols(leth.Protocols()); err != nil {
diff --git a/miner/miner.go b/miner/miner.go
index d7d5872dba2f..5249118cae14 100644
--- a/miner/miner.go
+++ b/miner/miner.go
@@ -36,7 +36,7 @@ import (
)
// Backend wraps all methods required for mining.
-type Backend interface {
+type Backend interface {
BlockChain() *core.BlockChain
TxPool() *core.TxPool
}
diff --git a/node/api.go b/node/api.go
index 3badf6209073..0f21156e75bd 100644
--- a/node/api.go
+++ b/node/api.go
@@ -190,13 +190,13 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
}
// configure http server
httpServer := &HTTPServer{
- host: *host,
- port: *port,
- endpoint: endpoint,
- Srv: rpc.NewServer(),
+ host: *host,
+ port: *port,
+ endpoint: endpoint,
+ Srv: rpc.NewServer(),
CorsAllowedOrigins: allowedOrigins,
- Vhosts: allowedVHosts,
- Whitelist: modules,
+ Vhosts: allowedVHosts,
+ Whitelist: modules,
}
// create handler
httpServer.handler = NewHTTPHandlerStack(httpServer.Srv, httpServer.CorsAllowedOrigins, httpServer.Vhosts)
@@ -269,7 +269,6 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
return true, nil
}
-
origins := api.node.config.WSOrigins
if allowedOrigins != nil {
origins = nil
@@ -294,13 +293,13 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
}
wsServer := &HTTPServer{
- Srv: rpc.NewServer(),
- endpoint: endpoint,
- host: *host,
- port: *port,
- Whitelist: modules,
- WsOrigins: origins,
- WSAllowed: true,
+ Srv: rpc.NewServer(),
+ endpoint: endpoint,
+ host: *host,
+ port: *port,
+ Whitelist: modules,
+ WsOrigins: origins,
+ WSAllowed: true,
}
wsServer.handler = wsServer.Srv.WebsocketHandler(wsServer.WsOrigins)
diff --git a/node/endpoints.go b/node/endpoints.go
index 1baa1b5c417f..1f85a5213168 100644
--- a/node/endpoints.go
+++ b/node/endpoints.go
@@ -48,21 +48,6 @@ func StartHTTPEndpoint(endpoint string, timeouts rpc.HTTPTimeouts, handler http.
return httpSrv, listener.Addr(), err
}
-// startWSEndpoint starts a websocket endpoint.
-func startWSEndpoint(endpoint string, handler http.Handler) (*http.Server, net.Addr, error) {
- // start the HTTP listener
- var (
- listener net.Listener
- err error
- )
- if listener, err = net.Listen("tcp", endpoint); err != nil {
- return nil, nil, err
- }
- wsSrv := &http.Server{Handler: handler}
- go wsSrv.Serve(listener)
- return wsSrv, listener.Addr(), err
-}
-
// checkModuleAvailability checks that all names given in modules are actually
// available API services. It assumes that the MetadataApi module ("rpc") is always available;
// the registration of this "rpc" module happens in NewServer() and is thus common to all endpoints.
diff --git a/node/node_example_test.go b/node/node_example_test.go
index 9363bbc18379..6ad74aaca885 100644
--- a/node/node_example_test.go
+++ b/node/node_example_test.go
@@ -31,8 +31,8 @@ import (
// - Stop() error - method invoked when the node terminates the service
type SampleLifecycle struct{}
-func (s *SampleLifecycle) Start() error { fmt.Println("Service starting..."); return nil }
-func (s *SampleLifecycle) Stop() error { fmt.Println("Service stopping..."); return nil }
+func (s *SampleLifecycle) Start() error { fmt.Println("Service starting..."); return nil }
+func (s *SampleLifecycle) Stop() error { fmt.Println("Service stopping..."); return nil }
func ExampleLifecycle() {
// Create a network node to run protocols with the default values.
diff --git a/node/node_test.go b/node/node_test.go
index 337b55525b6e..e8ac35318a59 100644
--- a/node/node_test.go
+++ b/node/node_test.go
@@ -132,23 +132,23 @@ func TestLifecycleLifeCycle(t *testing.T) {
stopped := make(map[string]bool)
// Create a batch of instrumented services
- lifecycles := map[string]Lifecycle{
+ lifecycles := map[string]Lifecycle{
"A": &InstrumentedServiceA{
InstrumentedService{
startHook: func() { started["A"] = true },
- stopHook: func() { stopped["A"] = true },
+ stopHook: func() { stopped["A"] = true },
},
},
"B": &InstrumentedServiceB{
InstrumentedService{
startHook: func() { started["B"] = true },
- stopHook: func() { stopped["B"] = true },
+ stopHook: func() { stopped["B"] = true },
},
},
"C": &InstrumentedServiceC{
InstrumentedService{
startHook: func() { started["C"] = true },
- stopHook: func() { stopped["C"] = true },
+ stopHook: func() { stopped["C"] = true },
},
},
}
@@ -192,23 +192,23 @@ func TestLifecycleStartupAbortion(t *testing.T) {
stopped := make(map[string]bool)
// Create a batch of instrumented services
- lifecycles := map[string]Lifecycle{
+ lifecycles := map[string]Lifecycle{
"A": &InstrumentedServiceA{
InstrumentedService{
startHook: func() { started["A"] = true },
- stopHook: func() { stopped["A"] = true },
+ stopHook: func() { stopped["A"] = true },
},
},
"B": &InstrumentedServiceB{
InstrumentedService{
startHook: func() { started["B"] = true },
- stopHook: func() { stopped["B"] = true },
+ stopHook: func() { stopped["B"] = true },
},
},
"C": &InstrumentedServiceC{
InstrumentedService{
startHook: func() { started["C"] = true },
- stopHook: func() { stopped["C"] = true },
+ stopHook: func() { stopped["C"] = true },
},
},
}
@@ -219,7 +219,7 @@ func TestLifecycleStartupAbortion(t *testing.T) {
// Register a service that fails to construct itself
failure := errors.New("fail")
- failer := &InstrumentedService{ start: failure }
+ failer := &InstrumentedService{start: failure}
stack.RegisterLifecycle(failer)
// Start the protocol stack and ensure all started services stop
@@ -250,23 +250,23 @@ func TestLifecycleTerminationGuarantee(t *testing.T) {
stopped := make(map[string]bool)
// Create a batch of instrumented services
- lifecycles := map[string]Lifecycle{
+ lifecycles := map[string]Lifecycle{
"A": &InstrumentedServiceA{
InstrumentedService{
startHook: func() { started["A"] = true },
- stopHook: func() { stopped["A"] = true },
+ stopHook: func() { stopped["A"] = true },
},
},
"B": &InstrumentedServiceB{
InstrumentedService{
startHook: func() { started["B"] = true },
- stopHook: func() { stopped["B"] = true },
+ stopHook: func() { stopped["B"] = true },
},
},
"C": &InstrumentedServiceC{
InstrumentedService{
startHook: func() { started["C"] = true },
- stopHook: func() { stopped["C"] = true },
+ stopHook: func() { stopped["C"] = true },
},
},
}
@@ -277,7 +277,7 @@ func TestLifecycleTerminationGuarantee(t *testing.T) {
// Register a service that fails to shot down cleanly
failure := errors.New("fail")
- failer := &InstrumentedService{ stop: failure }
+ failer := &InstrumentedService{stop: failure}
stack.RegisterLifecycle(failer)
// Start the protocol stack, and ensure that a failing shut down terminates all // TODO, deleting loop because constructors no longer stored on node.
@@ -396,8 +396,8 @@ func startHTTP(t *testing.T) *Node {
conf := &Config{
HTTPHost: "127.0.0.1",
HTTPPort: 7453,
- WSHost: "127.0.0.1",
- WSPort: 7453,
+ WSHost: "127.0.0.1",
+ WSPort: 7453,
}
node, err := New(conf)
if err != nil {
diff --git a/node/rpcstack.go b/node/rpcstack.go
index 1020a0d043bd..d5b5168e9bdd 100644
--- a/node/rpcstack.go
+++ b/node/rpcstack.go
@@ -20,7 +20,6 @@ import (
"compress/gzip"
"context"
"fmt"
- "github.com/ethereum/go-ethereum/rpc"
"io"
"io/ioutil"
"net"
@@ -29,15 +28,16 @@ import (
"sync"
"github.com/ethereum/go-ethereum/log"
+ "github.com/ethereum/go-ethereum/rpc"
"github.com/rs/cors"
)
type HTTPServer struct {
handler http.Handler
Srv *rpc.Server
- Server *http.Server
+ Server *http.Server
- Listener net.Listener
+ Listener net.Listener
endpoint string
host string
diff --git a/node/rpcstack_test.go b/node/rpcstack_test.go
index 364bceb54094..799b138a6917 100644
--- a/node/rpcstack_test.go
+++ b/node/rpcstack_test.go
@@ -12,7 +12,7 @@ import (
func TestNewWebsocketUpgradeHandler_websocket(t *testing.T) {
h := &HTTPServer{
- Srv: rpc.NewServer(),
+ Srv: rpc.NewServer(),
WSAllowed: true,
}
handler := h.NewWebsocketUpgradeHandler(nil, h.Srv.WebsocketHandler([]string{}))
@@ -43,10 +43,10 @@ func TestNewWebsocketUpgradeHandler_websocket(t *testing.T) {
// Tests that a ws handler can be added to and enabled on an existing HTTPServer
func TestWSAllowed(t *testing.T) {
stack, err := New(&Config{
- HTTPHost: DefaultHTTPHost,
- HTTPPort: 9393,
- WSHost: DefaultHTTPHost,
- WSPort: 9393,
+ HTTPHost: DefaultHTTPHost,
+ HTTPPort: 9393,
+ WSHost: DefaultHTTPHost,
+ WSPort: 9393,
})
if err != nil {
t.Fatalf("could not create node: %v", err)
diff --git a/node/service.go b/node/service.go
index 53ed61017f39..072933fe6050 100644
--- a/node/service.go
+++ b/node/service.go
@@ -31,9 +31,9 @@ import (
// as well as utility methods to operate on the service environment.
type ServiceContext struct {
Config Config
- Lifecycles map[reflect.Type]Lifecycle // TODO should this be in the service context or should it be on the node itself .. ?
- EventMux *event.TypeMux // Event multiplexer used for decoupled notifications
- AccountManager *accounts.Manager // Account manager created by the node.
+ Lifecycles map[reflect.Type]Lifecycle // TODO should this be in the service context or should it be on the node itself .. ?
+ EventMux *event.TypeMux // Event multiplexer used for decoupled notifications
+ AccountManager *accounts.Manager // Account manager created by the node.
}
// OpenDatabase opens an existing database with the given name (or creates one
diff --git a/node/utils_test.go b/node/utils_test.go
index 0755e0411171..17c45a238fd6 100644
--- a/node/utils_test.go
+++ b/node/utils_test.go
@@ -24,8 +24,8 @@ import "github.com/ethereum/go-ethereum/p2p"
// NoopLifecycle is a trivial implementation of the Service interface.
type NoopLifecycle struct{}
-func (s *NoopLifecycle) Start() error { return nil }
-func (s *NoopLifecycle) Stop() error { return nil }
+func (s *NoopLifecycle) Start() error { return nil }
+func (s *NoopLifecycle) Stop() error { return nil }
func NewNoop() *Noop {
noop := new(Noop)
@@ -36,22 +36,21 @@ func NewNoop() *Noop {
// signatures but different outer types.
type Noop struct{ NoopLifecycle }
-
// InstrumentedService is an implementation of Lifecycle for which all interface
// methods can be instrumented both return value as well as event hook wise.
type InstrumentedService struct {
- start error
- stop error
+ start error
+ stop error
- startHook func()
- stopHook func()
+ startHook func()
+ stopHook func()
protocols []p2p.Protocol
}
-type InstrumentedServiceA struct { InstrumentedService }
-type InstrumentedServiceB struct { InstrumentedService }
-type InstrumentedServiceC struct { InstrumentedService }
+type InstrumentedServiceA struct{ InstrumentedService }
+type InstrumentedServiceB struct{ InstrumentedService }
+type InstrumentedServiceC struct{ InstrumentedService }
func NewInstrumentedService() (*InstrumentedService, error) {
return new(InstrumentedService), nil
diff --git a/p2p/testing/protocoltester.go b/p2p/testing/protocoltester.go
index 159cd7d16d5e..9dd53e71226a 100644
--- a/p2p/testing/protocoltester.go
+++ b/p2p/testing/protocoltester.go
@@ -66,7 +66,7 @@ func NewProtocolTester(prvkey *ecdsa.PrivateKey, nodeCount int, run func(*p2p.Pe
nodeConfig := &adapters.NodeConfig{
PrivateKey: prvkey,
EnableMsgEvents: true,
- Lifecycles: []string{"test"},
+ Lifecycles: []string{"test"},
}
if _, err := net.NewNodeWithConfig(nodeConfig); err != nil {
panic(err.Error())
diff --git a/whisper/mailserver/server_test.go b/whisper/mailserver/server_test.go
index c9820f5974f7..959a1e32f629 100644
--- a/whisper/mailserver/server_test.go
+++ b/whisper/mailserver/server_test.go
@@ -20,7 +20,6 @@ import (
"bytes"
"crypto/ecdsa"
"encoding/binary"
- "github.com/ethereum/go-ethereum/node"
"io/ioutil"
"math/rand"
"testing"
@@ -28,6 +27,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/node"
whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
)
diff --git a/whisper/whisperv6/whisper.go b/whisper/whisperv6/whisper.go
index 3ded51010f63..a58e1710c9f6 100644
--- a/whisper/whisperv6/whisper.go
+++ b/whisper/whisperv6/whisper.go
@@ -21,7 +21,6 @@ import (
"crypto/ecdsa"
"crypto/sha256"
"fmt"
- "github.com/ethereum/go-ethereum/node"
"math"
"runtime"
"sync"
@@ -31,6 +30,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log"
+ "github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
diff --git a/whisper/whisperv6/whisper_test.go b/whisper/whisperv6/whisper_test.go
index 27873ca6917c..a8056d6776e1 100644
--- a/whisper/whisperv6/whisper_test.go
+++ b/whisper/whisperv6/whisper_test.go
@@ -20,12 +20,12 @@ import (
"bytes"
"crypto/ecdsa"
"crypto/sha256"
- "github.com/ethereum/go-ethereum/node"
mrand "math/rand"
"testing"
"time"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/node"
"golang.org/x/crypto/pbkdf2"
)
@@ -538,7 +538,6 @@ func TestCustomization(t *testing.T) {
defer w.SetMinimumPowTest(DefaultMinimumPoW)
defer w.SetMaxMessageSize(DefaultMaxMessageSize)
w.Start()
-
const smallPoW = 0.00001
@@ -635,7 +634,6 @@ func TestSymmetricSendCycle(t *testing.T) {
defer w.SetMinimumPowTest(DefaultMinimumPoW)
defer w.SetMaxMessageSize(DefaultMaxMessageSize)
w.Start()
-
filter1, err := generateFilter(t, true)
if err != nil {
@@ -730,7 +728,6 @@ func TestSymmetricSendWithoutAKey(t *testing.T) {
defer w.SetMinimumPowTest(DefaultMinimumPoW)
defer w.SetMaxMessageSize(DefaultMaxMessageSize)
w.Start()
-
filter, err := generateFilter(t, true)
if err != nil {
@@ -804,7 +801,6 @@ func TestSymmetricSendKeyMismatch(t *testing.T) {
defer w.SetMinimumPowTest(DefaultMinimumPoW)
defer w.SetMaxMessageSize(DefaultMaxMessageSize)
w.Start()
-
filter, err := generateFilter(t, true)
if err != nil {
From 6c91bb43f7d9ebfd4cea6de89a874cb35b274a3e Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Tue, 9 Jun 2020 13:00:15 +0200
Subject: [PATCH 055/160] not passing backends to startnode
---
cmd/geth/consolecmd.go | 18 ++----------------
cmd/geth/main.go | 22 ++++++++--------------
2 files changed, 10 insertions(+), 30 deletions(-)
diff --git a/cmd/geth/consolecmd.go b/cmd/geth/consolecmd.go
index c35863a1e157..5a88414a4230 100644
--- a/cmd/geth/consolecmd.go
+++ b/cmd/geth/consolecmd.go
@@ -26,8 +26,6 @@ import (
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/console"
- "github.com/ethereum/go-ethereum/eth"
- "github.com/ethereum/go-ethereum/les"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/rpc"
"gopkg.in/urfave/cli.v1"
@@ -81,13 +79,7 @@ func localConsole(ctx *cli.Context) error {
// Create and start the node based on the CLI flags
prepare(ctx)
stack := makeFullNode(ctx)
- // fetch backend
- var ethBackend *eth.Ethereum
- stack.ServiceContext.Lifecycle(ðBackend)
- var lesBackend *les.LightEthereum
- stack.ServiceContext.Lifecycle(&lesBackend)
-
- startNode(ctx, stack, ethBackend, lesBackend)
+ startNode(ctx, stack)
defer stack.Close()
// Attach to the newly started node and start the JavaScript console
@@ -199,13 +191,7 @@ func dialRPC(endpoint string) (*rpc.Client, error) {
func ephemeralConsole(ctx *cli.Context) error {
// Create and start the node based on the CLI flags
stack := makeFullNode(ctx)
- // fetch backend
- var ethBackend *eth.Ethereum
- stack.ServiceContext.Lifecycle(ðBackend)
- var lesBackend *les.LightEthereum
- stack.ServiceContext.Lifecycle(&lesBackend)
-
- startNode(ctx, stack, ethBackend, lesBackend)
+ startNode(ctx, stack)
defer stack.Close()
// Attach to the newly started node and start the JavaScript console
diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index 8cfbc4de310e..03c2755807a9 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -352,14 +352,9 @@ func geth(ctx *cli.Context) error {
}
prepare(ctx)
stack := makeFullNode(ctx)
- // fetch backend
- var ethBackend *eth.Ethereum
- stack.ServiceContext.Lifecycle(ðBackend)
- var lesBackend *les.LightEthereum
- stack.ServiceContext.Lifecycle(&lesBackend)
defer stack.Close()
- startNode(ctx, stack, ethBackend, lesBackend)
+ startNode(ctx, stack)
stack.Wait()
return nil
@@ -368,13 +363,9 @@ func geth(ctx *cli.Context) error {
// startNode boots up the system node and all registered protocols, after which
// it unlocks any requested accounts, and starts the RPC/IPC interfaces and the
// miner.
-func startNode(ctx *cli.Context, stack *node.Node, ethBackend *eth.Ethereum, lesBackend *les.LightEthereum) {
+func startNode(ctx *cli.Context, stack *node.Node) {
debug.Memsize.Add("node", stack)
- if ethBackend == nil && lesBackend == nil {
- utils.Fatalf("No backend service found") // TODO is this error okay?
- }
-
// Start up the node itself
utils.StartNode(stack)
@@ -395,7 +386,8 @@ func startNode(ctx *cli.Context, stack *node.Node, ethBackend *eth.Ethereum, les
// Set contract backend for ethereum service if local node
// is serving LES requests.
if ctx.GlobalInt(utils.LegacyLightServFlag.Name) > 0 || ctx.GlobalInt(utils.LightServeFlag.Name) > 0 {
- if ethBackend == nil {
+ var ethBackend *eth.Ethereum
+ if err := stack.ServiceContext.Lifecycle(ðBackend); err != nil {
utils.Fatalf("Failed to retrieve ethereum service: %v", err)
}
ethBackend.SetContractBackend(ethClient)
@@ -403,7 +395,8 @@ func startNode(ctx *cli.Context, stack *node.Node, ethBackend *eth.Ethereum, les
// Set contract backend for les service if local node is
// running as a light client.
if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" {
- if lesBackend == nil {
+ var lesBackend *les.LightEthereum
+ if err := stack.ServiceContext.Lifecycle(&lesBackend); err != nil {
utils.Fatalf("Failed to retrieve light ethereum service: %v", err)
}
lesBackend.SetContractBackend(ethClient)
@@ -473,7 +466,8 @@ func startNode(ctx *cli.Context, stack *node.Node, ethBackend *eth.Ethereum, les
utils.Fatalf("Light clients do not support mining")
}
// Check if node's backend is eth and that it exists
- if ethBackend == nil {
+ var ethBackend *eth.Ethereum
+ if err := stack.ServiceContext.Lifecycle(ðBackend); err != nil {
utils.Fatalf("Ethereum service not running: backend is not an eth backend")
}
// Set the gas price to the limits from the CLI and start mining
From 5d67845206ed4e501ab732dc618969c7f5b5beb9 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Tue, 9 Jun 2020 14:56:16 +0200
Subject: [PATCH 056/160] fixing docs
---
eth/backend.go | 4 ++--
les/client.go | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/eth/backend.go b/eth/backend.go
index 46d5fedcbede..56f605bc98c3 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -529,7 +529,7 @@ func (s *Ethereum) Downloader() *downloader.Downloader { return s.protocolManage
func (s *Ethereum) Synced() bool { return atomic.LoadUint32(&s.protocolManager.acceptTxs) == 1 }
func (s *Ethereum) ArchiveMode() bool { return s.config.NoPruning }
-// Protocols implements node.Backend, returning all the currently configured
+// Protocols returns all the currently configured
// network protocols to start.
func (s *Ethereum) Protocols() []p2p.Protocol {
protos := make([]p2p.Protocol, len(ProtocolVersions))
@@ -544,7 +544,7 @@ func (s *Ethereum) Protocols() []p2p.Protocol {
return protos
}
-// P2PServer implements node.Backend, registering the node's running p2p server with the Backend.
+// P2PServer registers the node's running p2p server with the Backend.
func (s *Ethereum) P2PServer(server *p2p.Server) error {
if server == nil {
return errors.New("p2p server is not running, cannot register with eth backend") // TODO is this error message okay?
diff --git a/les/client.go b/les/client.go
index dd62aa82bcb7..286fab7b2ede 100644
--- a/les/client.go
+++ b/les/client.go
@@ -281,7 +281,7 @@ func (s *LightEthereum) Protocols() []p2p.Protocol {
}, s.dialCandidates)
}
-// P2PServer implements node.Backend, registering the node's running p2p server with the Backend.
+// P2PServer registers the node's running p2p server with the Backend.
func (s *LightEthereum) P2PServer(server *p2p.Server) error {
if server == nil {
return errors.New("p2p server is not running, cannot register with les backend") // TODO is this error message okay?
From b8c5dc484ec54c5bb8850b5835449ceaae78088a Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Tue, 16 Jun 2020 10:05:09 +0200
Subject: [PATCH 057/160] fixed dao_test
---
cmd/geth/chaincmd.go | 15 ++++++++-------
cmd/geth/config.go | 7 ++++++-
cmd/geth/consolecmd.go | 4 ++--
cmd/geth/dao_test.go | 6 +++---
cmd/geth/main.go | 2 +-
core/rawdb/accessors_metadata.go | 2 +-
6 files changed, 21 insertions(+), 15 deletions(-)
diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go
index 247c202bca17..d16ec73cb6b2 100644
--- a/cmd/geth/chaincmd.go
+++ b/cmd/geth/chaincmd.go
@@ -239,8 +239,9 @@ func initGenesis(ctx *cli.Context) error {
if err := json.NewDecoder(file).Decode(genesis); err != nil {
utils.Fatalf("invalid genesis file: %v", err)
}
+
// Open an initialise both full and light databases
- stack := makeFullNode(ctx)
+ stack, _ := makeConfigNode(ctx)
defer stack.Close()
for _, name := range []string{"chaindata", "lightchaindata"} {
@@ -277,7 +278,7 @@ func importChain(ctx *cli.Context) error {
utils.SetupMetrics(ctx)
// Start system runtime metrics collection
go metrics.CollectProcessMetrics(3 * time.Second)
- stack := makeFullNode(ctx)
+ stack := makeFullNode(ctx, nil)
defer stack.Close()
chain, db := utils.MakeChain(ctx, stack, false)
@@ -371,7 +372,7 @@ func exportChain(ctx *cli.Context) error {
if len(ctx.Args()) < 1 {
utils.Fatalf("This command requires an argument.")
}
- stack := makeFullNode(ctx)
+ stack := makeFullNode(ctx, nil)
defer stack.Close()
chain, _ := utils.MakeChain(ctx, stack, true)
@@ -406,7 +407,7 @@ func importPreimages(ctx *cli.Context) error {
if len(ctx.Args()) < 1 {
utils.Fatalf("This command requires an argument.")
}
- stack := makeFullNode(ctx)
+ stack := makeFullNode(ctx, nil)
defer stack.Close()
db := utils.MakeChainDatabase(ctx, stack)
@@ -424,7 +425,7 @@ func exportPreimages(ctx *cli.Context) error {
if len(ctx.Args()) < 1 {
utils.Fatalf("This command requires an argument.")
}
- stack := makeFullNode(ctx)
+ stack := makeFullNode(ctx, nil)
defer stack.Close()
db := utils.MakeChainDatabase(ctx, stack)
@@ -446,7 +447,7 @@ func copyDb(ctx *cli.Context) error {
utils.Fatalf("Source ancient chain directory path argument missing")
}
// Initialize a new chain for the running node to sync into
- stack := makeFullNode(ctx)
+ stack := makeFullNode(ctx, nil)
defer stack.Close()
chain, chainDb := utils.MakeChain(ctx, stack, false)
@@ -554,7 +555,7 @@ func confirmAndRemoveDB(database string, kind string) {
}
func dump(ctx *cli.Context) error {
- stack := makeFullNode(ctx)
+ stack := makeFullNode(ctx, nil)
defer stack.Close()
chain, chainDb := utils.MakeChain(ctx, stack, true)
diff --git a/cmd/geth/config.go b/cmd/geth/config.go
index 60d9d0006689..2444ed066947 100644
--- a/cmd/geth/config.go
+++ b/cmd/geth/config.go
@@ -20,6 +20,7 @@ import (
"bufio"
"errors"
"fmt"
+ "github.com/ethereum/go-ethereum/core"
"os"
"reflect"
"unicode"
@@ -129,6 +130,7 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) {
if ctx.GlobalIsSet(utils.EthStatsURLFlag.Name) {
cfg.Ethstats.URL = ctx.GlobalString(utils.EthStatsURLFlag.Name)
}
+
utils.SetShhConfig(ctx, stack, &cfg.Shh)
return stack, cfg
@@ -144,8 +146,11 @@ func enableWhisper(ctx *cli.Context) bool {
return false
}
-func makeFullNode(ctx *cli.Context) *node.Node {
+func makeFullNode(ctx *cli.Context, genesis *core.Genesis) *node.Node {
stack, cfg := makeConfigNode(ctx)
+ if genesis != nil {
+ cfg.Eth.Genesis = genesis
+ }
utils.RegisterEthService(stack, &cfg.Eth)
// Whisper must be explicitly enabled by specifying at least 1 whisper flag or in dev mode
diff --git a/cmd/geth/consolecmd.go b/cmd/geth/consolecmd.go
index 5a88414a4230..25529c7dbaa4 100644
--- a/cmd/geth/consolecmd.go
+++ b/cmd/geth/consolecmd.go
@@ -78,7 +78,7 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/JavaScript-Cons
func localConsole(ctx *cli.Context) error {
// Create and start the node based on the CLI flags
prepare(ctx)
- stack := makeFullNode(ctx)
+ stack := makeFullNode(ctx, nil)
startNode(ctx, stack)
defer stack.Close()
@@ -190,7 +190,7 @@ func dialRPC(endpoint string) (*rpc.Client, error) {
// everything down.
func ephemeralConsole(ctx *cli.Context) error {
// Create and start the node based on the CLI flags
- stack := makeFullNode(ctx)
+ stack := makeFullNode(ctx, nil)
startNode(ctx, stack)
defer stack.Close()
diff --git a/cmd/geth/dao_test.go b/cmd/geth/dao_test.go
index f63b0dc6c8f5..96778bc13291 100644
--- a/cmd/geth/dao_test.go
+++ b/cmd/geth/dao_test.go
@@ -17,6 +17,7 @@
package main
import (
+ "github.com/ethereum/go-ethereum/params"
"io/ioutil"
"math/big"
"os"
@@ -25,7 +26,6 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
- "github.com/ethereum/go-ethereum/params"
)
// Genesis block for nodes which don't care about the DAO fork (i.e. not configured)
@@ -119,8 +119,7 @@ func testDAOForkBlockNewChain(t *testing.T, test int, genesis string, expectBloc
} else {
// Force chain initialization
args := []string{"--port", "0", "--maxpeers", "0", "--nodiscover", "--nat", "none", "--ipcdisable", "--datadir", datadir}
- geth := runGeth(t, append(args, []string{"--exec", "2+2", "console"}...)...)
- geth.WaitExit()
+ runGeth(t, append(args, []string{"--exec", "2+2", "console"}...)...).WaitExit()
}
// Retrieve the DAO config flag from the database
path := filepath.Join(datadir, "geth", "chaindata")
@@ -134,6 +133,7 @@ func testDAOForkBlockNewChain(t *testing.T, test int, genesis string, expectBloc
if genesis != "" {
genesisHash = daoGenesisHash
}
+
config := rawdb.ReadChainConfig(db, genesisHash)
if config == nil {
t.Errorf("test %d: failed to retrieve chain config: %v", test, err)
diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index 03c2755807a9..694d02bee331 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -351,7 +351,7 @@ func geth(ctx *cli.Context) error {
return fmt.Errorf("invalid command: %q", args[0])
}
prepare(ctx)
- stack := makeFullNode(ctx)
+ stack := makeFullNode(ctx, nil)
defer stack.Close()
startNode(ctx, stack)
diff --git a/core/rawdb/accessors_metadata.go b/core/rawdb/accessors_metadata.go
index f8d09fbddf2d..93df167e07dc 100644
--- a/core/rawdb/accessors_metadata.go
+++ b/core/rawdb/accessors_metadata.go
@@ -18,7 +18,7 @@ package rawdb
import (
"encoding/json"
-
+
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
From 885a7d428dc2c5c8b05158d1cef777254fe1a077 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Tue, 16 Jun 2020 12:48:10 +0200
Subject: [PATCH 058/160] lint
---
cmd/geth/config.go | 2 +-
cmd/geth/dao_test.go | 2 +-
core/rawdb/accessors_metadata.go | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/cmd/geth/config.go b/cmd/geth/config.go
index 2444ed066947..b395e80fde15 100644
--- a/cmd/geth/config.go
+++ b/cmd/geth/config.go
@@ -20,7 +20,6 @@ import (
"bufio"
"errors"
"fmt"
- "github.com/ethereum/go-ethereum/core"
"os"
"reflect"
"unicode"
@@ -28,6 +27,7 @@ import (
cli "gopkg.in/urfave/cli.v1"
"github.com/ethereum/go-ethereum/cmd/utils"
+ "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params"
diff --git a/cmd/geth/dao_test.go b/cmd/geth/dao_test.go
index 96778bc13291..a77cbec0bee5 100644
--- a/cmd/geth/dao_test.go
+++ b/cmd/geth/dao_test.go
@@ -17,7 +17,6 @@
package main
import (
- "github.com/ethereum/go-ethereum/params"
"io/ioutil"
"math/big"
"os"
@@ -26,6 +25,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
+ "github.com/ethereum/go-ethereum/params"
)
// Genesis block for nodes which don't care about the DAO fork (i.e. not configured)
diff --git a/core/rawdb/accessors_metadata.go b/core/rawdb/accessors_metadata.go
index 93df167e07dc..f8d09fbddf2d 100644
--- a/core/rawdb/accessors_metadata.go
+++ b/core/rawdb/accessors_metadata.go
@@ -18,7 +18,7 @@ package rawdb
import (
"encoding/json"
-
+
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
From abbe6f83cc66078fe1d9e27815d68603a57a8011 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Tue, 16 Jun 2020 16:42:48 +0200
Subject: [PATCH 059/160] fixed current tests, but need to add more
---
graphql/graphql_test.go | 46 ++++++++++++++++++++++++++++++++++++++---
node/api.go | 10 ++++-----
node/node.go | 35 +++++++++++++++++--------------
node/rpcstack.go | 30 +++++++++++++++++++++++----
node/rpcstack_test.go | 2 +-
5 files changed, 95 insertions(+), 28 deletions(-)
diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go
index 29b8c469cebf..4c103bc462a2 100644
--- a/graphql/graphql_test.go
+++ b/graphql/graphql_test.go
@@ -130,6 +130,41 @@ func TestGraphQLHTTPOnSamePort_GQLRequest_Unsuccessful(t *testing.T) {
assert.Equal(t, string(bodyBytes), expected)
}
+func TestGraphqlOnSeparatePort(t *testing.T) {
+ stack, err := node.New(&node.Config{
+ HTTPHost: "127.0.0.1",
+ HTTPPort: 9393,
+ })
+ if err != nil {
+ t.Fatalf("could not create node: %v", err)
+ }
+ defer stack.Close()
+
+ separateTestEndpoint := "127.0.0.1:7474"
+
+ createGQLService(t, stack, separateTestEndpoint)
+ // start node
+ if err := stack.Start(); err != nil {
+ t.Fatalf("could not start node: %v", err)
+ }
+ // create http request
+ body := strings.NewReader("{\"query\": \"{block{number}}\",\"variables\": null}")
+ gqlReq, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s/graphql", separateTestEndpoint), body)
+ if err != nil {
+ t.Error("could not issue new http request ", err)
+ }
+ gqlReq.Header.Set("Content-Type", "application/json")
+ // read from response
+ resp := doHTTPRequest(t, gqlReq)
+ bodyBytes, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ t.Fatalf("could not read from response body: %v", err)
+ }
+ expected := "{\"data\":{\"block\":{\"number\":\"0x0\"}}}"
+ assert.Equal(t, expected, string(bodyBytes))
+
+}
+
func createNode(t *testing.T, gqlEnabled bool) *node.Node {
stack, err := node.New(&node.Config{
HTTPHost: "127.0.0.1",
@@ -143,6 +178,13 @@ func createNode(t *testing.T, gqlEnabled bool) *node.Node {
if !gqlEnabled {
return stack
}
+
+ createGQLService(t, stack, testEndpoint)
+
+ return stack
+}
+
+func createGQLService(t *testing.T, stack *node.Node, endpoint string) {
// create backend
ethBackend, err := eth.New(stack, ð.DefaultConfig)
if err != nil {
@@ -150,12 +192,10 @@ func createNode(t *testing.T, gqlEnabled bool) *node.Node {
}
// create gql service
- err = New(stack, ethBackend.APIBackend, testEndpoint, []string{}, []string{}, rpc.DefaultHTTPTimeouts)
+ err = New(stack, ethBackend.APIBackend, endpoint, []string{}, []string{}, rpc.DefaultHTTPTimeouts)
if err != nil {
t.Fatalf("could not create graphql service: %v", err)
}
-
- return stack
}
func doHTTPRequest(t *testing.T, req *http.Request) *http.Response {
diff --git a/node/api.go b/node/api.go
index 0f21156e75bd..0b56184feff9 100644
--- a/node/api.go
+++ b/node/api.go
@@ -159,7 +159,7 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
}
endpoint := fmt.Sprintf("%s:%d", *host, *port)
// check if HTTP server already exists
- if server, exists := api.node.httpServerMap[endpoint]; exists {
+ if server, exists := api.node.HTTPServers.servers[endpoint]; exists {
if server.RPCAllowed {
return false, fmt.Errorf("HTTP RPC already running on %v", server.Listener.Addr())
}
@@ -219,7 +219,7 @@ func (api *PrivateAdminAPI) StopRPC() (bool, error) {
api.node.lock.Lock()
defer api.node.lock.Unlock()
- for _, httpServer := range api.node.httpServerMap {
+ for _, httpServer := range api.node.HTTPServers.servers {
if httpServer.RPCAllowed {
api.node.stopServer(httpServer)
return true, nil
@@ -234,7 +234,7 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
api.node.lock.Lock()
defer api.node.lock.Unlock()
// check if an existing WS server already exists
- for _, server := range api.node.httpServerMap {
+ for _, server := range api.node.HTTPServers.servers {
if server.WSAllowed {
return false, fmt.Errorf("WebSocket RPC already running on %v", server.Listener.Addr())
}
@@ -252,7 +252,7 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
}
endpoint := fmt.Sprintf("%s:%d", *host, *port)
// check if there is an existing server on the specified port, and if there is, enable ws on it
- if server, exists := api.node.httpServerMap[endpoint]; exists {
+ if server, exists := api.node.HTTPServers.servers[endpoint]; exists {
// else configure ws on the existing server
server.WSAllowed = true
// configure origins
@@ -319,7 +319,7 @@ func (api *PrivateAdminAPI) StopWS() (bool, error) {
api.node.lock.Lock()
defer api.node.lock.Unlock()
- for _, httpServer := range api.node.httpServerMap {
+ for _, httpServer := range api.node.HTTPServers.servers {
if httpServer.WSAllowed {
httpServer.WSAllowed = false
// if RPC is not enabled on the WS http server, shut it down
diff --git a/node/node.go b/node/node.go
index f5716f56916b..8bdbaeace3d8 100644
--- a/node/node.go
+++ b/node/node.go
@@ -56,11 +56,11 @@ type Node struct {
lifecycles map[reflect.Type]Lifecycle // All registered backends, services, and auxiliary services that have a lifecycle
+ HTTPServers *HTTPServers // TODO document
+
rpcAPIs []rpc.API // List of APIs currently provided by the node
inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
- httpServerMap map[string]*HTTPServer // Stores information about all http servers (if any) by their port, including http, ws, and graphql
-
ipc *HTTPServer // Stores information about the ipc http server
stop chan struct{} // Channel to wait for termination notifications
@@ -113,7 +113,9 @@ func New(conf *Config) (*Node, error) {
Config: *conf,
Lifecycles: make(map[reflect.Type]Lifecycle),
},
- httpServerMap: make(map[string]*HTTPServer),
+ HTTPServers: &HTTPServers{
+ servers: make(map[string]*HTTPServer),
+ },
ipc: &HTTPServer{
endpoint: conf.IPCEndpoint(),
},
@@ -157,13 +159,13 @@ func New(conf *Config) (*Node, error) {
httpServ.WSAllowed = true
httpServ.WsOrigins = conf.WSOrigins
httpServ.Whitelist = append(httpServ.Whitelist, conf.WSModules...)
- node.httpServerMap[conf.HTTPEndpoint()] = httpServ
+ node.HTTPServers.servers[conf.HTTPEndpoint()] = httpServ
return node, nil
}
- node.httpServerMap[conf.HTTPEndpoint()] = httpServ
+ node.HTTPServers.servers[conf.HTTPEndpoint()] = httpServ
}
if conf.WSHost != "" {
- node.httpServerMap[conf.WSEndpoint()] = &HTTPServer{
+ node.HTTPServers.servers[conf.WSEndpoint()] = &HTTPServer{
WsOrigins: conf.WSOrigins,
Whitelist: conf.WSModules,
Srv: rpc.NewServer(),
@@ -224,18 +226,18 @@ func (n *Node) RegisterAPIs(apis []rpc.API) {
// RegisterHTTPServer registers the given HTTP server on the node
func (n *Node) RegisterHTTPServer(endpoint string, server *HTTPServer) {
- n.httpServerMap[endpoint] = server
+ n.HTTPServers.servers[endpoint] = server
}
// ExistingHTTPServer checks if an HTTP server is already configured on the given endpoint
func (n *Node) ExistingHTTPServer(endpoint string) *HTTPServer {
- if server, exists := n.httpServerMap[endpoint]; exists {
+ if server, exists := n.HTTPServers.servers[endpoint]; exists {
return server
}
return nil
}
-// CreateHTTPServer creates an http.Server and adds it to the given HTTPServer // TODO improve?
+// CreateHTTPServer creates an http.Server and adds it to the given HTTPServers // TODO improve?
func (n *Node) CreateHTTPServer(h *HTTPServer, exposeAll bool) error {
// register apis and create handler stack
err := RegisterApisFromWhitelist(n.rpcAPIs, h.Whitelist, h.Srv, exposeAll)
@@ -258,7 +260,7 @@ func (n *Node) CreateHTTPServer(h *HTTPServer, exposeAll bool) error {
httpSrv.IdleTimeout = h.Timeouts.IdleTimeout
}
- // complete the HTTPServer
+ // complete the HTTPServers
h.Listener = listener
h.Server = httpSrv
@@ -293,6 +295,7 @@ func (n *Node) Start() error {
// Configure the RPC interfaces
if err := n.configureRPC(); err != nil {
+ n.HTTPServers.Stop()
n.server.Stop()
return err
}
@@ -363,7 +366,7 @@ func (n *Node) configureRPC() error {
return err
}
- for _, server := range n.httpServerMap {
+ for _, server := range n.HTTPServers.servers {
// configure the handlers
if server.RPCAllowed {
server.handler = NewHTTPHandlerStack(server.Srv, server.CorsAllowedOrigins, server.Vhosts)
@@ -392,8 +395,10 @@ func (n *Node) configureRPC() error {
if err := n.CreateHTTPServer(server, false); err != nil {
return err
}
- // start HTTP server
- n.RegisterLifecycle(server)
+ }
+ // only register http server as a lifecycle if it has not already been registered
+ if _, exists := n.lifecycles[reflect.TypeOf(n.HTTPServers)]; !exists {
+ n.RegisterLifecycle(n.HTTPServers)
}
// All API endpoints started successfully
return nil
@@ -463,7 +468,7 @@ func (n *Node) stopServer(server *HTTPServer) {
server.Srv = nil
}
// remove stopped http server from node's http servers // TODO is this preferable?
- delete(n.httpServerMap, server.endpoint)
+ delete(n.HTTPServers.servers, server.endpoint)
// remove stopped http server from node's lifecycles
n.removeLifecycle(server)
}
@@ -597,7 +602,7 @@ func (n *Node) WSEndpoint() string {
n.lock.Lock()
defer n.lock.Unlock()
- for _, httpServer := range n.httpServerMap {
+ for _, httpServer := range n.HTTPServers.servers {
if httpServer.WSAllowed {
if httpServer.Listener != nil {
return httpServer.Listener.Addr().String()
diff --git a/node/rpcstack.go b/node/rpcstack.go
index d5b5168e9bdd..3e4ea8ca4687 100644
--- a/node/rpcstack.go
+++ b/node/rpcstack.go
@@ -32,6 +32,10 @@ import (
"github.com/rs/cors"
)
+type HTTPServers struct {
+ servers map[string]*HTTPServer // Stores information about all http servers (if any) by their port, including http, ws, and graphql
+}
+
type HTTPServer struct {
handler http.Handler
Srv *rpc.Server
@@ -57,14 +61,32 @@ type HTTPServer struct {
GQLHandler http.Handler
}
-// Start starts the HTTPServer's HTTP server. // TODO I don't like the way this is written
+func (h *HTTPServers) Start() error {
+ for _, server := range h.servers {
+ if err := server.Start(); err != nil {
+ return h.Stop()
+ }
+ }
+ return nil
+}
+
+func (h *HTTPServers) Stop() error {
+ for _, server := range h.servers {
+ if err := server.Stop(); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// Start starts the HTTPServers's HTTP server. // TODO I don't like the way this is written
func (h *HTTPServer) Start() error {
go h.Server.Serve(h.Listener)
log.Info("HTTP endpoint successfully opened", "url", fmt.Sprintf("http://%v/", h.Listener.Addr()))
return nil
}
-// Stop shuts down the HTTPServer's HTTP server. // TODO I don't like the way this is written
+// Stop shuts down the HTTPServers's HTTP server. // TODO I don't like the way this is written
func (h *HTTPServer) Stop() error {
if h.Server != nil {
url := fmt.Sprintf("http://%v/", h.Listener.Addr())
@@ -80,12 +102,12 @@ func (h *HTTPServer) Stop() error {
return nil
}
-// SetHandler assigns the given handler to the HTTPServer.
+// SetHandler assigns the given handler to the HTTPServers.
func (h *HTTPServer) SetHandler(handler http.Handler) {
h.handler = handler
}
-// SetEndpoints assigns the given endpoint to the HTTPServer.
+// SetEndpoints assigns the given endpoint to the HTTPServers.
func (h *HTTPServer) SetEndpoint(endpoint string) {
h.endpoint = endpoint
}
diff --git a/node/rpcstack_test.go b/node/rpcstack_test.go
index 799b138a6917..dc75afa93438 100644
--- a/node/rpcstack_test.go
+++ b/node/rpcstack_test.go
@@ -40,7 +40,7 @@ func TestNewWebsocketUpgradeHandler_websocket(t *testing.T) {
assert.Equal(t, "websocket", response.Header.Get("Upgrade"))
}
-// Tests that a ws handler can be added to and enabled on an existing HTTPServer
+// Tests that a ws handler can be added to and enabled on an existing HTTPServers
func TestWSAllowed(t *testing.T) {
stack, err := New(&Config{
HTTPHost: DefaultHTTPHost,
From ae92dee0f2cc10d0d0e415ccfe724e4305bedcea Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Tue, 16 Jun 2020 17:14:25 +0200
Subject: [PATCH 060/160] new test to check for proper creation of http servers
on node
---
node/node_test.go | 59 +++++++++++++++++++++++++++++++++++++++--------
1 file changed, 49 insertions(+), 10 deletions(-)
diff --git a/node/node_test.go b/node/node_test.go
index e8ac35318a59..824653c697ab 100644
--- a/node/node_test.go
+++ b/node/node_test.go
@@ -359,9 +359,48 @@ func TestLifecycleRetrieval(t *testing.T) {
}
}
-// Tests whether websocket requests can be handled on the same port as a regular http server
+// Tests whether a node can successfully create and register HTTP server
+// lifecycles on the node.
+func TestHTTPServerCreation(t *testing.T) {
+ // test on same ports
+ node1 := startHTTP(t, 7453, 7453)
+ if len(node1.HTTPServers.servers) != 1 {
+ t.Fatalf("node has more than 1 http server")
+ }
+ // check to make sure http servers are registered
+ var httpSrv1 *HTTPServers
+ if err := node1.Lifecycle(&httpSrv1); err != nil {
+ t.Fatalf("HTTP servers not registered as lifecycles on the node: %v", err)
+ }
+ for _, server := range node1.HTTPServers.servers {
+ if !(server.WSAllowed && server.RPCAllowed) {
+ t.Fatalf("node's http server is not configured to handle both rpc and ws")
+ }
+ }
+ node1.Close()
+
+ // test on separate ports
+ node2 := startHTTP(t, 7453, 9393)
+ if len(node2.HTTPServers.servers) != 2 {
+ t.Fatalf("amount of http servers on the node is not equal to 2")
+ }
+ // check to make sure http servers are registered
+ var httpSrv2 *HTTPServers
+ if err := node2.Lifecycle(&httpSrv2); err != nil {
+ t.Fatalf("HTTP servers not registered as lifecycles on the node: %v", err)
+ }
+ // check that neither http server has both ws and rpc enabled
+ for _, server := range node2.HTTPServers.servers {
+ if server.WSAllowed && server.RPCAllowed {
+ t.Fatalf("both rpc and ws allowed on a single http server")
+ }
+ }
+ node2.Close()
+}
+
+// Tests whether websocket requests can be handled on the same port as a regular http server.
func TestWebsocketHTTPOnSamePort_WebsocketRequest(t *testing.T) {
- node := startHTTP(t)
+ node := startHTTP(t, 7453, 7453)
defer node.Close()
wsReq, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:7453", nil)
@@ -377,9 +416,9 @@ func TestWebsocketHTTPOnSamePort_WebsocketRequest(t *testing.T) {
assert.Equal(t, "websocket", resp.Header.Get("Upgrade"))
}
-// Tests whether http requests can be handled successfully
+// Tests whether http requests can be handled successfully.
func TestWebsocketHTTPOnSamePort_HTTPRequest(t *testing.T) {
- node := startHTTP(t)
+ node := startHTTP(t, 7453, 7453)
defer node.Close()
httpReq, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:7453", nil)
@@ -392,20 +431,20 @@ func TestWebsocketHTTPOnSamePort_HTTPRequest(t *testing.T) {
assert.Equal(t, "gzip", resp.Header.Get("Content-Encoding"))
}
-func startHTTP(t *testing.T) *Node {
+func startHTTP(t *testing.T, httpPort, wsPort int) *Node {
conf := &Config{
HTTPHost: "127.0.0.1",
- HTTPPort: 7453,
+ HTTPPort: httpPort,
WSHost: "127.0.0.1",
- WSPort: 7453,
+ WSPort: wsPort,
}
node, err := New(conf)
if err != nil {
- t.Error("could not create a new node ", err)
+ t.Fatalf("could not create a new node: %v", err)
}
err = node.Start()
if err != nil {
- t.Error("could not start http service on node ", err)
+ t.Fatalf("could not start http service on node: %v", err)
}
return node
@@ -415,7 +454,7 @@ func doHTTPRequest(t *testing.T, req *http.Request) *http.Response {
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
- t.Fatal("could not issue a GET request to the given endpoint", err)
+ t.Fatalf("could not issue a GET request to the given endpoint: %v", err)
}
return resp
From f2fcf692ebe95d8e3af9a9db5b201f02494daa91 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Wed, 17 Jun 2020 16:16:35 +0200
Subject: [PATCH 061/160] added more test coverage, removed some useless code
---
eth/backend.go | 4 +-
les/client.go | 4 +-
node/node.go | 12 +---
node/node_test.go | 98 ++++++++++++++++++++++++++-
node/utils_test.go | 52 +++++++++++++-
p2p/simulations/examples/ping-pong.go | 4 +-
p2p/simulations/http_test.go | 4 +-
whisper/whisperv6/whisper.go | 5 +-
8 files changed, 154 insertions(+), 29 deletions(-)
diff --git a/eth/backend.go b/eth/backend.go
index 56f605bc98c3..9da88d42dadc 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -239,9 +239,7 @@ func New(stack *node.Node, config *Config) (*Ethereum, error) {
// Register the backend on the node
stack.RegisterAPIs(eth.APIs())
- if err := stack.RegisterProtocols(eth.Protocols()); err != nil {
- return nil, err
- }
+ stack.RegisterProtocols(eth.Protocols())
stack.RegisterLifecycle(eth)
return eth, nil
diff --git a/les/client.go b/les/client.go
index 286fab7b2ede..3ed45c124b99 100644
--- a/les/client.go
+++ b/les/client.go
@@ -173,9 +173,7 @@ func New(stack *node.Node, config *eth.Config) (*LightEthereum, error) {
// Register the backend on the node
stack.RegisterAPIs(leth.APIs())
- if err := stack.RegisterProtocols(leth.Protocols()); err != nil {
- return nil, err
- }
+ stack.RegisterProtocols(leth.Protocols())
stack.RegisterLifecycle(leth)
return leth, nil
diff --git a/node/node.go b/node/node.go
index 8bdbaeace3d8..baaf172f315c 100644
--- a/node/node.go
+++ b/node/node.go
@@ -214,9 +214,8 @@ func (n *Node) RegisterLifecycle(lifecycle Lifecycle) {
}
// RegisterProtocols adds backend's protocols to the node's p2p server
-func (n *Node) RegisterProtocols(protocols []p2p.Protocol) error {
+func (n *Node) RegisterProtocols(protocols []p2p.Protocol) {
n.server.Protocols = append(n.server.Protocols, protocols...)
- return nil
}
// RegisterAPIs registers the APIs a service provides on the node
@@ -237,7 +236,7 @@ func (n *Node) ExistingHTTPServer(endpoint string) *HTTPServer {
return nil
}
-// CreateHTTPServer creates an http.Server and adds it to the given HTTPServers // TODO improve?
+// CreateHTTPServer creates an http.Server and adds it to the given HTTPServer
func (n *Node) CreateHTTPServer(h *HTTPServer, exposeAll bool) error {
// register apis and create handler stack
err := RegisterApisFromWhitelist(n.rpcAPIs, h.Whitelist, h.Srv, exposeAll)
@@ -469,13 +468,6 @@ func (n *Node) stopServer(server *HTTPServer) {
}
// remove stopped http server from node's http servers // TODO is this preferable?
delete(n.HTTPServers.servers, server.endpoint)
- // remove stopped http server from node's lifecycles
- n.removeLifecycle(server)
-}
-
-// removeLifecycle removes a stopped Lifecycle from the running node's Lifecycles
-func (n *Node) removeLifecycle(lifecycle Lifecycle) {
- delete(n.lifecycles, reflect.TypeOf(lifecycle))
}
// Stop terminates a running node along with all it's services. In the node was
diff --git a/node/node_test.go b/node/node_test.go
index 824653c697ab..446895aff4c7 100644
--- a/node/node_test.go
+++ b/node/node_test.go
@@ -18,6 +18,8 @@ package node
import (
"errors"
+ "fmt"
+ "github.com/ethereum/go-ethereum/rpc"
"io/ioutil"
"net/http"
"os"
@@ -105,7 +107,7 @@ func TestNodeUsedDataDir(t *testing.T) {
}
// Tests whether a Lifecycle can be registered.
-func TestLifecycleRegistry(t *testing.T) {
+func TestLifecycleRegistry_Successful(t *testing.T) {
stack, err := New(testNodeConfig())
if err != nil {
t.Fatalf("failed to create protocol stack: %v", err)
@@ -120,6 +122,50 @@ func TestLifecycleRegistry(t *testing.T) {
}
}
+// Tests whether a service's protocols can be registered properly on the node's p2p server.
+func TestRegisterProtocols(t *testing.T) {
+ stack, err := New(testNodeConfig())
+ if err != nil {
+ t.Fatalf("failed to create protocol stack: %v", err)
+ }
+ defer stack.Close()
+
+ fs, err := NewFullService(stack)
+ if err != nil {
+ t.Fatalf("could not create full service: %v", err)
+ }
+
+ for _, protocol := range fs.Protocols() {
+ if !containsProtocol(stack.server.Protocols, protocol) {
+ t.Fatalf("protocol %v was not successfully registered", protocol)
+ }
+ }
+
+ for _, api := range fs.APIs() {
+ if !containsAPI(stack.rpcAPIs, api) {
+ t.Fatalf("api %v was not successfully registered", api)
+ }
+ }
+}
+
+func containsProtocol(stackProtocols []p2p.Protocol, protocol p2p.Protocol) bool {
+ for _, a := range stackProtocols {
+ if reflect.DeepEqual(a, protocol) {
+ return true
+ }
+ }
+ return false
+}
+
+func containsAPI(stackAPIs []rpc.API, api rpc.API) bool {
+ for _, a := range stackAPIs {
+ if reflect.DeepEqual(a, api) {
+ return true
+ }
+ }
+ return false
+}
+
// Tests that registered Lifecycles get started and stopped correctly.
func TestLifecycleLifeCycle(t *testing.T) {
stack, err := New(testNodeConfig())
@@ -359,9 +405,48 @@ func TestLifecycleRetrieval(t *testing.T) {
}
}
+// Tests whether a given HTTPServer can be registered on the node
+func TestRegisterHTTPServer(t *testing.T) {
+ stack, err := New(testNodeConfig())
+ if err != nil {
+ t.Fatalf("failed to create protocol stack: %v", err)
+ }
+ defer stack.Close()
+
+ srv1 := &HTTPServer{
+ host: "test1",
+ port: 0001,
+ }
+ endpoint1 := fmt.Sprintf("%s:%d", srv1.host, srv1.port)
+ stack.RegisterHTTPServer(endpoint1, srv1)
+
+ srv2 := &HTTPServer{
+ host: "test2",
+ port: 0002,
+ }
+ endpoint2 := fmt.Sprintf("%s:%d", srv2.host, srv2.port)
+ stack.RegisterHTTPServer(endpoint2, srv2)
+
+ noop := &HTTPServer{
+ host: "test",
+ port: 0000,
+ }
+ endpointNoop := fmt.Sprintf("%s:%d", noop.host, noop.port)
+
+ if srv1 != stack.ExistingHTTPServer(endpoint1) {
+ t.Fatalf("server %v was not properly registered on the given endpoint %s", srv1, endpoint1)
+ }
+ if srv2 != stack.ExistingHTTPServer(endpoint2) {
+ t.Fatalf("server %v was not properly registered on the given endpoint %s", srv2, endpoint2)
+ }
+ if noop == stack.ExistingHTTPServer(endpointNoop) {
+ t.Fatalf("server %v was incorrectly registered on the given endpoint %s", noop, endpointNoop)
+ }
+}
+
// Tests whether a node can successfully create and register HTTP server
// lifecycles on the node.
-func TestHTTPServerCreation(t *testing.T) {
+func TestHTTPServerCreateAndStop(t *testing.T) {
// test on same ports
node1 := startHTTP(t, 7453, 7453)
if len(node1.HTTPServers.servers) != 1 {
@@ -376,7 +461,12 @@ func TestHTTPServerCreation(t *testing.T) {
if !(server.WSAllowed && server.RPCAllowed) {
t.Fatalf("node's http server is not configured to handle both rpc and ws")
}
+ node1.stopServer(server)
+ if node1.ExistingHTTPServer(server.endpoint) != nil {
+ t.Fatalf("failed to remove server %v from node after stopping it", server)
+ }
}
+
node1.Close()
// test on separate ports
@@ -394,6 +484,10 @@ func TestHTTPServerCreation(t *testing.T) {
if server.WSAllowed && server.RPCAllowed {
t.Fatalf("both rpc and ws allowed on a single http server")
}
+ node2.stopServer(server)
+ if node2.ExistingHTTPServer(server.endpoint) != nil {
+ t.Fatalf("failed to remove server %v from node after stopping it", server)
+ }
}
node2.Close()
}
diff --git a/node/utils_test.go b/node/utils_test.go
index 17c45a238fd6..0df20f5db440 100644
--- a/node/utils_test.go
+++ b/node/utils_test.go
@@ -19,7 +19,10 @@
package node
-import "github.com/ethereum/go-ethereum/p2p"
+import (
+ "github.com/ethereum/go-ethereum/p2p"
+ "github.com/ethereum/go-ethereum/rpc"
+)
// NoopLifecycle is a trivial implementation of the Service interface.
type NoopLifecycle struct{}
@@ -69,3 +72,50 @@ func (s *InstrumentedService) Stop() error {
}
return s.stop
}
+
+type FullService struct{}
+
+func NewFullService(stack *Node) (*FullService, error) {
+ fs := new(FullService)
+
+ stack.RegisterProtocols(fs.Protocols())
+ stack.RegisterAPIs(fs.APIs())
+ stack.RegisterLifecycle(fs)
+ return fs, nil
+}
+
+func (f *FullService) Start() error { return nil }
+
+func (f *FullService) Stop() error { return nil }
+
+func (f *FullService) Protocols() []p2p.Protocol {
+ return []p2p.Protocol{
+ p2p.Protocol{
+ Name: "test1",
+ Version: uint(1),
+ },
+ p2p.Protocol{
+ Name: "test2",
+ Version: uint(2),
+ },
+ }
+}
+
+func (f *FullService) APIs() []rpc.API {
+ return []rpc.API{
+ {
+ Namespace: "admin",
+ Version: "1.0",
+ },
+ {
+ Namespace: "debug",
+ Version: "1.0",
+ Public: true,
+ },
+ {
+ Namespace: "net",
+ Version: "1.0",
+ Public: true,
+ },
+ }
+}
\ No newline at end of file
diff --git a/p2p/simulations/examples/ping-pong.go b/p2p/simulations/examples/ping-pong.go
index 678236f3552a..13b6873bfea3 100644
--- a/p2p/simulations/examples/ping-pong.go
+++ b/p2p/simulations/examples/ping-pong.go
@@ -48,9 +48,7 @@ func main() {
services := map[string]adapters.LifecycleConstructor{
"ping-pong": func(ctx *adapters.ServiceContext, stack *node.Node) (node.Lifecycle, error) {
pps := newPingPongService(ctx.Config.ID)
- if err := stack.RegisterProtocols(pps.Protocols()); err != nil {
- return nil, err
- }
+ stack.RegisterProtocols(pps.Protocols())
stack.RegisterAPIs(pps.APIs())
return pps, nil
},
diff --git a/p2p/simulations/http_test.go b/p2p/simulations/http_test.go
index 1ecfb719fb96..6d7f0b6d7a31 100644
--- a/p2p/simulations/http_test.go
+++ b/p2p/simulations/http_test.go
@@ -71,9 +71,7 @@ func newTestService(ctx *adapters.ServiceContext, stack *node.Node) (node.Lifecy
}
svc.state.Store(ctx.Snapshot)
- if err := stack.RegisterProtocols(svc.Protocols()); err != nil {
- return nil, err
- }
+ stack.RegisterProtocols(svc.Protocols())
stack.RegisterAPIs(svc.APIs())
return svc, nil
}
diff --git a/whisper/whisperv6/whisper.go b/whisper/whisperv6/whisper.go
index a58e1710c9f6..5799919db967 100644
--- a/whisper/whisperv6/whisper.go
+++ b/whisper/whisperv6/whisper.go
@@ -134,11 +134,8 @@ func New(stack *node.Node, cfg *Config) error {
}
stack.RegisterAPIs(whisper.APIs())
- if err := stack.RegisterProtocols(whisper.Protocols()); err != nil {
- return err
- }
+ stack.RegisterProtocols(whisper.Protocols())
stack.RegisterLifecycle(whisper)
-
return nil
}
From 204514c2de1741e21414aedce4e37d1235c72f15 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Wed, 17 Jun 2020 18:29:12 +0200
Subject: [PATCH 062/160] minor changes, removing spaces, cleaninng up
---
cmd/geth/config.go | 2 --
cmd/geth/dao_test.go | 1 -
cmd/geth/main.go | 8 ++++----
cmd/utils/flags.go | 6 +++---
console/console_test.go | 1 -
eth/backend.go | 4 +---
ethclient/ethclient_test.go | 3 ---
7 files changed, 8 insertions(+), 17 deletions(-)
diff --git a/cmd/geth/config.go b/cmd/geth/config.go
index b395e80fde15..8495af7e2fc1 100644
--- a/cmd/geth/config.go
+++ b/cmd/geth/config.go
@@ -130,7 +130,6 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) {
if ctx.GlobalIsSet(utils.EthStatsURLFlag.Name) {
cfg.Ethstats.URL = ctx.GlobalString(utils.EthStatsURLFlag.Name)
}
-
utils.SetShhConfig(ctx, stack, &cfg.Shh)
return stack, cfg
@@ -176,7 +175,6 @@ func makeFullNode(ctx *cli.Context, genesis *core.Genesis) *node.Node {
if cfg.Ethstats.URL != "" {
utils.RegisterEthStatsService(stack, cfg.Ethstats.URL)
}
-
return stack
}
diff --git a/cmd/geth/dao_test.go b/cmd/geth/dao_test.go
index a77cbec0bee5..6c36771e9726 100644
--- a/cmd/geth/dao_test.go
+++ b/cmd/geth/dao_test.go
@@ -133,7 +133,6 @@ func testDAOForkBlockNewChain(t *testing.T, test int, genesis string, expectBloc
if genesis != "" {
genesisHash = daoGenesisHash
}
-
config := rawdb.ReadChainConfig(db, genesisHash)
if config == nil {
t.Errorf("test %d: failed to retrieve chain config: %v", test, err)
diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index 694d02bee331..c5e16e74ec14 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -350,12 +350,12 @@ func geth(ctx *cli.Context) error {
if args := ctx.Args(); len(args) > 0 {
return fmt.Errorf("invalid command: %q", args[0])
}
+
prepare(ctx)
stack := makeFullNode(ctx, nil)
-
defer stack.Close()
- startNode(ctx, stack)
+ startNode(ctx, stack)
stack.Wait()
return nil
}
@@ -465,10 +465,10 @@ func startNode(ctx *cli.Context, stack *node.Node) {
if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" {
utils.Fatalf("Light clients do not support mining")
}
- // Check if node's backend is eth and that it exists
+ // Check if node's backend is eth
var ethBackend *eth.Ethereum
if err := stack.ServiceContext.Lifecycle(ðBackend); err != nil {
- utils.Fatalf("Ethereum service not running: backend is not an eth backend")
+ utils.Fatalf("Ethereum service not running: %v", err)
}
// Set the gas price to the limits from the CLI and start mining
gasprice := utils.GlobalBig(ctx, utils.MinerGasPriceFlag.Name)
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index fa7b13af45ba..27937da36ed7 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -1696,7 +1696,7 @@ func RegisterEthService(stack *node.Node, cfg *eth.Config) {
if cfg.SyncMode == downloader.LightSync {
_, err := les.New(stack, cfg)
if err != nil {
- Fatalf("Failed to register the Ethereum service: %w", err)
+ Fatalf("Failed to register the Ethereum service: %v", err)
}
} else {
backend, err := eth.New(stack, cfg)
@@ -1713,7 +1713,7 @@ func RegisterEthService(stack *node.Node, cfg *eth.Config) {
// RegisterShhService configures Whisper and adds it to the given node.
func RegisterShhService(stack *node.Node, cfg *whisper.Config) {
if err := whisper.New(stack, cfg); err != nil {
- Fatalf("Failed to register the Whisper service: %w", err)
+ Fatalf("Failed to register the Whisper service: %v", err)
}
}
@@ -1721,7 +1721,7 @@ func RegisterShhService(stack *node.Node, cfg *whisper.Config) {
// the given node.
func RegisterEthStatsService(stack *node.Node, url string) {
if err := ethstats.New(stack, url); err != nil {
- Fatalf("Failed to register the Ethereum Stats service: %w", err)
+ Fatalf("Failed to register the Ethereum Stats service: %v", err)
}
}
diff --git a/console/console_test.go b/console/console_test.go
index 80a2253997c0..68c03d108d00 100644
--- a/console/console_test.go
+++ b/console/console_test.go
@@ -113,7 +113,6 @@ func newTester(t *testing.T, confOverride func(*eth.Config)) *tester {
if err != nil {
t.Fatalf("failed to register Ethereum protocol: %v", err)
}
-
// Start the node and assemble the JavaScript console around it
if err = stack.Start(); err != nil {
t.Fatalf("failed to start test stack: %v", err)
diff --git a/eth/backend.go b/eth/backend.go
index 9da88d42dadc..cfd90d4fe3fd 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -221,7 +221,6 @@ func New(stack *node.Node, config *Config) (*Ethereum, error) {
if eth.protocolManager, err = NewProtocolManager(chainConfig, checkpoint, config.SyncMode, config.NetworkId, eth.eventMux, eth.txPool, eth.engine, eth.blockchain, chainDb, cacheLimit, config.Whitelist); err != nil {
return nil, err
}
-
eth.miner = miner.New(eth, &config.Miner, chainConfig, eth.EventMux(), eth.engine, eth.isLocalBlock)
eth.miner.SetExtra(makeExtraData(config.Miner.ExtraData))
@@ -241,7 +240,6 @@ func New(stack *node.Node, config *Config) (*Ethereum, error) {
stack.RegisterAPIs(eth.APIs())
stack.RegisterProtocols(eth.Protocols())
stack.RegisterLifecycle(eth)
-
return eth, nil
}
@@ -545,7 +543,7 @@ func (s *Ethereum) Protocols() []p2p.Protocol {
// P2PServer registers the node's running p2p server with the Backend.
func (s *Ethereum) P2PServer(server *p2p.Server) error {
if server == nil {
- return errors.New("p2p server is not running, cannot register with eth backend") // TODO is this error message okay?
+ return node.ErrNodeStopped // TODO is this error okay to return?
}
s.p2pServer = server
return nil
diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go
index c1d98f020279..b49abe917732 100644
--- a/ethclient/ethclient_test.go
+++ b/ethclient/ethclient_test.go
@@ -187,13 +187,11 @@ var (
func newTestBackend(t *testing.T) (*node.Node, []*types.Block) {
// Generate test chain.
genesis, blocks := generateTestChain()
-
// Create node
n, err := node.New(&node.Config{})
if err != nil {
t.Fatalf("can't create new node: %v", err)
}
-
// Create Ethereum Service
config := ð.Config{Genesis: genesis}
config.Ethash.PowMode = ethash.ModeFake
@@ -201,7 +199,6 @@ func newTestBackend(t *testing.T) (*node.Node, []*types.Block) {
if err != nil {
t.Fatalf("can't create new ethereum service: %v", err)
}
-
// Import the test chain.
if err := n.Start(); err != nil {
t.Fatalf("can't start test node: %v", err)
From 41a25c362760a4a2d73ca66ba433b39a2bbbd022 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Thu, 18 Jun 2020 16:53:46 +0200
Subject: [PATCH 063/160] some changes to graphql and other misc
---
cmd/utils/flags.go | 13 +------------
ethstats/ethstats.go | 6 +++---
graphql/graphql_test.go | 13 ++++---------
graphql/service.go | 42 +++++++++++++++--------------------------
4 files changed, 23 insertions(+), 51 deletions(-)
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index 27937da36ed7..6622781f478b 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -49,7 +49,6 @@ import (
"github.com/ethereum/go-ethereum/ethstats"
"github.com/ethereum/go-ethereum/graphql"
"github.com/ethereum/go-ethereum/internal/flags"
- "github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/les"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
@@ -1727,18 +1726,8 @@ func RegisterEthStatsService(stack *node.Node, url string) {
// RegisterGraphQLService is a utility function to construct a new service and register it against a node.
func RegisterGraphQLService(stack *node.Node, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) {
- var backend ethapi.Backend
- // fetch backend
- var ethServ *eth.Ethereum
- if err := stack.ServiceContext.Lifecycle(ðServ); err == nil {
- backend = ethServ.APIBackend
- }
- var lesServ *les.LightEthereum
- if err := stack.ServiceContext.Lifecycle(&lesServ); err == nil {
- backend = lesServ.ApiBackend
- }
// create new graphQL service
- if err := graphql.New(stack, backend, endpoint, cors, vhosts, timeouts); err != nil {
+ if err := graphql.New(stack, endpoint, cors, vhosts, timeouts); err != nil {
Fatalf("Failed to register the GraphQL service: %v", err)
}
}
diff --git a/ethstats/ethstats.go b/ethstats/ethstats.go
index e40e973cbb13..e29fadd17838 100644
--- a/ethstats/ethstats.go
+++ b/ethstats/ethstats.go
@@ -110,7 +110,9 @@ func New(node *node.Node, url string) error {
ethstats.les = lesServ
ethstats.engine = lesServ.Engine()
}
- // TODO check to make sure at least one backend is not nil?
+ if ethstats.engine == nil {// TODO check to make sure at least one backend is not nil?
+ return fmt.Errorf("Ethereum service not found")
+ }
node.RegisterLifecycle(ethstats)
return nil
@@ -130,8 +132,6 @@ func (s *Service) Stop() error {
return nil
}
-func (s *Service) Server() *node.HTTPServer { return nil }
-
// loop keeps trying to connect to the netstats server, reporting chain events
// until termination.
func (s *Service) loop() {
diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go
index 4c103bc462a2..1c2a56ab0877 100644
--- a/graphql/graphql_test.go
+++ b/graphql/graphql_test.go
@@ -130,14 +130,9 @@ func TestGraphQLHTTPOnSamePort_GQLRequest_Unsuccessful(t *testing.T) {
assert.Equal(t, string(bodyBytes), expected)
}
+// Tests that graphql can be successfully enabled on a separate port than rpc and ws.
func TestGraphqlOnSeparatePort(t *testing.T) {
- stack, err := node.New(&node.Config{
- HTTPHost: "127.0.0.1",
- HTTPPort: 9393,
- })
- if err != nil {
- t.Fatalf("could not create node: %v", err)
- }
+ stack := createNode(t, false)
defer stack.Close()
separateTestEndpoint := "127.0.0.1:7474"
@@ -186,13 +181,13 @@ func createNode(t *testing.T, gqlEnabled bool) *node.Node {
func createGQLService(t *testing.T, stack *node.Node, endpoint string) {
// create backend
- ethBackend, err := eth.New(stack, ð.DefaultConfig)
+ _, err := eth.New(stack, ð.DefaultConfig)
if err != nil {
t.Fatalf("could not create eth backend: %v", err)
}
// create gql service
- err = New(stack, ethBackend.APIBackend, endpoint, []string{}, []string{}, rpc.DefaultHTTPTimeouts)
+ err = New(stack, endpoint, []string{}, []string{}, rpc.DefaultHTTPTimeouts)
if err != nil {
t.Fatalf("could not create graphql service: %v", err)
}
diff --git a/graphql/service.go b/graphql/service.go
index eb62f2f0695a..1ba7bdf582f0 100644
--- a/graphql/service.go
+++ b/graphql/service.go
@@ -18,6 +18,8 @@ package graphql
import (
"errors"
+ "github.com/ethereum/go-ethereum/eth"
+ "github.com/ethereum/go-ethereum/les"
"net/http"
"github.com/ethereum/go-ethereum/internal/ethapi"
@@ -27,19 +29,21 @@ import (
"github.com/graph-gophers/graphql-go/relay"
)
-// Service encapsulates a GraphQL service.
-type Service struct {
- backend ethapi.Backend // The backend that queries will operate on.
- graphqlServer *node.HTTPServer
-}
-
// New constructs a new GraphQL service instance.
-func New(stack *node.Node, backend ethapi.Backend, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) error {
- service := new(Service)
+func New(stack *node.Node, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) error {
+ // fetch backend
+ var backend ethapi.Backend
+ var ethServ *eth.Ethereum
+ if err := stack.ServiceContext.Lifecycle(ðServ); err == nil {
+ backend = ethServ.APIBackend
+ }
+ var lesServ *les.LightEthereum
+ if err := stack.ServiceContext.Lifecycle(&lesServ); err == nil {
+ backend = lesServ.ApiBackend
+ }
if backend == nil {
return errors.New("No backend found") // TODO should this be a fatal error?
}
- service.backend = backend
// check if http server with given endpoint exists and enable graphQL on it
server := stack.ExistingHTTPServer(endpoint)
if server != nil {
@@ -48,7 +52,7 @@ func New(stack *node.Node, backend ethapi.Backend, endpoint string, cors, vhosts
server.CorsAllowedOrigins = append(server.CorsAllowedOrigins, cors...)
server.Timeouts = timeouts
// create handler
- handler, err := createHandler(service.backend, cors, vhosts)
+ handler, err := createHandler(backend, cors, vhosts)
if err != nil {
return err
}
@@ -57,7 +61,7 @@ func New(stack *node.Node, backend ethapi.Backend, endpoint string, cors, vhosts
return nil
}
// otherwise create a new server
- handler, err := createHandler(service.backend, cors, vhosts)
+ handler, err := createHandler(backend, cors, vhosts)
if err != nil {
return err
}
@@ -73,7 +77,6 @@ func New(stack *node.Node, backend ethapi.Backend, endpoint string, cors, vhosts
gqlServer.SetEndpoint(endpoint)
stack.RegisterHTTPServer(endpoint, gqlServer)
- service.graphqlServer = gqlServer
return nil
}
@@ -106,18 +109,3 @@ func newHandler(backend ethapi.Backend) (http.Handler, error) {
mux.Handle("/graphql/", h)
return mux, nil
}
-
-// Start is called after all services have been constructed and the networking
-// layer was also initialized to spawn any goroutines required by the service.
-func (s *Service) Start() error {
-
- return nil
-}
-
-// Stop terminates all goroutines belonging to the service, blocking until they
-// are all terminated.
-func (s *Service) Stop() error { return nil }
-
-func (s *Service) Server() *node.HTTPServer {
- return s.graphqlServer
-}
From 666db04bd9c62ff63b82e26425553e4069ca5cce Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Fri, 19 Jun 2020 13:44:19 +0200
Subject: [PATCH 064/160] linted
---
ethstats/ethstats.go | 2 +-
graphql/service.go | 5 ++---
node/node_test.go | 2 +-
node/utils_test.go | 8 ++++----
4 files changed, 8 insertions(+), 9 deletions(-)
diff --git a/ethstats/ethstats.go b/ethstats/ethstats.go
index e29fadd17838..0989a9862b12 100644
--- a/ethstats/ethstats.go
+++ b/ethstats/ethstats.go
@@ -110,7 +110,7 @@ func New(node *node.Node, url string) error {
ethstats.les = lesServ
ethstats.engine = lesServ.Engine()
}
- if ethstats.engine == nil {// TODO check to make sure at least one backend is not nil?
+ if ethstats.engine == nil { // TODO check to make sure at least one backend is not nil?
return fmt.Errorf("Ethereum service not found")
}
diff --git a/graphql/service.go b/graphql/service.go
index 1ba7bdf582f0..8bec768ef6ef 100644
--- a/graphql/service.go
+++ b/graphql/service.go
@@ -18,11 +18,11 @@ package graphql
import (
"errors"
- "github.com/ethereum/go-ethereum/eth"
- "github.com/ethereum/go-ethereum/les"
"net/http"
+ "github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/internal/ethapi"
+ "github.com/ethereum/go-ethereum/les"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/rpc"
"github.com/graph-gophers/graphql-go"
@@ -77,7 +77,6 @@ func New(stack *node.Node, endpoint string, cors, vhosts []string, timeouts rpc.
gqlServer.SetEndpoint(endpoint)
stack.RegisterHTTPServer(endpoint, gqlServer)
-
return nil
}
diff --git a/node/node_test.go b/node/node_test.go
index 446895aff4c7..e00c686058e4 100644
--- a/node/node_test.go
+++ b/node/node_test.go
@@ -19,7 +19,6 @@ package node
import (
"errors"
"fmt"
- "github.com/ethereum/go-ethereum/rpc"
"io/ioutil"
"net/http"
"os"
@@ -28,6 +27,7 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/p2p"
+ "github.com/ethereum/go-ethereum/rpc"
"github.com/stretchr/testify/assert"
)
diff --git a/node/utils_test.go b/node/utils_test.go
index 0df20f5db440..481edd6d4822 100644
--- a/node/utils_test.go
+++ b/node/utils_test.go
@@ -91,12 +91,12 @@ func (f *FullService) Stop() error { return nil }
func (f *FullService) Protocols() []p2p.Protocol {
return []p2p.Protocol{
p2p.Protocol{
- Name: "test1",
+ Name: "test1",
Version: uint(1),
},
p2p.Protocol{
- Name: "test2",
- Version: uint(2),
+ Name: "test2",
+ Version: uint(2),
},
}
}
@@ -118,4 +118,4 @@ func (f *FullService) APIs() []rpc.API {
Public: true,
},
}
-}
\ No newline at end of file
+}
From 828646c35ec4ba6762236c00d1163c3c5f183401 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Fri, 19 Jun 2020 16:22:24 +0200
Subject: [PATCH 065/160] no need to pass gen state to makefullnode
---
cmd/geth/chaincmd.go | 12 ++++++------
cmd/geth/config.go | 7 ++-----
cmd/geth/consolecmd.go | 4 ++--
cmd/geth/main.go | 2 +-
4 files changed, 11 insertions(+), 14 deletions(-)
diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go
index d16ec73cb6b2..147587004060 100644
--- a/cmd/geth/chaincmd.go
+++ b/cmd/geth/chaincmd.go
@@ -278,7 +278,7 @@ func importChain(ctx *cli.Context) error {
utils.SetupMetrics(ctx)
// Start system runtime metrics collection
go metrics.CollectProcessMetrics(3 * time.Second)
- stack := makeFullNode(ctx, nil)
+ stack := makeFullNode(ctx)
defer stack.Close()
chain, db := utils.MakeChain(ctx, stack, false)
@@ -372,7 +372,7 @@ func exportChain(ctx *cli.Context) error {
if len(ctx.Args()) < 1 {
utils.Fatalf("This command requires an argument.")
}
- stack := makeFullNode(ctx, nil)
+ stack := makeFullNode(ctx)
defer stack.Close()
chain, _ := utils.MakeChain(ctx, stack, true)
@@ -407,7 +407,7 @@ func importPreimages(ctx *cli.Context) error {
if len(ctx.Args()) < 1 {
utils.Fatalf("This command requires an argument.")
}
- stack := makeFullNode(ctx, nil)
+ stack := makeFullNode(ctx)
defer stack.Close()
db := utils.MakeChainDatabase(ctx, stack)
@@ -425,7 +425,7 @@ func exportPreimages(ctx *cli.Context) error {
if len(ctx.Args()) < 1 {
utils.Fatalf("This command requires an argument.")
}
- stack := makeFullNode(ctx, nil)
+ stack := makeFullNode(ctx)
defer stack.Close()
db := utils.MakeChainDatabase(ctx, stack)
@@ -447,7 +447,7 @@ func copyDb(ctx *cli.Context) error {
utils.Fatalf("Source ancient chain directory path argument missing")
}
// Initialize a new chain for the running node to sync into
- stack := makeFullNode(ctx, nil)
+ stack := makeFullNode(ctx)
defer stack.Close()
chain, chainDb := utils.MakeChain(ctx, stack, false)
@@ -555,7 +555,7 @@ func confirmAndRemoveDB(database string, kind string) {
}
func dump(ctx *cli.Context) error {
- stack := makeFullNode(ctx, nil)
+ stack := makeFullNode(ctx)
defer stack.Close()
chain, chainDb := utils.MakeChain(ctx, stack, true)
diff --git a/cmd/geth/config.go b/cmd/geth/config.go
index 8495af7e2fc1..af08b7788611 100644
--- a/cmd/geth/config.go
+++ b/cmd/geth/config.go
@@ -27,7 +27,6 @@ import (
cli "gopkg.in/urfave/cli.v1"
"github.com/ethereum/go-ethereum/cmd/utils"
- "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params"
@@ -145,11 +144,9 @@ func enableWhisper(ctx *cli.Context) bool {
return false
}
-func makeFullNode(ctx *cli.Context, genesis *core.Genesis) *node.Node {
+func makeFullNode(ctx *cli.Context) *node.Node {
stack, cfg := makeConfigNode(ctx)
- if genesis != nil {
- cfg.Eth.Genesis = genesis
- }
+
utils.RegisterEthService(stack, &cfg.Eth)
// Whisper must be explicitly enabled by specifying at least 1 whisper flag or in dev mode
diff --git a/cmd/geth/consolecmd.go b/cmd/geth/consolecmd.go
index 25529c7dbaa4..5a88414a4230 100644
--- a/cmd/geth/consolecmd.go
+++ b/cmd/geth/consolecmd.go
@@ -78,7 +78,7 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/JavaScript-Cons
func localConsole(ctx *cli.Context) error {
// Create and start the node based on the CLI flags
prepare(ctx)
- stack := makeFullNode(ctx, nil)
+ stack := makeFullNode(ctx)
startNode(ctx, stack)
defer stack.Close()
@@ -190,7 +190,7 @@ func dialRPC(endpoint string) (*rpc.Client, error) {
// everything down.
func ephemeralConsole(ctx *cli.Context) error {
// Create and start the node based on the CLI flags
- stack := makeFullNode(ctx, nil)
+ stack := makeFullNode(ctx)
startNode(ctx, stack)
defer stack.Close()
diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index c5e16e74ec14..b0fb861016c0 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -352,7 +352,7 @@ func geth(ctx *cli.Context) error {
}
prepare(ctx)
- stack := makeFullNode(ctx, nil)
+ stack := makeFullNode(ctx)
defer stack.Close()
startNode(ctx, stack)
From 344320270d7a61083c88b5e406a473dbe3580fe1 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Mon, 22 Jun 2020 13:10:34 +0200
Subject: [PATCH 066/160] missing register apis and protocols
---
miner/stress_clique.go | 2 ++
miner/stress_ethash.go | 2 ++
2 files changed, 4 insertions(+)
diff --git a/miner/stress_clique.go b/miner/stress_clique.go
index a69dfbd69d9d..6f65ddddfca2 100644
--- a/miner/stress_clique.go
+++ b/miner/stress_clique.go
@@ -208,6 +208,8 @@ func makeSealer(genesis *core.Genesis) (*node.Node, error) {
if err != nil {
return nil, err
}
+ stack.RegisterAPIs(ethBackend.APIs())
+ stack.RegisterProtocols(ethBackend.Protocols())
stack.RegisterLifecycle(ethBackend)
// Start the node and return if successful
diff --git a/miner/stress_ethash.go b/miner/stress_ethash.go
index 1cb5396ce323..6893dff6e273 100644
--- a/miner/stress_ethash.go
+++ b/miner/stress_ethash.go
@@ -189,6 +189,8 @@ func makeMiner(genesis *core.Genesis) (*node.Node, error) {
if err != nil {
return nil, err
}
+ stack.RegisterAPIs(ethBackend.APIs())
+ stack.RegisterProtocols(ethBackend.Protocols())
stack.RegisterLifecycle(ethBackend)
// Start the node and return if successful
From 9ed169edd0161ace72844c6d0a1dfc74fead3b11 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Mon, 22 Jun 2020 14:44:19 +0200
Subject: [PATCH 067/160] register http before starting
---
node/api.go | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/node/api.go b/node/api.go
index 0b56184feff9..ec9b836d7203 100644
--- a/node/api.go
+++ b/node/api.go
@@ -204,13 +204,14 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
if err := api.node.CreateHTTPServer(httpServer, false); err != nil {
return false, err
}
+ // register the HTTP server
+ api.node.RegisterHTTPServer(endpoint, httpServer)
// start the HTTP server
httpServer.Start()
api.node.log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%v/", httpServer.Listener.Addr()),
"cors", strings.Join(httpServer.CorsAllowedOrigins, ","),
"vhosts", strings.Join(httpServer.Vhosts, ","))
- api.node.RegisterHTTPServer(endpoint, httpServer)
return true, nil
}
@@ -291,7 +292,7 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
modules = append(modules, strings.TrimSpace(m))
}
}
-
+ // configure http server
wsServer := &HTTPServer{
Srv: rpc.NewServer(),
endpoint: endpoint,
@@ -301,16 +302,18 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
WsOrigins: origins,
WSAllowed: true,
}
-
+ // create handler
wsServer.handler = wsServer.Srv.WebsocketHandler(wsServer.WsOrigins)
+ // create the HTTP server
if err := api.node.CreateHTTPServer(wsServer, api.node.config.WSExposeAll); err != nil {
return false, err
}
-
+ // register the HTTP server
+ api.node.RegisterHTTPServer(endpoint, wsServer)
+ // start the HTTP server
wsServer.Start()
api.node.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", wsServer.Listener.Addr()))
- api.node.RegisterHTTPServer(endpoint, wsServer)
return true, nil
}
From fb8e5b0f909d5d9a7e0da406c561d7eff0279797 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Mon, 22 Jun 2020 15:20:27 +0200
Subject: [PATCH 068/160] added some documentation
---
node/node.go | 2 +-
node/rpcstack.go | 4 ++--
node/service.go | 5 ++++-
3 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/node/node.go b/node/node.go
index baaf172f315c..f4c35254ac67 100644
--- a/node/node.go
+++ b/node/node.go
@@ -56,7 +56,7 @@ type Node struct {
lifecycles map[reflect.Type]Lifecycle // All registered backends, services, and auxiliary services that have a lifecycle
- HTTPServers *HTTPServers // TODO document
+ HTTPServers *HTTPServers // HTTPServers stores information about the node's rpc, ws, and graphQL http servers.
rpcAPIs []rpc.API // List of APIs currently provided by the node
inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
diff --git a/node/rpcstack.go b/node/rpcstack.go
index 3e4ea8ca4687..3ceab681e687 100644
--- a/node/rpcstack.go
+++ b/node/rpcstack.go
@@ -241,7 +241,7 @@ func isWebsocket(r *http.Request) bool {
strings.ToLower(r.Header.Get("Connection")) == "upgrade"
}
-// TODO document
+// NewGQLUpgradeHandler wraps the given handler, h, in the given graphQL handler.
func NewGQLUpgradeHandler(h http.Handler, gql http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if isGQL(r) {
@@ -254,7 +254,7 @@ func NewGQLUpgradeHandler(h http.Handler, gql http.Handler) http.Handler {
})
}
-// TODO document
+// isGQL checks if the given request is a graphQL request.
func isGQL(r *http.Request) bool {
return r.URL.Path == "/graphql" || r.URL.Path == "/graphql/"
}
diff --git a/node/service.go b/node/service.go
index 072933fe6050..3cb1b978ade7 100644
--- a/node/service.go
+++ b/node/service.go
@@ -89,7 +89,10 @@ func (ctx *ServiceContext) ExtRPCEnabled() bool {
return ctx.Config.ExtRPCEnabled()
}
-// TODO document
+// Lifecycle encompasses the behavior of services that can be started and stopped
+// on the node. Lifecycle management is delegated to the node, but it is the
+// responsibility of the service-specific package to configure and register the
+// service on the node using the `RegisterLifecycle` method.
type Lifecycle interface {
// Start is called after all services have been constructed and the networking
// layer was also initialized to spawn any goroutines required by the service.
From e897df9ebda3201843b7206679ea31e4e784aef2 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Mon, 22 Jun 2020 15:34:31 +0200
Subject: [PATCH 069/160] minor fixes
---
node/service.go | 2 +-
p2p/server.go | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/node/service.go b/node/service.go
index 3cb1b978ade7..e7746e92262c 100644
--- a/node/service.go
+++ b/node/service.go
@@ -73,7 +73,7 @@ func (ctx *ServiceContext) ResolvePath(path string) string {
return ctx.Config.ResolvePath(path)
}
-// Lifecycle retrieves a currently running lifecycle registered of a specific type.
+// Lifecycle retrieves a currently running Lifecycle registered of a specific type.
func (ctx *ServiceContext) Lifecycle(lifecycle interface{}) error {
element := reflect.ValueOf(lifecycle).Elem()
if running, ok := ctx.Lifecycles[element.Type()]; ok {
diff --git a/p2p/server.go b/p2p/server.go
index aae88260a91b..58a41729861e 100644
--- a/p2p/server.go
+++ b/p2p/server.go
@@ -1120,6 +1120,7 @@ func (srv *Server) PeersInfo() []*PeerInfo {
return infos
}
+// Running returns whether the server is running.
func (srv *Server) Running() bool {
return srv.running
}
From cfae6edded511a44c382253e320fca722dcf9d4e Mon Sep 17 00:00:00 2001
From: rene <41963722+renaynay@users.noreply.github.com>
Date: Mon, 29 Jun 2020 15:59:33 +0200
Subject: [PATCH 070/160] Changes requested from PR review (#23)
---
cmd/faucet/faucet.go | 4 +-
cmd/geth/chaincmd.go | 12 +--
cmd/geth/config.go | 11 ++-
cmd/geth/consolecmd.go | 8 +-
cmd/geth/main.go | 34 +++----
cmd/utils/flags.go | 19 ++--
eth/api_backend.go | 31 ++++++
eth/backend.go | 27 ++----
ethclient/ethclient.go | 8 ++
ethclient/ethclient_test.go | 33 +++----
ethstats/ethstats.go | 147 +++++++++--------------------
graphql/graphql_test.go | 4 +-
graphql/service.go | 17 +---
internal/ethapi/backend.go | 15 ++-
les/api_backend.go | 33 +++++++
les/client.go | 14 +--
miner/stress_clique.go | 41 ++++----
miner/stress_ethash.go | 39 ++++----
mobile/geth.go | 6 +-
node/api.go | 10 +-
node/lifecycle.go | 31 ++++++
node/node.go | 70 ++++----------
node/node_test.go | 73 +++++---------
node/rpcstack.go | 25 +++--
node/rpcstack_test.go | 2 +-
node/service.go | 104 --------------------
node/service_test.go | 93 ------------------
p2p/simulations/adapters/exec.go | 5 +-
p2p/simulations/adapters/inproc.go | 5 +-
p2p/simulations/adapters/types.go | 5 +-
whisper/mailserver/server_test.go | 20 +---
whisper/whisperv6/api_test.go | 4 +-
whisper/whisperv6/filter_test.go | 20 +---
whisper/whisperv6/whisper.go | 4 +-
whisper/whisperv6/whisper_test.go | 57 +++--------
35 files changed, 381 insertions(+), 650 deletions(-)
create mode 100644 node/lifecycle.go
delete mode 100644 node/service.go
delete mode 100644 node/service_test.go
diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go
index 6f6cb39069f0..65c71ce4eb03 100644
--- a/cmd/faucet/faucet.go
+++ b/cmd/faucet/faucet.go
@@ -241,14 +241,14 @@ func newFaucet(genesis *core.Genesis, port int, enodes []*discv5.Node, network u
cfg.SyncMode = downloader.LightSync
cfg.NetworkId = network
cfg.Genesis = genesis
- _, err = les.New(stack, &cfg)
+ lesBackend, err := les.New(stack, &cfg)
if err != nil {
return nil, fmt.Errorf("Failed to register the Ethereum service: %w", err)
}
// Assemble the ethstats monitoring and reporting service'
if stats != "" {
- if err := ethstats.New(stack, stats); err != nil {
+ if err := ethstats.New(stack, lesBackend.ApiBackend, lesBackend.Engine(), stats); err != nil {
return nil, err
}
}
diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go
index 147587004060..6bc595566f15 100644
--- a/cmd/geth/chaincmd.go
+++ b/cmd/geth/chaincmd.go
@@ -278,7 +278,7 @@ func importChain(ctx *cli.Context) error {
utils.SetupMetrics(ctx)
// Start system runtime metrics collection
go metrics.CollectProcessMetrics(3 * time.Second)
- stack := makeFullNode(ctx)
+ stack, _ := makeFullNode(ctx)
defer stack.Close()
chain, db := utils.MakeChain(ctx, stack, false)
@@ -372,7 +372,7 @@ func exportChain(ctx *cli.Context) error {
if len(ctx.Args()) < 1 {
utils.Fatalf("This command requires an argument.")
}
- stack := makeFullNode(ctx)
+ stack, _ := makeFullNode(ctx)
defer stack.Close()
chain, _ := utils.MakeChain(ctx, stack, true)
@@ -407,7 +407,7 @@ func importPreimages(ctx *cli.Context) error {
if len(ctx.Args()) < 1 {
utils.Fatalf("This command requires an argument.")
}
- stack := makeFullNode(ctx)
+ stack, _ := makeFullNode(ctx)
defer stack.Close()
db := utils.MakeChainDatabase(ctx, stack)
@@ -425,7 +425,7 @@ func exportPreimages(ctx *cli.Context) error {
if len(ctx.Args()) < 1 {
utils.Fatalf("This command requires an argument.")
}
- stack := makeFullNode(ctx)
+ stack, _ := makeFullNode(ctx)
defer stack.Close()
db := utils.MakeChainDatabase(ctx, stack)
@@ -447,7 +447,7 @@ func copyDb(ctx *cli.Context) error {
utils.Fatalf("Source ancient chain directory path argument missing")
}
// Initialize a new chain for the running node to sync into
- stack := makeFullNode(ctx)
+ stack, _ := makeFullNode(ctx)
defer stack.Close()
chain, chainDb := utils.MakeChain(ctx, stack, false)
@@ -555,7 +555,7 @@ func confirmAndRemoveDB(database string, kind string) {
}
func dump(ctx *cli.Context) error {
- stack := makeFullNode(ctx)
+ stack, _ := makeFullNode(ctx)
defer stack.Close()
chain, chainDb := utils.MakeChain(ctx, stack, true)
diff --git a/cmd/geth/config.go b/cmd/geth/config.go
index af08b7788611..a777f37050e5 100644
--- a/cmd/geth/config.go
+++ b/cmd/geth/config.go
@@ -28,6 +28,7 @@ import (
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/eth"
+ "github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params"
whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
@@ -144,10 +145,10 @@ func enableWhisper(ctx *cli.Context) bool {
return false
}
-func makeFullNode(ctx *cli.Context) *node.Node {
+func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
stack, cfg := makeConfigNode(ctx)
- utils.RegisterEthService(stack, &cfg.Eth)
+ backend := utils.RegisterEthService(stack, &cfg.Eth)
// Whisper must be explicitly enabled by specifying at least 1 whisper flag or in dev mode
shhEnabled := enableWhisper(ctx)
@@ -166,13 +167,13 @@ func makeFullNode(ctx *cli.Context) *node.Node {
}
// Configure GraphQL if requested
if ctx.GlobalIsSet(utils.GraphQLEnabledFlag.Name) {
- utils.RegisterGraphQLService(stack, cfg.Node.GraphQLEndpoint(), cfg.Node.GraphQLCors, cfg.Node.GraphQLVirtualHosts, cfg.Node.HTTPTimeouts)
+ utils.RegisterGraphQLService(stack, backend, cfg.Node)
}
// Add the Ethereum Stats daemon if requested.
if cfg.Ethstats.URL != "" {
- utils.RegisterEthStatsService(stack, cfg.Ethstats.URL)
+ utils.RegisterEthStatsService(stack, backend, cfg.Ethstats.URL)
}
- return stack
+ return stack, backend
}
// dumpConfig is the dumpconfig command.
diff --git a/cmd/geth/consolecmd.go b/cmd/geth/consolecmd.go
index 5a88414a4230..e2f733f844a4 100644
--- a/cmd/geth/consolecmd.go
+++ b/cmd/geth/consolecmd.go
@@ -78,8 +78,8 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/JavaScript-Cons
func localConsole(ctx *cli.Context) error {
// Create and start the node based on the CLI flags
prepare(ctx)
- stack := makeFullNode(ctx)
- startNode(ctx, stack)
+ stack, backend := makeFullNode(ctx)
+ startNode(ctx, stack, backend)
defer stack.Close()
// Attach to the newly started node and start the JavaScript console
@@ -190,8 +190,8 @@ func dialRPC(endpoint string) (*rpc.Client, error) {
// everything down.
func ephemeralConsole(ctx *cli.Context) error {
// Create and start the node based on the CLI flags
- stack := makeFullNode(ctx)
- startNode(ctx, stack)
+ stack, backend := makeFullNode(ctx)
+ startNode(ctx, stack, backend)
defer stack.Close()
// Attach to the newly started node and start the JavaScript console
diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index b0fb861016c0..bbbc1b70d4ea 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -32,12 +32,11 @@ import (
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/console/prompt"
- "github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/internal/debug"
"github.com/ethereum/go-ethereum/internal/flags"
- "github.com/ethereum/go-ethereum/les"
+ "github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/node"
@@ -352,10 +351,10 @@ func geth(ctx *cli.Context) error {
}
prepare(ctx)
- stack := makeFullNode(ctx)
+ stack, backend := makeFullNode(ctx)
defer stack.Close()
- startNode(ctx, stack)
+ startNode(ctx, stack, backend)
stack.Wait()
return nil
}
@@ -363,7 +362,7 @@ func geth(ctx *cli.Context) error {
// startNode boots up the system node and all registered protocols, after which
// it unlocks any requested accounts, and starts the RPC/IPC interfaces and the
// miner.
-func startNode(ctx *cli.Context, stack *node.Node) {
+func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend) {
debug.Memsize.Add("node", stack)
// Start up the node itself
@@ -386,20 +385,12 @@ func startNode(ctx *cli.Context, stack *node.Node) {
// Set contract backend for ethereum service if local node
// is serving LES requests.
if ctx.GlobalInt(utils.LegacyLightServFlag.Name) > 0 || ctx.GlobalInt(utils.LightServeFlag.Name) > 0 {
- var ethBackend *eth.Ethereum
- if err := stack.ServiceContext.Lifecycle(ðBackend); err != nil {
- utils.Fatalf("Failed to retrieve ethereum service: %v", err)
- }
- ethBackend.SetContractBackend(ethClient)
+ backend.SetContractBackend(ethClient)
}
// Set contract backend for les service if local node is
// running as a light client.
if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" {
- var lesBackend *les.LightEthereum
- if err := stack.ServiceContext.Lifecycle(&lesBackend); err != nil {
- utils.Fatalf("Failed to retrieve light ethereum service: %v", err)
- }
- lesBackend.SetContractBackend(ethClient)
+ backend.SetContractBackend(ethClient)
}
go func() {
@@ -465,24 +456,23 @@ func startNode(ctx *cli.Context, stack *node.Node) {
if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" {
utils.Fatalf("Light clients do not support mining")
}
- // Check if node's backend is eth
- var ethBackend *eth.Ethereum
- if err := stack.ServiceContext.Lifecycle(ðBackend); err != nil {
- utils.Fatalf("Ethereum service not running: %v", err)
- }
// Set the gas price to the limits from the CLI and start mining
gasprice := utils.GlobalBig(ctx, utils.MinerGasPriceFlag.Name)
if ctx.GlobalIsSet(utils.LegacyMinerGasPriceFlag.Name) && !ctx.GlobalIsSet(utils.MinerGasPriceFlag.Name) {
gasprice = utils.GlobalBig(ctx, utils.LegacyMinerGasPriceFlag.Name)
}
- ethBackend.TxPool().SetGasPrice(gasprice)
+ txpool := backend.TxPool()
+ if txpool == nil {
+ utils.Fatalf("Ethereum service not running: %v", err)
+ }
+ txpool.SetGasPrice(gasprice)
threads := ctx.GlobalInt(utils.MinerThreadsFlag.Name)
if ctx.GlobalIsSet(utils.LegacyMinerThreadsFlag.Name) && !ctx.GlobalIsSet(utils.MinerThreadsFlag.Name) {
threads = ctx.GlobalInt(utils.LegacyMinerThreadsFlag.Name)
log.Warn("The flag --minerthreads is deprecated and will be removed in the future, please use --miner.threads")
}
- if err := ethBackend.StartMining(threads); err != nil {
+ if err := backend.StartMining(threads); err != nil {
utils.Fatalf("Failed to start mining: %v", err)
}
}
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index 6622781f478b..e177df569261 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -49,6 +49,7 @@ import (
"github.com/ethereum/go-ethereum/ethstats"
"github.com/ethereum/go-ethereum/graphql"
"github.com/ethereum/go-ethereum/internal/flags"
+ "github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/les"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
@@ -62,7 +63,6 @@ import (
"github.com/ethereum/go-ethereum/p2p/nat"
"github.com/ethereum/go-ethereum/p2p/netutil"
"github.com/ethereum/go-ethereum/params"
- "github.com/ethereum/go-ethereum/rpc"
whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
pcsclite "github.com/gballet/go-libpcsclite"
cli "gopkg.in/urfave/cli.v1"
@@ -1691,12 +1691,13 @@ func setDNSDiscoveryDefaults(cfg *eth.Config, genesis common.Hash) {
}
// RegisterEthService adds an Ethereum client to the stack.
-func RegisterEthService(stack *node.Node, cfg *eth.Config) {
+func RegisterEthService(stack *node.Node, cfg *eth.Config) ethapi.Backend {
if cfg.SyncMode == downloader.LightSync {
- _, err := les.New(stack, cfg)
+ backend, err := les.New(stack, cfg)
if err != nil {
Fatalf("Failed to register the Ethereum service: %v", err)
}
+ return backend.ApiBackend
} else {
backend, err := eth.New(stack, cfg)
if err != nil {
@@ -1706,28 +1707,28 @@ func RegisterEthService(stack *node.Node, cfg *eth.Config) {
ls, _ := les.NewLesServer(backend, cfg)
backend.AddLesServer(ls)
}
+ return backend.APIBackend
}
}
// RegisterShhService configures Whisper and adds it to the given node.
func RegisterShhService(stack *node.Node, cfg *whisper.Config) {
- if err := whisper.New(stack, cfg); err != nil {
+ if _, err := whisper.New(stack, cfg); err != nil {
Fatalf("Failed to register the Whisper service: %v", err)
}
}
// RegisterEthStatsService configures the Ethereum Stats daemon and adds it to
// the given node.
-func RegisterEthStatsService(stack *node.Node, url string) {
- if err := ethstats.New(stack, url); err != nil {
+func RegisterEthStatsService(stack *node.Node, backend ethapi.Backend, url string) {
+ if err := ethstats.New(stack, backend, backend.Engine(), url); err != nil {
Fatalf("Failed to register the Ethereum Stats service: %v", err)
}
}
// RegisterGraphQLService is a utility function to construct a new service and register it against a node.
-func RegisterGraphQLService(stack *node.Node, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) {
- // create new graphQL service
- if err := graphql.New(stack, endpoint, cors, vhosts, timeouts); err != nil {
+func RegisterGraphQLService(stack *node.Node, backend ethapi.Backend, cfg node.Config) {
+ if err := graphql.New(stack, backend, cfg.GraphQLEndpoint(), cfg.GraphQLCors, cfg.GraphQLVirtualHosts, cfg.HTTPTimeouts); err != nil {
Fatalf("Failed to register the GraphQL service: %v", err)
}
}
diff --git a/eth/api_backend.go b/eth/api_backend.go
index a7122da2cba8..46f41e7cd678 100644
--- a/eth/api_backend.go
+++ b/eth/api_backend.go
@@ -23,6 +23,7 @@ import (
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/bloombits"
"github.com/ethereum/go-ethereum/core/rawdb"
@@ -31,8 +32,10 @@ import (
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/eth/gasprice"
+ "github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
+ "github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
)
@@ -257,6 +260,10 @@ func (b *EthAPIBackend) TxPoolContent() (map[common.Address]types.Transactions,
return b.eth.TxPool().Content()
}
+func (b *EthAPIBackend) TxPool() *core.TxPool {
+ return b.eth.TxPool()
+}
+
func (b *EthAPIBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription {
return b.eth.TxPool().SubscribeNewTxsEvent(ch)
}
@@ -307,3 +314,27 @@ func (b *EthAPIBackend) ServiceFilter(ctx context.Context, session *bloombits.Ma
go session.Multiplex(bloomRetrievalBatch, bloomRetrievalWait, b.eth.bloomRequests)
}
}
+
+func (b *EthAPIBackend) Engine() consensus.Engine {
+ return b.eth.engine
+}
+
+func (b *EthAPIBackend) GetBlockByNumber(ctx context.Context, number uint64) (*types.Block, error) {
+ return b.eth.blockchain.GetBlockByNumber(number), nil
+}
+
+func (b *EthAPIBackend) CurrentHeader() *types.Header {
+ return b.eth.blockchain.CurrentHeader()
+}
+
+func (b *EthAPIBackend) Miner() *miner.Miner {
+ return b.eth.Miner()
+}
+
+func (b *EthAPIBackend) StartMining(threads int) error {
+ return b.eth.StartMining(threads)
+}
+
+func (b *EthAPIBackend) SetContractBackend(client *ethclient.Client) {
+ b.eth.SetContractBackend(client)
+}
diff --git a/eth/backend.go b/eth/backend.go
index cfd90d4fe3fd..b9b356d20bee 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -138,7 +138,7 @@ func New(stack *node.Node, config *Config) (*Ethereum, error) {
log.Info("Allocated trie memory caches", "clean", common.StorageSize(config.TrieCleanCache)*1024*1024, "dirty", common.StorageSize(config.TrieDirtyCache)*1024*1024)
// Assemble the Ethereum object
- chainDb, err := stack.ServiceContext.OpenDatabaseWithFreezer("chaindata", config.DatabaseCache, config.DatabaseHandles, config.DatabaseFreezer, "eth/db/chaindata/")
+ chainDb, err := stack.OpenDatabaseWithFreezer("chaindata", config.DatabaseCache, config.DatabaseHandles, config.DatabaseFreezer, "eth/db/chaindata/")
if err != nil {
return nil, err
}
@@ -151,9 +151,9 @@ func New(stack *node.Node, config *Config) (*Ethereum, error) {
eth := &Ethereum{
config: config,
chainDb: chainDb,
- eventMux: stack.ServiceContext.EventMux,
- accountManager: stack.ServiceContext.AccountManager,
- engine: CreateConsensusEngine(stack.ServiceContext, chainConfig, &config.Ethash, config.Miner.Notify, config.Miner.Noverify, chainDb),
+ eventMux: stack.EventMux(),
+ accountManager: stack.AccountManager(),
+ engine: CreateConsensusEngine(stack, chainConfig, &config.Ethash, config.Miner.Notify, config.Miner.Noverify, chainDb),
closeBloomHandler: make(chan struct{}),
networkID: config.NetworkId,
gasPrice: config.Miner.GasPrice,
@@ -208,7 +208,7 @@ func New(stack *node.Node, config *Config) (*Ethereum, error) {
eth.bloomIndexer.Start(eth.blockchain)
if config.TxPool.Journal != "" {
- config.TxPool.Journal = stack.ServiceContext.ResolvePath(config.TxPool.Journal)
+ config.TxPool.Journal = stack.ResolvePath(config.TxPool.Journal)
}
eth.txPool = core.NewTxPool(config.TxPool, chainConfig, eth.blockchain)
@@ -224,14 +224,14 @@ func New(stack *node.Node, config *Config) (*Ethereum, error) {
eth.miner = miner.New(eth, &config.Miner, chainConfig, eth.EventMux(), eth.engine, eth.isLocalBlock)
eth.miner.SetExtra(makeExtraData(config.Miner.ExtraData))
- eth.APIBackend = &EthAPIBackend{stack.ServiceContext.ExtRPCEnabled(), eth, nil}
+ eth.APIBackend = &EthAPIBackend{stack.Config().ExtRPCEnabled(), eth, nil}
gpoParams := config.GPO
if gpoParams.Default == nil {
gpoParams.Default = config.Miner.GasPrice
}
eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, gpoParams)
- eth.dialCandidates, err = eth.setupDiscovery(&stack.ServiceContext.Config.P2P)
+ eth.dialCandidates, err = eth.setupDiscovery(&stack.Config().P2P)
if err != nil {
return nil, err
}
@@ -261,7 +261,7 @@ func makeExtraData(extra []byte) []byte {
}
// CreateConsensusEngine creates the required type of consensus engine instance for an Ethereum service
-func CreateConsensusEngine(ctx *node.ServiceContext, chainConfig *params.ChainConfig, config *ethash.Config, notify []string, noverify bool, db ethdb.Database) consensus.Engine {
+func CreateConsensusEngine(stack *node.Node, chainConfig *params.ChainConfig, config *ethash.Config, notify []string, noverify bool, db ethdb.Database) consensus.Engine {
// If proof-of-authority is requested, set it up
if chainConfig.Clique != nil {
return clique.New(chainConfig.Clique, db)
@@ -279,7 +279,7 @@ func CreateConsensusEngine(ctx *node.ServiceContext, chainConfig *params.ChainCo
return ethash.NewShared()
default:
engine := ethash.New(ethash.Config{
- CacheDir: ctx.ResolvePath(config.CacheDir),
+ CacheDir: stack.ResolvePath(config.CacheDir),
CachesInMem: config.CachesInMem,
CachesOnDisk: config.CachesOnDisk,
CachesLockMmap: config.CachesLockMmap,
@@ -540,15 +540,6 @@ func (s *Ethereum) Protocols() []p2p.Protocol {
return protos
}
-// P2PServer registers the node's running p2p server with the Backend.
-func (s *Ethereum) P2PServer(server *p2p.Server) error {
- if server == nil {
- return node.ErrNodeStopped // TODO is this error okay to return?
- }
- s.p2pServer = server
- return nil
-}
-
// Start implements node.Lifecycle, starting all internal goroutines needed by the
// Ethereum protocol implementation.
func (s *Ethereum) Start() error {
diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go
index bc0305fc229d..e869f492e575 100644
--- a/ethclient/ethclient.go
+++ b/ethclient/ethclient.go
@@ -397,6 +397,14 @@ func (ec *Client) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuer
return ec.c.EthSubscribe(ctx, ch, "logs", arg)
}
+// ToFilterArg is for testing purposes only.
+func ToFilterArg(q ethereum.FilterQuery, test bool) (interface{}, error) {
+ if test {
+ return toFilterArg(q)
+ }
+ return nil, fmt.Errorf("functionality reserved for testing") // TODO is this okay?
+}
+
func toFilterArg(q ethereum.FilterQuery) (interface{}, error) {
arg := map[string]interface{}{
"address": q.Addresses,
diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go
index b49abe917732..09cbdefa7e72 100644
--- a/ethclient/ethclient_test.go
+++ b/ethclient/ethclient_test.go
@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see .
-package ethclient
+package ethclient_test
import (
"context"
@@ -33,23 +33,24 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth"
+ "github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params"
)
// Verify that Client implements the ethereum interfaces.
var (
- _ = ethereum.ChainReader(&Client{})
- _ = ethereum.TransactionReader(&Client{})
- _ = ethereum.ChainStateReader(&Client{})
- _ = ethereum.ChainSyncReader(&Client{})
- _ = ethereum.ContractCaller(&Client{})
- _ = ethereum.GasEstimator(&Client{})
- _ = ethereum.GasPricer(&Client{})
- _ = ethereum.LogFilterer(&Client{})
- _ = ethereum.PendingStateReader(&Client{})
+ _ = ethereum.ChainReader(ðclient.Client{})
+ _ = ethereum.TransactionReader(ðclient.Client{})
+ _ = ethereum.ChainStateReader(ðclient.Client{})
+ _ = ethereum.ChainSyncReader(ðclient.Client{})
+ _ = ethereum.ContractCaller(ðclient.Client{})
+ _ = ethereum.GasEstimator(ðclient.Client{})
+ _ = ethereum.GasPricer(ðclient.Client{})
+ _ = ethereum.LogFilterer(ðclient.Client{})
+ _ = ethereum.PendingStateReader(ðclient.Client{})
// _ = ethereum.PendingStateEventer(&Client{})
- _ = ethereum.PendingContractCaller(&Client{})
+ _ = ethereum.PendingContractCaller(ðclient.Client{})
)
func TestToFilterArg(t *testing.T) {
@@ -163,7 +164,7 @@ func TestToFilterArg(t *testing.T) {
},
} {
t.Run(testCase.name, func(t *testing.T) {
- output, err := toFilterArg(testCase.input)
+ output, err := ethclient.ToFilterArg(testCase.input, true)
if (testCase.err == nil) != (err == nil) {
t.Fatalf("expected error %v but got %v", testCase.err, err)
}
@@ -255,7 +256,7 @@ func TestHeader(t *testing.T) {
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
- ec := NewClient(client)
+ ec := ethclient.NewClient(client)
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
@@ -304,7 +305,7 @@ func TestBalanceAt(t *testing.T) {
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
- ec := NewClient(client)
+ ec := ethclient.NewClient(client)
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
@@ -325,7 +326,7 @@ func TestTransactionInBlockInterrupted(t *testing.T) {
defer backend.Stop()
defer client.Close()
- ec := NewClient(client)
+ ec := ethclient.NewClient(client)
ctx, cancel := context.WithCancel(context.Background())
cancel()
tx, err := ec.TransactionInBlock(ctx, common.Hash{1}, 1)
@@ -342,7 +343,7 @@ func TestChainID(t *testing.T) {
client, _ := backend.Attach()
defer backend.Stop()
defer client.Close()
- ec := NewClient(client)
+ ec := ethclient.NewClient(client)
id, err := ec.ChainID(context.Background())
if err != nil {
diff --git a/ethstats/ethstats.go b/ethstats/ethstats.go
index 0989a9862b12..2f8766ef8cca 100644
--- a/ethstats/ethstats.go
+++ b/ethstats/ethstats.go
@@ -36,7 +36,7 @@ import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth"
- "github.com/ethereum/go-ethereum/event"
+ "github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/les"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
@@ -56,23 +56,15 @@ const (
chainHeadChanSize = 10
)
-type txPool interface {
- // SubscribeNewTxsEvent should return an event subscription of
- // NewTxsEvent and send events to the given channel.
- SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription
-}
-
-type blockChain interface {
- SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription
-}
+// Backend encompasses the backend behaviors needed for the ethstats service.
+type Backend ethapi.Backend
// Service implements an Ethereum netstats reporting daemon that pushes local
// chain statistics up to a monitoring server.
type Service struct {
- server *p2p.Server // Peer-to-peer server to retrieve networking infos
- eth *eth.Ethereum // Full Ethereum service if monitoring a full node
- les *les.LightEthereum // Light Ethereum service if monitoring a light node
- engine consensus.Engine // Consensus engine to retrieve variadic block fields
+ server *p2p.Server // Peer-to-peer server to retrieve networking infos
+ backend Backend
+ engine consensus.Engine // Consensus engine to retrieve variadic block fields
node string // Name of the node to display on the monitoring page
pass string // Password to authorize access to the monitoring page
@@ -83,7 +75,7 @@ type Service struct {
}
// New returns a monitoring service ready for stats reporting.
-func New(node *node.Node, url string) error {
+func New(node *node.Node, backend Backend, engine consensus.Engine, url string) error {
// Parse the netstats connection url
re := regexp.MustCompile("([^:@]*)(:([^@]*))?@(.+)")
parts := re.FindStringSubmatch(url)
@@ -91,27 +83,14 @@ func New(node *node.Node, url string) error {
return fmt.Errorf("invalid netstats url: \"%s\", should be nodename:secret@host:port", url)
}
ethstats := &Service{
- server: node.Server(),
- node: parts[1],
- pass: parts[3],
- host: parts[4],
- pongCh: make(chan struct{}),
- histCh: make(chan []uint64, 1),
- }
-
- // fetch backend
- var ethServ *eth.Ethereum
- if err := node.ServiceContext.Lifecycle(ðServ); err == nil {
- ethstats.eth = ethServ
- ethstats.engine = ethServ.Engine()
- }
- var lesServ *les.LightEthereum
- if err := node.ServiceContext.Lifecycle(&lesServ); err == nil {
- ethstats.les = lesServ
- ethstats.engine = lesServ.Engine()
- }
- if ethstats.engine == nil { // TODO check to make sure at least one backend is not nil?
- return fmt.Errorf("Ethereum service not found")
+ backend: backend,
+ engine: engine,
+ server: node.Server(),
+ node: parts[1],
+ pass: parts[3],
+ host: parts[4],
+ pongCh: make(chan struct{}),
+ histCh: make(chan []uint64, 1),
}
node.RegisterLifecycle(ethstats)
@@ -136,22 +115,12 @@ func (s *Service) Stop() error {
// until termination.
func (s *Service) loop() {
// Subscribe to chain events to execute updates on
- var blockchain blockChain
- var txpool txPool
- if s.eth != nil {
- blockchain = s.eth.BlockChain()
- txpool = s.eth.TxPool()
- } else {
- blockchain = s.les.BlockChain()
- txpool = s.les.TxPool()
- }
-
chainHeadCh := make(chan core.ChainHeadEvent, chainHeadChanSize)
- headSub := blockchain.SubscribeChainHeadEvent(chainHeadCh)
+ headSub := s.backend.SubscribeChainHeadEvent(chainHeadCh)
defer headSub.Unsubscribe()
txEventCh := make(chan core.NewTxsEvent, txChanSize)
- txSub := txpool.SubscribeNewTxsEvent(txEventCh)
+ txSub := s.backend.SubscribeNewTxsEvent(txEventCh)
defer txSub.Unsubscribe()
// Start a goroutine that exhausts the subscriptions to avoid events piling up
@@ -560,29 +529,20 @@ func (s *Service) assembleBlockStats(block *types.Block) *blockStats {
txs []txStats
uncles []*types.Header
)
- if s.eth != nil {
- // Full nodes have all needed information available
- if block == nil {
- block = s.eth.BlockChain().CurrentBlock()
- }
- header = block.Header()
- td = s.eth.BlockChain().GetTd(header.Hash(), header.Number.Uint64())
- txs = make([]txStats, len(block.Transactions()))
- for i, tx := range block.Transactions() {
- txs[i].Hash = tx.Hash()
- }
- uncles = block.Uncles()
- } else {
- // Light nodes would need on-demand lookups for transactions/uncles, skip
- if block != nil {
- header = block.Header()
- } else {
- header = s.les.BlockChain().CurrentHeader()
- }
- td = s.les.BlockChain().GetTd(header.Hash(), header.Number.Uint64())
- txs = []txStats{}
+ // Full nodes have all needed information available
+ if block == nil {
+ block = s.backend.CurrentBlock()
+ }
+ header = block.Header()
+ td = s.backend.GetTd(header.Hash()) // TODO is it okay to just call `GetTD` with just the hash and not number?
+
+ txs = make([]txStats, len(block.Transactions()))
+ for i, tx := range block.Transactions() {
+ txs[i].Hash = tx.Hash()
}
+ uncles = block.Uncles()
+
// Assemble and return the block stats
author, _ := s.engine.Author(header)
@@ -613,12 +573,7 @@ func (s *Service) reportHistory(conn *websocket.Conn, list []uint64) error {
indexes = append(indexes, list...)
} else {
// No indexes requested, send back the top ones
- var head int64
- if s.eth != nil {
- head = s.eth.BlockChain().CurrentHeader().Number.Int64()
- } else {
- head = s.les.BlockChain().CurrentHeader().Number.Int64()
- }
+ head := s.backend.CurrentHeader().Number.Int64()
start := head - historyUpdateRange + 1
if start < 0 {
start = 0
@@ -631,14 +586,11 @@ func (s *Service) reportHistory(conn *websocket.Conn, list []uint64) error {
history := make([]*blockStats, len(indexes))
for i, number := range indexes {
// Retrieve the next block if it's known to us
- var block *types.Block
- if s.eth != nil {
- block = s.eth.BlockChain().GetBlockByNumber(number)
- } else {
- if header := s.les.BlockChain().GetHeaderByNumber(number); header != nil {
- block = types.NewBlockWithHeader(header)
- }
+ block, err := s.backend.GetBlockByNumber(context.Background(), number)
+ if err != nil {
+ return err
}
+
// If we do have the block, add to the history and continue
if block != nil {
history[len(history)-1-i] = s.assembleBlockStats(block)
@@ -673,12 +625,7 @@ type pendStats struct {
// it to the stats server.
func (s *Service) reportPending(conn *websocket.Conn) error {
// Retrieve the pending count from the local blockchain
- var pending int
- if s.eth != nil {
- pending, _ = s.eth.TxPool().Stats()
- } else {
- pending = s.les.TxPool().Stats()
- }
+ pending, _ := s.backend.Stats()
// Assemble the transaction stats and send it to the server
log.Trace("Sending pending transactions to ethstats", "count", pending)
@@ -712,22 +659,20 @@ func (s *Service) reportStats(conn *websocket.Conn) error {
var (
mining bool
hashrate int
- syncing bool
- gasprice int
)
- if s.eth != nil {
- mining = s.eth.Miner().Mining()
- hashrate = int(s.eth.Miner().HashRate())
- sync := s.eth.Downloader().Progress()
- syncing = s.eth.BlockChain().CurrentHeader().Number.Uint64() >= sync.HighestBlock
-
- price, _ := s.eth.APIBackend.SuggestPrice(context.Background())
- gasprice = int(price.Uint64())
- } else {
- sync := s.les.Downloader().Progress()
- syncing = s.les.BlockChain().CurrentHeader().Number.Uint64() >= sync.HighestBlock
+ mine := s.backend.Miner()
+ if mine != nil {
+ mining = mine.Mining()
+ hashrate = int(s.backend.Miner().HashRate())
}
+
+ sync := s.backend.Downloader().Progress()
+ syncing := s.backend.CurrentHeader().Number.Uint64() >= sync.HighestBlock
+
+ price, _ := s.backend.SuggestPrice(context.Background())
+ gasprice := int(price.Uint64())
+
// Assemble the node stats and send it to the server
log.Trace("Sending node details to ethstats")
diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go
index 1c2a56ab0877..3b18cb5e670a 100644
--- a/graphql/graphql_test.go
+++ b/graphql/graphql_test.go
@@ -181,13 +181,13 @@ func createNode(t *testing.T, gqlEnabled bool) *node.Node {
func createGQLService(t *testing.T, stack *node.Node, endpoint string) {
// create backend
- _, err := eth.New(stack, ð.DefaultConfig)
+ ethBackend, err := eth.New(stack, ð.DefaultConfig)
if err != nil {
t.Fatalf("could not create eth backend: %v", err)
}
// create gql service
- err = New(stack, endpoint, []string{}, []string{}, rpc.DefaultHTTPTimeouts)
+ err = New(stack, ethBackend.APIBackend, endpoint, []string{}, []string{}, rpc.DefaultHTTPTimeouts)
if err != nil {
t.Fatalf("could not create graphql service: %v", err)
}
diff --git a/graphql/service.go b/graphql/service.go
index 8bec768ef6ef..f93f12a545e3 100644
--- a/graphql/service.go
+++ b/graphql/service.go
@@ -17,12 +17,9 @@
package graphql
import (
- "errors"
"net/http"
- "github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/internal/ethapi"
- "github.com/ethereum/go-ethereum/les"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/rpc"
"github.com/graph-gophers/graphql-go"
@@ -30,19 +27,9 @@ import (
)
// New constructs a new GraphQL service instance.
-func New(stack *node.Node, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) error {
- // fetch backend
- var backend ethapi.Backend
- var ethServ *eth.Ethereum
- if err := stack.ServiceContext.Lifecycle(ðServ); err == nil {
- backend = ethServ.APIBackend
- }
- var lesServ *les.LightEthereum
- if err := stack.ServiceContext.Lifecycle(&lesServ); err == nil {
- backend = lesServ.ApiBackend
- }
+func New(stack *node.Node, backend ethapi.Backend, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) error {
if backend == nil {
- return errors.New("No backend found") // TODO should this be a fatal error?
+ stack.Fatalf("missing backend")
}
// check if http server with given endpoint exists and enable graphQL on it
server := stack.ExistingHTTPServer(endpoint)
diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go
index 074cd794a65a..6d8374eb53c9 100644
--- a/internal/ethapi/backend.go
+++ b/internal/ethapi/backend.go
@@ -23,14 +23,17 @@ import (
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/bloombits"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/downloader"
+ "github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
+ "github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
)
@@ -53,9 +56,12 @@ type Backend interface {
HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error)
HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error)
HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error)
+ CurrentHeader() *types.Header
+ CurrentBlock() *types.Block
BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error)
BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error)
BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error)
+ GetBlockByNumber(ctx context.Context, number uint64) (*types.Block, error)
StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error)
StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error)
GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error)
@@ -73,8 +79,13 @@ type Backend interface {
GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error)
Stats() (pending int, queued int)
TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions)
+ TxPool() *core.TxPool
SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription
+ // Mining API
+ Miner() *miner.Miner
+ StartMining(threads int) error
+
// Filter API
BloomStatus() (uint64, uint64)
GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error)
@@ -84,7 +95,9 @@ type Backend interface {
SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription
ChainConfig() *params.ChainConfig
- CurrentBlock() *types.Block
+ Engine() consensus.Engine
+
+ SetContractBackend(client *ethclient.Client)
}
func GetAPIs(apiBackend Backend) []rpc.API {
diff --git a/les/api_backend.go b/les/api_backend.go
index 448260a19802..d905081077a6 100644
--- a/les/api_backend.go
+++ b/les/api_backend.go
@@ -19,10 +19,12 @@ package les
import (
"context"
"errors"
+ "fmt"
"math/big"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/bloombits"
"github.com/ethereum/go-ethereum/core/rawdb"
@@ -31,9 +33,11 @@ import (
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/eth/gasprice"
+ "github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/light"
+ "github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
)
@@ -282,3 +286,32 @@ func (b *LesApiBackend) ServiceFilter(ctx context.Context, session *bloombits.Ma
go session.Multiplex(bloomRetrievalBatch, bloomRetrievalWait, b.eth.bloomRequests)
}
}
+
+func (b *LesApiBackend) Engine() consensus.Engine {
+ return b.eth.engine
+}
+
+func (b *LesApiBackend) GetBlockByNumber(ctx context.Context, number uint64) (*types.Block, error) {
+ header := b.eth.blockchain.GetHeaderByNumber(number)
+ return types.NewBlockWithHeader(header), nil // TODO is this okay?
+}
+
+func (b *LesApiBackend) CurrentHeader() *types.Header {
+ return b.eth.blockchain.CurrentHeader()
+}
+
+func (b *LesApiBackend) Miner() *miner.Miner {
+ return nil
+}
+
+func (b *LesApiBackend) StartMining(threads int) error {
+ return fmt.Errorf("Light clients do not support mining") // TODO is this okay?
+}
+
+func (b *LesApiBackend) SetContractBackend(client *ethclient.Client) {
+ b.eth.SetContractBackend(client)
+}
+
+func (b *LesApiBackend) TxPool() *core.TxPool {
+ return nil // TODO is this okay?
+}
diff --git a/les/client.go b/les/client.go
index 3ed45c124b99..0ae6700d0bb4 100644
--- a/les/client.go
+++ b/les/client.go
@@ -78,11 +78,11 @@ type LightEthereum struct {
}
func New(stack *node.Node, config *eth.Config) (*LightEthereum, error) {
- chainDb, err := stack.ServiceContext.OpenDatabase("lightchaindata", config.DatabaseCache, config.DatabaseHandles, "eth/db/chaindata/")
+ chainDb, err := stack.OpenDatabase("lightchaindata", config.DatabaseCache, config.DatabaseHandles, "eth/db/chaindata/")
if err != nil {
return nil, err
}
- lespayDb, err := stack.ServiceContext.OpenDatabase("lespay", 0, 0, "eth/db/lespay")
+ lespayDb, err := stack.OpenDatabase("lespay", 0, 0, "eth/db/lespay")
if err != nil {
return nil, err
}
@@ -103,10 +103,10 @@ func New(stack *node.Node, config *eth.Config) (*LightEthereum, error) {
closeCh: make(chan struct{}),
},
peers: peers,
- eventMux: stack.ServiceContext.EventMux,
+ eventMux: stack.EventMux(),
reqDist: newRequestDistributor(peers, &mclock.System{}),
- accountManager: stack.ServiceContext.AccountManager,
- engine: eth.CreateConsensusEngine(stack.ServiceContext, chainConfig, &config.Ethash, nil, false, chainDb),
+ accountManager: stack.AccountManager(),
+ engine: eth.CreateConsensusEngine(stack, chainConfig, &config.Ethash, nil, false, chainDb),
bloomRequests: make(chan chan *bloombits.Retrieval),
bloomIndexer: eth.NewBloomIndexer(chainDb, params.BloomBitsBlocksClient, params.HelperTrieConfirmations),
valueTracker: lpc.NewValueTracker(lespayDb, &mclock.System{}, requestList, time.Minute, 1/float64(time.Hour), 1/float64(time.Hour*100), 1/float64(time.Hour*1000)),
@@ -114,7 +114,7 @@ func New(stack *node.Node, config *eth.Config) (*LightEthereum, error) {
}
peers.subscribe((*vtSubscription)(leth.valueTracker))
- dnsdisc, err := leth.setupDiscovery(&stack.ServiceContext.Config.P2P)
+ dnsdisc, err := leth.setupDiscovery(&stack.Config().P2P)
if err != nil {
return nil, err
}
@@ -164,7 +164,7 @@ func New(stack *node.Node, config *eth.Config) (*LightEthereum, error) {
rawdb.WriteChainConfig(chainDb, genesisHash, chainConfig)
}
- leth.ApiBackend = &LesApiBackend{stack.ServiceContext.ExtRPCEnabled(), leth, nil}
+ leth.ApiBackend = &LesApiBackend{stack.Config().ExtRPCEnabled(), leth, nil}
gpoParams := config.GPO
if gpoParams.Default == nil {
gpoParams.Default = config.Miner.GasPrice
diff --git a/miner/stress_clique.go b/miner/stress_clique.go
index 6f65ddddfca2..143ce3f5eb2e 100644
--- a/miner/stress_clique.go
+++ b/miner/stress_clique.go
@@ -22,6 +22,7 @@ package main
import (
"bytes"
"crypto/ecdsa"
+ "github.com/ethereum/go-ethereum/internal/ethapi"
"io/ioutil"
"math/big"
"math/rand"
@@ -59,12 +60,16 @@ func main() {
genesis := makeGenesis(faucets, sealers)
var (
- nodes []*node.Node
+ nodes []struct{
+ node *node.Node
+ backend ethapi.Backend
+ }
enodes []*enode.Node
)
+
for _, sealer := range sealers {
// Start the node and wait until it's up
- node, err := makeSealer(genesis)
+ node, ethBackend, err := makeSealer(genesis)
if err != nil {
panic(err)
}
@@ -78,7 +83,13 @@ func main() {
node.Server().AddPeer(n)
}
// Start tracking the node and it's enode
- nodes = append(nodes, node)
+ nodes = append(nodes, struct{
+ node *node.Node
+ backend ethapi.Backend
+ }{
+ node,
+ ethBackend,
+ })
enodes = append(enodes, node.Server().Self())
// Inject the signer key and start sealing with it
@@ -95,11 +106,7 @@ func main() {
time.Sleep(3 * time.Second)
for _, node := range nodes {
- var ethereum *eth.Ethereum
- if err := node.ServiceContext.Lifecycle(ðereum); err != nil {
- panic(err)
- }
- if err := ethereum.StartMining(1); err != nil {
+ if err := node.backend.StartMining(1); err != nil {
panic(err)
}
}
@@ -111,22 +118,24 @@ func main() {
index := rand.Intn(len(faucets))
// Fetch the accessor for the relevant signer
- var ethereum *eth.Ethereum
- if err := nodes[index%len(nodes)].Service(ðereum); err != nil {
- panic(err)
- }
+ backend := nodes[index%len(nodes)].backend
+
// Create a self transaction and inject into the pool
tx, err := types.SignTx(types.NewTransaction(nonces[index], crypto.PubkeyToAddress(faucets[index].PublicKey), new(big.Int), 21000, big.NewInt(100000000000), nil), types.HomesteadSigner{}, faucets[index])
if err != nil {
panic(err)
}
- if err := ethereum.TxPool().AddLocal(tx); err != nil {
+ txpool := backend.TxPool()
+ if txpool == nil {
+ panic(fmt.Errorf("Ethereum service not running"))
+ }
+ if err := txpool.AddLocal(tx); err != nil {
panic(err)
}
nonces[index]++
// Wait if we're too saturated
- if pend, _ := ethereum.TxPool().Stats(); pend > 2048 {
+ if pend, _ := txpool.Stats(); pend > 2048 {
time.Sleep(100 * time.Millisecond)
}
}
@@ -169,7 +178,7 @@ func makeGenesis(faucets []*ecdsa.PrivateKey, sealers []*ecdsa.PrivateKey) *core
return genesis
}
-func makeSealer(genesis *core.Genesis) (*node.Node, error) {
+func makeSealer(genesis *core.Genesis) (*node.Node, ethapi.Backend, error) {
// Define the basic configurations for the Ethereum node
datadir, _ := ioutil.TempDir("", "")
@@ -213,5 +222,5 @@ func makeSealer(genesis *core.Genesis) (*node.Node, error) {
stack.RegisterLifecycle(ethBackend)
// Start the node and return if successful
- return stack, stack.Start()
+ return stack, ethBackend, stack.Start()
}
diff --git a/miner/stress_ethash.go b/miner/stress_ethash.go
index 6893dff6e273..4e0a75174d3f 100644
--- a/miner/stress_ethash.go
+++ b/miner/stress_ethash.go
@@ -61,12 +61,15 @@ func main() {
genesis := makeGenesis(faucets)
var (
- nodes []*node.Node
+ nodes []struct{
+ node *node.Node
+ backend ethapi.Backend
+ }
enodes []*enode.Node
)
for i := 0; i < 4; i++ {
// Start the node and wait until it's up
- node, err := makeMiner(genesis)
+ node, ethBackend, err := makeMiner(genesis)
if err != nil {
panic(err)
}
@@ -80,7 +83,13 @@ func main() {
node.Server().AddPeer(n)
}
// Start tracking the node and it's enode
- nodes = append(nodes, node)
+ nodes = append(nodes, struct{
+ node *node.Node
+ backend ethapi.Backend
+ }{
+ node,
+ ethBackend,
+ })
enodes = append(enodes, node.Server().Self())
// Inject the signer key and start sealing with it
@@ -93,11 +102,7 @@ func main() {
time.Sleep(3 * time.Second)
for _, node := range nodes {
- var ethereum *eth.Ethereum
- if err := node.ServiceContext.Lifecycle(ðereum); err != nil {
- panic(err)
- }
- if err := ethereum.StartMining(1); err != nil {
+ if err := node.backend.StartMining(1); err != nil {
panic(err)
}
}
@@ -107,24 +112,24 @@ func main() {
nonces := make([]uint64, len(faucets))
for {
index := rand.Intn(len(faucets))
-
// Fetch the accessor for the relevant signer
- var ethereum *eth.Ethereum
- if err := nodes[index%len(nodes)].Service(ðereum); err != nil {
- panic(err)
- }
+ backend := nodes[index%len(nodes)].backend
// Create a self transaction and inject into the pool
tx, err := types.SignTx(types.NewTransaction(nonces[index], crypto.PubkeyToAddress(faucets[index].PublicKey), new(big.Int), 21000, big.NewInt(100000000000+rand.Int63n(65536)), nil), types.HomesteadSigner{}, faucets[index])
if err != nil {
panic(err)
}
- if err := ethereum.TxPool().AddLocal(tx); err != nil {
+ txpool := backend.TxPool()
+ if txpool == nil {
+ panic(fmt.Errorf("Ethereum service not running"))
+ }
+ if err := txpool.AddLocal(tx); err != nil {
panic(err)
}
nonces[index]++
// Wait if we're too saturated
- if pend, _ := ethereum.TxPool().Stats(); pend > 2048 {
+ if pend, _ := txpool.Stats(); pend > 2048 {
time.Sleep(100 * time.Millisecond)
}
}
@@ -149,7 +154,7 @@ func makeGenesis(faucets []*ecdsa.PrivateKey) *core.Genesis {
return genesis
}
-func makeMiner(genesis *core.Genesis) (*node.Node, error) {
+func makeMiner(genesis *core.Genesis) (*node.Node, ethapi.Backend, error) {
// Define the basic configurations for the Ethereum node
datadir, _ := ioutil.TempDir("", "")
@@ -194,5 +199,5 @@ func makeMiner(genesis *core.Genesis) (*node.Node, error) {
stack.RegisterLifecycle(ethBackend)
// Start the node and return if successful
- return stack, stack.Start()
+ return stack, ethBackend, stack.Start()
}
diff --git a/mobile/geth.go b/mobile/geth.go
index 053c304f6738..22567a5d107b 100644
--- a/mobile/geth.go
+++ b/mobile/geth.go
@@ -175,20 +175,20 @@ func NewNode(datadir string, config *NodeConfig) (stack *Node, _ error) {
ethConf.SyncMode = downloader.LightSync
ethConf.NetworkId = uint64(config.EthereumNetworkID)
ethConf.DatabaseCache = config.EthereumDatabaseCache
- _, err = les.New(rawStack, ðConf)
+ lesBackend, err := les.New(rawStack, ðConf)
if err != nil {
return nil, fmt.Errorf("ethereum init: %v", err)
}
// If netstats reporting is requested, do it
if config.EthereumNetStats != "" {
- if err := ethstats.New(rawStack, config.EthereumNetStats); err != nil {
+ if err := ethstats.New(rawStack, lesBackend.ApiBackend, lesBackend.Engine(), config.EthereumNetStats); err != nil {
return nil, fmt.Errorf("netstats init: %v", err)
}
}
}
// Register the Whisper protocol if requested
if config.WhisperEnabled {
- if err := whisper.New(rawStack, &whisper.DefaultConfig); err != nil {
+ if _, err := whisper.New(rawStack, &whisper.DefaultConfig); err != nil {
return nil, fmt.Errorf("whisper init: %v", err)
}
}
diff --git a/node/api.go b/node/api.go
index ec9b836d7203..d6f1901907aa 100644
--- a/node/api.go
+++ b/node/api.go
@@ -159,7 +159,7 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
}
endpoint := fmt.Sprintf("%s:%d", *host, *port)
// check if HTTP server already exists
- if server, exists := api.node.HTTPServers.servers[endpoint]; exists {
+ if server, exists := api.node.httpServers[endpoint]; exists {
if server.RPCAllowed {
return false, fmt.Errorf("HTTP RPC already running on %v", server.Listener.Addr())
}
@@ -220,7 +220,7 @@ func (api *PrivateAdminAPI) StopRPC() (bool, error) {
api.node.lock.Lock()
defer api.node.lock.Unlock()
- for _, httpServer := range api.node.HTTPServers.servers {
+ for _, httpServer := range api.node.httpServers {
if httpServer.RPCAllowed {
api.node.stopServer(httpServer)
return true, nil
@@ -235,7 +235,7 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
api.node.lock.Lock()
defer api.node.lock.Unlock()
// check if an existing WS server already exists
- for _, server := range api.node.HTTPServers.servers {
+ for _, server := range api.node.httpServers {
if server.WSAllowed {
return false, fmt.Errorf("WebSocket RPC already running on %v", server.Listener.Addr())
}
@@ -253,7 +253,7 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
}
endpoint := fmt.Sprintf("%s:%d", *host, *port)
// check if there is an existing server on the specified port, and if there is, enable ws on it
- if server, exists := api.node.HTTPServers.servers[endpoint]; exists {
+ if server, exists := api.node.httpServers[endpoint]; exists {
// else configure ws on the existing server
server.WSAllowed = true
// configure origins
@@ -322,7 +322,7 @@ func (api *PrivateAdminAPI) StopWS() (bool, error) {
api.node.lock.Lock()
defer api.node.lock.Unlock()
- for _, httpServer := range api.node.HTTPServers.servers {
+ for _, httpServer := range api.node.httpServers {
if httpServer.WSAllowed {
httpServer.WSAllowed = false
// if RPC is not enabled on the WS http server, shut it down
diff --git a/node/lifecycle.go b/node/lifecycle.go
new file mode 100644
index 000000000000..0d5f9a0680a0
--- /dev/null
+++ b/node/lifecycle.go
@@ -0,0 +1,31 @@
+// Copyright 2020 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package node
+
+// Lifecycle encompasses the behavior of services that can be started and stopped
+// on the node. Lifecycle management is delegated to the node, but it is the
+// responsibility of the service-specific package to configure and register the
+// service on the node using the `RegisterLifecycle` method.
+type Lifecycle interface {
+ // Start is called after all services have been constructed and the networking
+ // layer was also initialized to spawn any goroutines required by the service.
+ Start() error
+
+ // Stop terminates all goroutines belonging to the service, blocking until they
+ // are all terminated.
+ Stop() error
+}
diff --git a/node/node.go b/node/node.go
index f4c35254ac67..d347c7fbaa69 100644
--- a/node/node.go
+++ b/node/node.go
@@ -52,11 +52,9 @@ type Node struct {
server *p2p.Server // Currently running P2P networking layer
- ServiceContext *ServiceContext // TODO rename to LifecycleContext or just NodeContext?
-
lifecycles map[reflect.Type]Lifecycle // All registered backends, services, and auxiliary services that have a lifecycle
- HTTPServers *HTTPServers // HTTPServers stores information about the node's rpc, ws, and graphQL http servers.
+ httpServers serverMap // serverMap stores information about the node's rpc, ws, and graphQL http servers.
rpcAPIs []rpc.API // List of APIs currently provided by the node
inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
@@ -109,13 +107,7 @@ func New(conf *Config) (*Node, error) {
ephemeralKeystore: ephemeralKeystore,
config: conf,
lifecycles: make(map[reflect.Type]Lifecycle),
- ServiceContext: &ServiceContext{
- Config: *conf,
- Lifecycles: make(map[reflect.Type]Lifecycle),
- },
- HTTPServers: &HTTPServers{
- servers: make(map[string]*HTTPServer),
- },
+ httpServers: make(serverMap),
ipc: &HTTPServer{
endpoint: conf.IPCEndpoint(),
},
@@ -138,9 +130,7 @@ func New(conf *Config) (*Node, error) {
if node.server.Config.NodeDatabase == "" {
node.server.Config.NodeDatabase = node.config.NodeDB()
}
- // Configure service context
- node.ServiceContext.EventMux = node.eventmux
- node.ServiceContext.AccountManager = node.accman
+
// Configure HTTP server(s)
if conf.HTTPHost != "" {
httpServ := &HTTPServer{
@@ -159,13 +149,14 @@ func New(conf *Config) (*Node, error) {
httpServ.WSAllowed = true
httpServ.WsOrigins = conf.WSOrigins
httpServ.Whitelist = append(httpServ.Whitelist, conf.WSModules...)
- node.HTTPServers.servers[conf.HTTPEndpoint()] = httpServ
+
+ node.httpServers[conf.HTTPEndpoint()] = httpServ
return node, nil
}
- node.HTTPServers.servers[conf.HTTPEndpoint()] = httpServ
+ node.httpServers[conf.HTTPEndpoint()] = httpServ
}
if conf.WSHost != "" {
- node.HTTPServers.servers[conf.WSEndpoint()] = &HTTPServer{
+ node.httpServers[conf.WSEndpoint()] = &HTTPServer{
WsOrigins: conf.WSOrigins,
Whitelist: conf.WSModules,
Srv: rpc.NewServer(),
@@ -206,11 +197,10 @@ func (n *Node) Close() error {
func (n *Node) RegisterLifecycle(lifecycle Lifecycle) {
kind := reflect.TypeOf(lifecycle)
if _, exists := n.lifecycles[kind]; exists {
- Fatalf("Lifecycle cannot be registered more than once", kind)
+ n.Fatalf("Lifecycle cannot be registered more than once", kind)
}
n.lifecycles[kind] = lifecycle
- n.ServiceContext.Lifecycles[kind] = lifecycle
}
// RegisterProtocols adds backend's protocols to the node's p2p server
@@ -225,12 +215,12 @@ func (n *Node) RegisterAPIs(apis []rpc.API) {
// RegisterHTTPServer registers the given HTTP server on the node
func (n *Node) RegisterHTTPServer(endpoint string, server *HTTPServer) {
- n.HTTPServers.servers[endpoint] = server
+ n.httpServers[endpoint] = server
}
// ExistingHTTPServer checks if an HTTP server is already configured on the given endpoint
func (n *Node) ExistingHTTPServer(endpoint string) *HTTPServer {
- if server, exists := n.HTTPServers.servers[endpoint]; exists {
+ if server, exists := n.httpServers[endpoint]; exists {
return server
}
return nil
@@ -258,8 +248,7 @@ func (n *Node) CreateHTTPServer(h *HTTPServer, exposeAll bool) error {
httpSrv.WriteTimeout = h.Timeouts.WriteTimeout
httpSrv.IdleTimeout = h.Timeouts.IdleTimeout
}
-
- // complete the HTTPServers
+ // add listener and http.Server to HTTPServer
h.Listener = listener
h.Server = httpSrv
@@ -294,7 +283,7 @@ func (n *Node) Start() error {
// Configure the RPC interfaces
if err := n.configureRPC(); err != nil {
- n.HTTPServers.Stop()
+ n.httpServers.Stop()
n.server.Stop()
return err
}
@@ -310,10 +299,6 @@ func (n *Node) Start() error {
started = append(started, lifecycle)
}
- // Finish initializing the service context
- n.ServiceContext.AccountManager = n.accman
- n.ServiceContext.EventMux = n.eventmux
-
// Finish initializing the startup
n.stop = make(chan struct{})
return nil
@@ -365,7 +350,7 @@ func (n *Node) configureRPC() error {
return err
}
- for _, server := range n.HTTPServers.servers {
+ for _, server := range n.httpServers {
// configure the handlers
if server.RPCAllowed {
server.handler = NewHTTPHandlerStack(server.Srv, server.CorsAllowedOrigins, server.Vhosts)
@@ -396,8 +381,8 @@ func (n *Node) configureRPC() error {
}
}
// only register http server as a lifecycle if it has not already been registered
- if _, exists := n.lifecycles[reflect.TypeOf(n.HTTPServers)]; !exists {
- n.RegisterLifecycle(n.HTTPServers)
+ if _, exists := n.lifecycles[reflect.TypeOf(n.httpServers)]; !exists {
+ n.RegisterLifecycle(n.httpServers)
}
// All API endpoints started successfully
return nil
@@ -467,7 +452,7 @@ func (n *Node) stopServer(server *HTTPServer) {
server.Srv = nil
}
// remove stopped http server from node's http servers // TODO is this preferable?
- delete(n.HTTPServers.servers, server.endpoint)
+ delete(n.httpServers, server.endpoint)
}
// Stop terminates a running node along with all it's services. In the node was
@@ -594,7 +579,7 @@ func (n *Node) WSEndpoint() string {
n.lock.Lock()
defer n.lock.Unlock()
- for _, httpServer := range n.HTTPServers.servers {
+ for _, httpServer := range n.httpServers {
if httpServer.WSAllowed {
if httpServer.Listener != nil {
return httpServer.Listener.Addr().String()
@@ -612,24 +597,6 @@ func (n *Node) EventMux() *event.TypeMux {
return n.eventmux
}
-// Lifecycle retrieves a currently running Lifecycle registered of a specific type.
-func (n *Node) Lifecycle(lifecycle interface{}) error {
- n.lock.RLock()
- defer n.lock.RUnlock()
-
- // Short circuit if the node's not running
- if !n.running() {
- return ErrNodeStopped
- }
- // Otherwise try to find the service to return
- element := reflect.ValueOf(lifecycle).Elem()
- if running, ok := n.lifecycles[element.Type()]; ok {
- element.Set(reflect.ValueOf(running))
- return nil
- }
- return ErrServiceUnknown
-}
-
// OpenDatabase opens an existing database with the given name (or creates one if no
// previous can be found) from within the node's instance directory. If the node is
// ephemeral, a memory database is returned.
@@ -712,11 +679,10 @@ func RegisterApisFromWhitelist(apis []rpc.API, modules []string, srv *rpc.Server
return nil
}
-// TODO change this when you figure out how else to do a nice fatal err
// Fatalf formats a message to standard error and exits the program.
// The message is also printed to standard output if standard error
// is redirected to a different file.
-func Fatalf(format string, args ...interface{}) {
+func (n *Node) Fatalf(format string, args ...interface{}) {
w := io.MultiWriter(os.Stdout, os.Stderr)
if runtime.GOOS == "windows" {
// The SameFile check below doesn't work on Windows.
diff --git a/node/node_test.go b/node/node_test.go
index e00c686058e4..d87a5612a5ce 100644
--- a/node/node_test.go
+++ b/node/node_test.go
@@ -364,47 +364,6 @@ func TestLifecycleTerminationGuarantee(t *testing.T) {
stack.server.PrivateKey = testNodeKey
}
-// TestLifecycleRetrieval tests that individual services can be retrieved.
-func TestLifecycleRetrieval(t *testing.T) {
- // Create a simple stack and register two service types
- stack, err := New(testNodeConfig())
- if err != nil {
- t.Fatalf("failed to create protocol stack: %v", err)
- }
- defer stack.Close()
-
- noop := NewNoop()
- stack.RegisterLifecycle(noop)
-
- is, err := NewInstrumentedService()
- if err != nil {
- t.Fatalf("instrumented service creation failed: %v", err)
- }
- stack.RegisterLifecycle(is)
-
- // Make sure none of the services can be retrieved until started
- var noopServ *Noop
- if err := stack.Lifecycle(&noopServ); err != ErrNodeStopped {
- t.Fatalf("noop service retrieval mismatch: have %v, want %v", err, ErrNodeStopped)
- }
- var instServ *InstrumentedService
- if err := stack.Lifecycle(&instServ); err != ErrNodeStopped {
- t.Fatalf("instrumented service retrieval mismatch: have %v, want %v", err, ErrNodeStopped)
- }
- // Start the stack and ensure everything is retrievable now
- if err := stack.Start(); err != nil {
- t.Fatalf("failed to start stack: %v", err)
- }
- defer stack.Stop()
-
- if err := stack.Lifecycle(&noopServ); err != nil {
- t.Fatalf("noop service retrieval mismatch: have %v, want %v", err, nil)
- }
- if err := stack.Lifecycle(&instServ); err != nil {
- t.Fatalf("instrumented service retrieval mismatch: have %v, want %v", err, nil)
- }
-}
-
// Tests whether a given HTTPServer can be registered on the node
func TestRegisterHTTPServer(t *testing.T) {
stack, err := New(testNodeConfig())
@@ -449,15 +408,21 @@ func TestRegisterHTTPServer(t *testing.T) {
func TestHTTPServerCreateAndStop(t *testing.T) {
// test on same ports
node1 := startHTTP(t, 7453, 7453)
- if len(node1.HTTPServers.servers) != 1 {
+ if len(node1.httpServers) != 1 {
t.Fatalf("node has more than 1 http server")
}
// check to make sure http servers are registered
- var httpSrv1 *HTTPServers
- if err := node1.Lifecycle(&httpSrv1); err != nil {
- t.Fatalf("HTTP servers not registered as lifecycles on the node: %v", err)
+ var exists bool
+ for _, lifecycle := range node1.lifecycles {
+ if reflect.DeepEqual(node1.httpServers, lifecycle) {
+ exists = true
+ }
+ }
+ if !exists {
+ t.Fatal("HTTP servers not registered as lifecycles on the node")
}
- for _, server := range node1.HTTPServers.servers {
+ // check to make sure http servers are configured properly
+ for _, server := range node1.httpServers {
if !(server.WSAllowed && server.RPCAllowed) {
t.Fatalf("node's http server is not configured to handle both rpc and ws")
}
@@ -466,21 +431,25 @@ func TestHTTPServerCreateAndStop(t *testing.T) {
t.Fatalf("failed to remove server %v from node after stopping it", server)
}
}
-
node1.Close()
// test on separate ports
node2 := startHTTP(t, 7453, 9393)
- if len(node2.HTTPServers.servers) != 2 {
+ if len(node2.httpServers) != 2 {
t.Fatalf("amount of http servers on the node is not equal to 2")
}
// check to make sure http servers are registered
- var httpSrv2 *HTTPServers
- if err := node2.Lifecycle(&httpSrv2); err != nil {
- t.Fatalf("HTTP servers not registered as lifecycles on the node: %v", err)
+ exists = false
+ for _, lifecycle := range node2.lifecycles {
+ if reflect.DeepEqual(node2.httpServers, lifecycle) {
+ exists = true
+ }
+ }
+ if !exists {
+ t.Fatal("HTTP servers not registered as lifecycles on the node")
}
// check that neither http server has both ws and rpc enabled
- for _, server := range node2.HTTPServers.servers {
+ for _, server := range node2.httpServers {
if server.WSAllowed && server.RPCAllowed {
t.Fatalf("both rpc and ws allowed on a single http server")
}
diff --git a/node/rpcstack.go b/node/rpcstack.go
index 3ceab681e687..d12089274b8d 100644
--- a/node/rpcstack.go
+++ b/node/rpcstack.go
@@ -32,9 +32,7 @@ import (
"github.com/rs/cors"
)
-type HTTPServers struct {
- servers map[string]*HTTPServer // Stores information about all http servers (if any) by their port, including http, ws, and graphql
-}
+type serverMap map[string]*HTTPServer // Stores information about all http servers (if any) by their endpoint, including http, ws, and graphql
type HTTPServer struct {
handler http.Handler
@@ -55,23 +53,23 @@ type HTTPServer struct {
Timeouts rpc.HTTPTimeouts
RPCAllowed bool
- WSAllowed bool
+ WSAllowed bool // TODO discuss this later bc possible race condition
GQLAllowed bool
GQLHandler http.Handler
}
-func (h *HTTPServers) Start() error {
- for _, server := range h.servers {
+func (sm serverMap) Start() error {
+ for _, server := range sm {
if err := server.Start(); err != nil {
- return h.Stop()
+ return sm.Stop()
}
}
return nil
}
-func (h *HTTPServers) Stop() error {
- for _, server := range h.servers {
+func (sm serverMap) Stop() error {
+ for _, server := range sm {
if err := server.Stop(); err != nil {
return err
}
@@ -79,14 +77,14 @@ func (h *HTTPServers) Stop() error {
return nil
}
-// Start starts the HTTPServers's HTTP server. // TODO I don't like the way this is written
+// Start starts the serverMap's HTTP server. // TODO I don't like the way this is written
func (h *HTTPServer) Start() error {
go h.Server.Serve(h.Listener)
log.Info("HTTP endpoint successfully opened", "url", fmt.Sprintf("http://%v/", h.Listener.Addr()))
return nil
}
-// Stop shuts down the HTTPServers's HTTP server. // TODO I don't like the way this is written
+// Stop shuts down the serverMap's HTTP server. // TODO I don't like the way this is written
func (h *HTTPServer) Stop() error {
if h.Server != nil {
url := fmt.Sprintf("http://%v/", h.Listener.Addr())
@@ -102,12 +100,12 @@ func (h *HTTPServer) Stop() error {
return nil
}
-// SetHandler assigns the given handler to the HTTPServers.
+// SetHandler assigns the given handler to the serverMap.
func (h *HTTPServer) SetHandler(handler http.Handler) {
h.handler = handler
}
-// SetEndpoints assigns the given endpoint to the HTTPServers.
+// SetEndpoints assigns the given endpoint to the serverMap.
func (h *HTTPServer) SetEndpoint(endpoint string) {
h.endpoint = endpoint
}
@@ -224,6 +222,7 @@ func newGzipHandler(next http.Handler) http.Handler {
// NewWebsocketUpgradeHandler returns a websocket handler that serves an incoming request only if it contains an upgrade
// request to the websocket protocol. If not, serves the the request with the http handler.
func (hs *HTTPServer) NewWebsocketUpgradeHandler(h http.Handler, ws http.Handler) http.Handler {
+ // TODO make sure you protect the pointer
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if hs.WSAllowed && isWebsocket(r) {
ws.ServeHTTP(w, r)
diff --git a/node/rpcstack_test.go b/node/rpcstack_test.go
index dc75afa93438..799b138a6917 100644
--- a/node/rpcstack_test.go
+++ b/node/rpcstack_test.go
@@ -40,7 +40,7 @@ func TestNewWebsocketUpgradeHandler_websocket(t *testing.T) {
assert.Equal(t, "websocket", response.Header.Get("Upgrade"))
}
-// Tests that a ws handler can be added to and enabled on an existing HTTPServers
+// Tests that a ws handler can be added to and enabled on an existing HTTPServer
func TestWSAllowed(t *testing.T) {
stack, err := New(&Config{
HTTPHost: DefaultHTTPHost,
diff --git a/node/service.go b/node/service.go
deleted file mode 100644
index e7746e92262c..000000000000
--- a/node/service.go
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright 2015 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package node
-
-import (
- "path/filepath"
- "reflect"
-
- "github.com/ethereum/go-ethereum/accounts"
- "github.com/ethereum/go-ethereum/core/rawdb"
- "github.com/ethereum/go-ethereum/ethdb"
- "github.com/ethereum/go-ethereum/event"
-)
-
-// ServiceContext is a collection of service independent options inherited from
-// the protocol stack, that is passed to all constructors to be optionally used;
-// as well as utility methods to operate on the service environment.
-type ServiceContext struct {
- Config Config
- Lifecycles map[reflect.Type]Lifecycle // TODO should this be in the service context or should it be on the node itself .. ?
- EventMux *event.TypeMux // Event multiplexer used for decoupled notifications
- AccountManager *accounts.Manager // Account manager created by the node.
-}
-
-// OpenDatabase opens an existing database with the given name (or creates one
-// if no previous can be found) from within the node's data directory. If the
-// node is an ephemeral one, a memory database is returned.
-func (ctx *ServiceContext) OpenDatabase(name string, cache int, handles int, namespace string) (ethdb.Database, error) {
- if ctx.Config.DataDir == "" {
- return rawdb.NewMemoryDatabase(), nil
- }
- return rawdb.NewLevelDBDatabase(ctx.Config.ResolvePath(name), cache, handles, namespace)
-}
-
-// OpenDatabaseWithFreezer opens an existing database with the given name (or
-// creates one if no previous can be found) from within the node's data directory,
-// also attaching a chain freezer to it that moves ancient chain data from the
-// database to immutable append-only files. If the node is an ephemeral one, a
-// memory database is returned.
-func (ctx *ServiceContext) OpenDatabaseWithFreezer(name string, cache int, handles int, freezer string, namespace string) (ethdb.Database, error) {
- if ctx.Config.DataDir == "" {
- return rawdb.NewMemoryDatabase(), nil
- }
- root := ctx.Config.ResolvePath(name)
-
- switch {
- case freezer == "":
- freezer = filepath.Join(root, "ancient")
- case !filepath.IsAbs(freezer):
- freezer = ctx.Config.ResolvePath(freezer)
- }
- return rawdb.NewLevelDBDatabaseWithFreezer(root, cache, handles, freezer, namespace)
-}
-
-// ResolvePath resolves a user path into the data directory if that was relative
-// and if the user actually uses persistent storage. It will return an empty string
-// for emphemeral storage and the user's own input for absolute paths.
-func (ctx *ServiceContext) ResolvePath(path string) string {
- return ctx.Config.ResolvePath(path)
-}
-
-// Lifecycle retrieves a currently running Lifecycle registered of a specific type.
-func (ctx *ServiceContext) Lifecycle(lifecycle interface{}) error {
- element := reflect.ValueOf(lifecycle).Elem()
- if running, ok := ctx.Lifecycles[element.Type()]; ok {
- element.Set(reflect.ValueOf(running))
- return nil
- }
- return ErrServiceUnknown
-}
-
-// ExtRPCEnabled returns the indicator whether node enables the external
-// RPC(http, ws or graphql).
-func (ctx *ServiceContext) ExtRPCEnabled() bool {
- return ctx.Config.ExtRPCEnabled()
-}
-
-// Lifecycle encompasses the behavior of services that can be started and stopped
-// on the node. Lifecycle management is delegated to the node, but it is the
-// responsibility of the service-specific package to configure and register the
-// service on the node using the `RegisterLifecycle` method.
-type Lifecycle interface {
- // Start is called after all services have been constructed and the networking
- // layer was also initialized to spawn any goroutines required by the service.
- Start() error
-
- // Stop terminates all goroutines belonging to the service, blocking until they
- // are all terminated.
- Stop() error
-}
diff --git a/node/service_test.go b/node/service_test.go
deleted file mode 100644
index 80f40aeeb68b..000000000000
--- a/node/service_test.go
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2015 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package node
-
-import (
- "io/ioutil"
- "os"
- "path/filepath"
- "testing"
-)
-
-// Tests that databases are correctly created persistent or ephemeral based on
-// the configured service context.
-func TestContextDatabases(t *testing.T) {
- // Create a temporary folder and ensure no database is contained within
- dir, err := ioutil.TempDir("", "")
- if err != nil {
- t.Fatalf("failed to create temporary data directory: %v", err)
- }
- defer os.RemoveAll(dir)
-
- if _, err := os.Stat(filepath.Join(dir, "database")); err == nil {
- t.Fatalf("non-created database already exists")
- }
- // Request the opening/creation of a database and ensure it persists to disk
- ctx := &ServiceContext{Config: Config{Name: "unit-test", DataDir: dir}}
- db, err := ctx.OpenDatabase("persistent", 0, 0, "")
- if err != nil {
- t.Fatalf("failed to open persistent database: %v", err)
- }
- db.Close()
-
- if _, err := os.Stat(filepath.Join(dir, "unit-test", "persistent")); err != nil {
- t.Fatalf("persistent database doesn't exists: %v", err)
- }
- // Request th opening/creation of an ephemeral database and ensure it's not persisted
- ctx = &ServiceContext{Config: Config{DataDir: ""}}
- db, err = ctx.OpenDatabase("ephemeral", 0, 0, "")
- if err != nil {
- t.Fatalf("failed to open ephemeral database: %v", err)
- }
- db.Close()
-
- if _, err := os.Stat(filepath.Join(dir, "ephemeral")); err == nil {
- t.Fatalf("ephemeral database exists")
- }
-}
-
-// Tests that already constructed Lifecycles can be retrieved by later ones.
-func TestContextLifecycles(t *testing.T) {
- stack, err := New(testNodeConfig())
- if err != nil {
- t.Fatalf("failed to create protocol stack: %v", err)
- }
- defer stack.Close()
- // Define a verifier that ensures a NoopA is before it and NoopB after
-
- noop := NewNoop()
- stack.RegisterLifecycle(noop)
-
- is, err := NewInstrumentedService()
- if err != nil {
- t.Fatalf("could not create instrumented service %v", err)
-
- }
- is.startHook = func() {
- if err := stack.ServiceContext.Lifecycle(&noop); err != nil {
- t.Errorf("former service not found: %v", err)
- }
- }
- stack.RegisterLifecycle(is)
-
- // Start the protocol stack and ensure services are constructed in order
- if err := stack.Start(); err != nil {
- t.Fatalf("failed to start stack: %v", err)
- }
-
- defer stack.Stop()
-}
diff --git a/p2p/simulations/adapters/exec.go b/p2p/simulations/adapters/exec.go
index 2a6d3aeaaa7e..1f7a21470db0 100644
--- a/p2p/simulations/adapters/exec.go
+++ b/p2p/simulations/adapters/exec.go
@@ -443,9 +443,8 @@ func startExecNodeStack() (*node.Node, error) {
return nil, fmt.Errorf("unknown node service %q", err)
}
ctx := &ServiceContext{
- RPCDialer: &wsRPCDialer{addrs: conf.PeerAddrs},
- NodeContext: stack.ServiceContext,
- Config: conf.Node,
+ RPCDialer: &wsRPCDialer{addrs: conf.PeerAddrs},
+ Config: conf.Node,
}
if conf.Snapshots != nil {
ctx.Snapshot = conf.Snapshots[name]
diff --git a/p2p/simulations/adapters/inproc.go b/p2p/simulations/adapters/inproc.go
index 48c5bd9753f2..c786b9f9ddc1 100644
--- a/p2p/simulations/adapters/inproc.go
+++ b/p2p/simulations/adapters/inproc.go
@@ -250,9 +250,8 @@ func (sn *SimNode) Start(snapshots map[string][]byte) error {
sn.registerOnce.Do(func() {
for _, name := range sn.config.Lifecycles {
ctx := &ServiceContext{
- RPCDialer: sn.adapter,
- NodeContext: sn.node.ServiceContext,
- Config: sn.config,
+ RPCDialer: sn.adapter,
+ Config: sn.config,
}
if snapshots != nil {
ctx.Snapshot = snapshots[name]
diff --git a/p2p/simulations/adapters/types.go b/p2p/simulations/adapters/types.go
index 1ca60f4b9b58..716cde6a6c7d 100644
--- a/p2p/simulations/adapters/types.go
+++ b/p2p/simulations/adapters/types.go
@@ -233,9 +233,8 @@ func assignTCPPort() (uint16, error) {
type ServiceContext struct {
RPCDialer
- NodeContext *node.ServiceContext
- Config *NodeConfig
- Snapshot []byte
+ Config *NodeConfig
+ Snapshot []byte
}
// RPCDialer is used when initialising services which need to connect to
diff --git a/whisper/mailserver/server_test.go b/whisper/mailserver/server_test.go
index 959a1e32f629..069ec97d09b3 100644
--- a/whisper/mailserver/server_test.go
+++ b/whisper/mailserver/server_test.go
@@ -91,10 +91,10 @@ func TestMailServer(t *testing.T) {
var server WMailServer
- stack := newNode(t)
+ stack, w := newNode(t)
defer stack.Close()
+ shh = w
- shh = getWhisperFromNode(stack, t)
shh.RegisterServer(&server)
err = server.Init(shh, dir, password, powRequirement)
@@ -218,12 +218,12 @@ func createRequest(t *testing.T, p *ServerTestParams) *whisper.Envelope {
// newNode creates a new node using a default config and
// creates and registers a new Whisper service on it.
-func newNode(t *testing.T) *node.Node {
+func newNode(t *testing.T) (*node.Node, *whisper.Whisper) {
stack, err := node.New(&node.DefaultConfig)
if err != nil {
t.Fatalf("could not create new node: %v", err)
}
- err = whisper.New(stack, &whisper.DefaultConfig)
+ w, err := whisper.New(stack, &whisper.DefaultConfig)
if err != nil {
t.Fatalf("could not create new whisper service: %v", err)
}
@@ -231,15 +231,5 @@ func newNode(t *testing.T) *node.Node {
if err != nil {
t.Fatalf("could not start node: %v", err)
}
- return stack
-}
-
-// getWhisperFromNode retrieves the Whisper service from the running node.
-func getWhisperFromNode(stack *node.Node, t *testing.T) *whisper.Whisper {
- var w *whisper.Whisper
- err := stack.Lifecycle(&w)
- if err != nil {
- t.Fatalf("could not get whisper service from node: %v", err)
- }
- return w
+ return stack, w
}
diff --git a/whisper/whisperv6/api_test.go b/whisper/whisperv6/api_test.go
index 9aceaf456d6b..759ef221ed8d 100644
--- a/whisper/whisperv6/api_test.go
+++ b/whisper/whisperv6/api_test.go
@@ -23,11 +23,9 @@ import (
)
func TestMultipleTopicCopyInNewMessageFilter(t *testing.T) {
- stack := newNode(t)
+ stack, w := newNodeWithWhisper(t)
defer stack.Close()
- w := getWhisperFromNode(stack, t)
-
keyID, err := w.GenerateSymKey()
if err != nil {
t.Fatalf("Error generating symmetric key: %v", err)
diff --git a/whisper/whisperv6/filter_test.go b/whisper/whisperv6/filter_test.go
index 49c2b7688361..c95e506972dd 100644
--- a/whisper/whisperv6/filter_test.go
+++ b/whisper/whisperv6/filter_test.go
@@ -93,11 +93,9 @@ func TestInstallFilters(t *testing.T) {
const SizeTestFilters = 256
- stack := newNode(t)
+ stack, w := newNodeWithWhisper(t)
defer stack.Close()
- w := getWhisperFromNode(stack, t)
-
filters := NewFilters(w)
tst := generateTestCases(t, SizeTestFilters)
@@ -135,11 +133,9 @@ func TestInstallFilters(t *testing.T) {
func TestInstallSymKeyGeneratesHash(t *testing.T) {
InitSingleTest()
- stack := newNode(t)
+ stack, w := newNodeWithWhisper(t)
defer stack.Close()
- w := getWhisperFromNode(stack, t)
-
filters := NewFilters(w)
filter, _ := generateFilter(t, true)
@@ -166,11 +162,9 @@ func TestInstallSymKeyGeneratesHash(t *testing.T) {
func TestInstallIdenticalFilters(t *testing.T) {
InitSingleTest()
- stack := newNode(t)
+ stack, w := newNodeWithWhisper(t)
defer stack.Close()
- w := getWhisperFromNode(stack, t)
-
filters := NewFilters(w)
filter1, _ := generateFilter(t, true)
@@ -240,11 +234,9 @@ func TestInstallIdenticalFilters(t *testing.T) {
func TestInstallFilterWithSymAndAsymKeys(t *testing.T) {
InitSingleTest()
- stack := newNode(t)
+ stack, w := newNodeWithWhisper(t)
defer stack.Close()
- w := getWhisperFromNode(stack, t)
-
filters := NewFilters(w)
filter1, _ := generateFilter(t, true)
@@ -658,11 +650,9 @@ func TestWatchers(t *testing.T) {
var x, firstID string
var err error
- stack := newNode(t)
+ stack, w := newNodeWithWhisper(t)
defer stack.Close()
- w := getWhisperFromNode(stack, t)
-
filters := NewFilters(w)
tst := generateTestCases(t, NumFilters)
for i = 0; i < NumFilters; i++ {
diff --git a/whisper/whisperv6/whisper.go b/whisper/whisperv6/whisper.go
index 5799919db967..ac610367050c 100644
--- a/whisper/whisperv6/whisper.go
+++ b/whisper/whisperv6/whisper.go
@@ -94,7 +94,7 @@ type Whisper struct {
}
// New creates a Whisper client ready to communicate through the Ethereum P2P network.
-func New(stack *node.Node, cfg *Config) error {
+func New(stack *node.Node, cfg *Config) (*Whisper, error) {
if cfg == nil {
cfg = &DefaultConfig
}
@@ -136,7 +136,7 @@ func New(stack *node.Node, cfg *Config) error {
stack.RegisterAPIs(whisper.APIs())
stack.RegisterProtocols(whisper.Protocols())
stack.RegisterLifecycle(whisper)
- return nil
+ return whisper, nil
}
// MinPow returns the PoW value required by this node.
diff --git a/whisper/whisperv6/whisper_test.go b/whisper/whisperv6/whisper_test.go
index a8056d6776e1..7fb8f7c1cd85 100644
--- a/whisper/whisperv6/whisper_test.go
+++ b/whisper/whisperv6/whisper_test.go
@@ -30,10 +30,9 @@ import (
)
func TestWhisperBasic(t *testing.T) {
- stack := newNode(t)
+ stack, w := newNodeWithWhisper(t)
defer stack.Close()
- // get whisper service from node
- w := getWhisperFromNode(stack, t)
+
shh := w.Protocols()[0]
if shh.Name != ProtocolName {
t.Fatalf("failed Protocol Name: %v.", shh.Name)
@@ -114,11 +113,10 @@ func TestWhisperBasic(t *testing.T) {
}
func TestWhisperAsymmetricKeyImport(t *testing.T) {
- stack := newNode(t)
+ stack, w := newNodeWithWhisper(t)
defer stack.Close()
var privateKeys []*ecdsa.PrivateKey
- w := getWhisperFromNode(stack, t)
for i := 0; i < 50; i++ {
id, err := w.NewKeyPair()
if err != nil {
@@ -145,10 +143,9 @@ func TestWhisperAsymmetricKeyImport(t *testing.T) {
}
func TestWhisperIdentityManagement(t *testing.T) {
- stack := newNode(t)
+ stack, w := newNodeWithWhisper(t)
defer stack.Close()
- w := getWhisperFromNode(stack, t)
id1, err := w.NewKeyPair()
if err != nil {
t.Fatalf("failed to generate new key pair: %s.", err)
@@ -272,11 +269,9 @@ func TestWhisperSymKeyManagement(t *testing.T) {
id2 = string("arbitrary-string-2")
)
- stack := newNode(t)
+ stack, w := newNodeWithWhisper(t)
defer stack.Close()
- w := getWhisperFromNode(stack, t)
-
id1, err := w.GenerateSymKey()
if err != nil {
t.Fatalf("failed GenerateSymKey with seed %d: %s.", seed, err)
@@ -461,11 +456,9 @@ func TestWhisperSymKeyManagement(t *testing.T) {
func TestExpiry(t *testing.T) {
InitSingleTest()
- stack := newNode(t)
+ stack, w := newNodeWithWhisper(t)
defer stack.Close()
- w := getWhisperFromNode(stack, t)
-
w.SetMinimumPowTest(0.0000001)
defer w.SetMinimumPowTest(DefaultMinimumPoW)
w.Start()
@@ -530,11 +523,9 @@ func TestExpiry(t *testing.T) {
func TestCustomization(t *testing.T) {
InitSingleTest()
- stack := newNode(t)
+ stack, w := newNodeWithWhisper(t)
defer stack.Close()
- w := getWhisperFromNode(stack, t)
-
defer w.SetMinimumPowTest(DefaultMinimumPoW)
defer w.SetMaxMessageSize(DefaultMaxMessageSize)
w.Start()
@@ -626,11 +617,9 @@ func TestCustomization(t *testing.T) {
func TestSymmetricSendCycle(t *testing.T) {
InitSingleTest()
- stack := newNode(t)
+ stack, w := newNodeWithWhisper(t)
defer stack.Close()
- w := getWhisperFromNode(stack, t)
-
defer w.SetMinimumPowTest(DefaultMinimumPoW)
defer w.SetMaxMessageSize(DefaultMaxMessageSize)
w.Start()
@@ -720,11 +709,9 @@ func TestSymmetricSendCycle(t *testing.T) {
func TestSymmetricSendWithoutAKey(t *testing.T) {
InitSingleTest()
- stack := newNode(t)
+ stack, w := newNodeWithWhisper(t)
defer stack.Close()
- w := getWhisperFromNode(stack, t)
-
defer w.SetMinimumPowTest(DefaultMinimumPoW)
defer w.SetMaxMessageSize(DefaultMaxMessageSize)
w.Start()
@@ -793,11 +780,9 @@ func TestSymmetricSendWithoutAKey(t *testing.T) {
func TestSymmetricSendKeyMismatch(t *testing.T) {
InitSingleTest()
- stack := newNode(t)
+ stack, w := newNodeWithWhisper(t)
defer stack.Close()
- w := getWhisperFromNode(stack, t)
-
defer w.SetMinimumPowTest(DefaultMinimumPoW)
defer w.SetMaxMessageSize(DefaultMaxMessageSize)
w.Start()
@@ -907,11 +892,9 @@ func TestBloom(t *testing.T) {
t.Fatal("bloomFilterMatch false negative")
}
- stack := newNode(t)
+ stack, w := newNodeWithWhisper(t)
defer stack.Close()
- w := getWhisperFromNode(stack, t)
-
f := w.BloomFilter()
if f != nil {
t.Fatal("wrong bloom on creation")
@@ -926,14 +909,14 @@ func TestBloom(t *testing.T) {
}
}
-// newNode creates a new node using a default config and
+// newNodeWithWhisper creates a new node using a default config and
// creates and registers a new Whisper service on it.
-func newNode(t *testing.T) *node.Node {
+func newNodeWithWhisper(t *testing.T) (*node.Node, *Whisper) {
stack, err := node.New(&node.DefaultConfig)
if err != nil {
t.Fatalf("could not create new node: %v", err)
}
- err = New(stack, &DefaultConfig)
+ w, err := New(stack, &DefaultConfig)
if err != nil {
t.Fatalf("could not create new whisper service: %v", err)
}
@@ -941,15 +924,5 @@ func newNode(t *testing.T) *node.Node {
if err != nil {
t.Fatalf("could not start node: %v", err)
}
- return stack
-}
-
-// getWhisperFromNode retrieves the Whisper service from the running node.
-func getWhisperFromNode(stack *node.Node, t *testing.T) *Whisper {
- var w *Whisper
- err := stack.Lifecycle(&w)
- if err != nil {
- t.Fatalf("could not get whisper service from node: %v", err)
- }
- return w
+ return stack, w
}
From d49a5be06105b2ee819fbd117687919af7aa04c5 Mon Sep 17 00:00:00 2001
From: rene <41963722+renaynay@users.noreply.github.com>
Date: Tue, 30 Jun 2020 14:57:32 +0200
Subject: [PATCH 071/160] attempt at fixing http test (#24)
---
go.sum | 14 --------------
graphql/graphql_test.go | 14 ++++++--------
2 files changed, 6 insertions(+), 22 deletions(-)
diff --git a/go.sum b/go.sum
index 2bb6d1e16912..acb104673937 100644
--- a/go.sum
+++ b/go.sum
@@ -193,44 +193,30 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX
github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208 h1:1cngl9mPEoITZG8s8cVcUy5CeIBYhEESkOB7m6Gmkrk=
github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
-golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
-gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
-gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6 h1:a6cXbcDDUkSBlpnkWV1bJ+vv3mOgQEltEJ2rPxroVu0=
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns=
-gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
-gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0=
gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go
index 3b18cb5e670a..f89ef8f04f88 100644
--- a/graphql/graphql_test.go
+++ b/graphql/graphql_test.go
@@ -30,8 +30,6 @@ import (
"github.com/stretchr/testify/assert"
)
-var testEndpoint = "127.0.0.1:9393"
-
func TestBuildSchema(t *testing.T) {
// Make sure the schema can be parsed and matched up to the object model.
if _, err := newHandler(nil); err != nil {
@@ -48,7 +46,7 @@ func TestGQLAllowed(t *testing.T) {
t.Fatalf("could not start node: %v", err)
}
// check that server was created
- server := stack.ExistingHTTPServer(testEndpoint)
+ server := stack.ExistingHTTPServer("127.0.0.1:9393")
if server == nil {
t.Errorf("server was not created on the given endpoint")
}
@@ -64,7 +62,7 @@ func TestMultiplexedServer(t *testing.T) {
if err := stack.Start(); err != nil {
t.Error("could not start http service on node ", err)
}
- server := stack.ExistingHTTPServer(testEndpoint)
+ server := stack.ExistingHTTPServer("127.0.0.1:9393")
if server == nil {
t.Fatalf("server was not configured on the given endpoint")
}
@@ -83,7 +81,7 @@ func TestGraphQLHTTPOnSamePort_GQLRequest_Successful(t *testing.T) {
}
// create http request
body := strings.NewReader("{\"query\": \"{block{number}}\",\"variables\": null}")
- gqlReq, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s/graphql", testEndpoint), body)
+ gqlReq, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s/graphql", "127.0.0.1:9393"), body)
if err != nil {
t.Error("could not issue new http request ", err)
}
@@ -107,14 +105,14 @@ func TestGraphQLHTTPOnSamePort_GQLRequest_Unsuccessful(t *testing.T) {
t.Fatalf("could not start node: %v", err)
}
// make sure GQL is not enabled
- server := stack.ExistingHTTPServer(testEndpoint)
+ server := stack.ExistingHTTPServer("127.0.0.1:9797")
if server == nil {
t.Fatalf("server was not created on the given endpoint")
}
assert.False(t, server.GQLAllowed)
// create http request
body := strings.NewReader("{\"query\": \"{block{number}}\",\"variables\": null}")
- gqlReq, err := http.NewRequest(http.MethodPost, fmt.Sprintf("http://%s/graphql", testEndpoint), body)
+ gqlReq, err := http.NewRequest(http.MethodPost, fmt.Sprintf("http://%s/graphql", "127.0.0.1:9797"), body)
if err != nil {
t.Error("could not issue new http request ", err)
}
@@ -174,7 +172,7 @@ func createNode(t *testing.T, gqlEnabled bool) *node.Node {
return stack
}
- createGQLService(t, stack, testEndpoint)
+ createGQLService(t, stack, "127.0.0.1:9393")
return stack
}
From 52896aeeb7d2bea26f8eec35a36f41dca6c558e1 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Tue, 30 Jun 2020 21:47:40 +0200
Subject: [PATCH 072/160] fixed broken http test, waiting whether it passes on
all builds
---
graphql/graphql_test.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go
index f89ef8f04f88..c8c1d6e6be90 100644
--- a/graphql/graphql_test.go
+++ b/graphql/graphql_test.go
@@ -105,14 +105,14 @@ func TestGraphQLHTTPOnSamePort_GQLRequest_Unsuccessful(t *testing.T) {
t.Fatalf("could not start node: %v", err)
}
// make sure GQL is not enabled
- server := stack.ExistingHTTPServer("127.0.0.1:9797")
+ server := stack.ExistingHTTPServer("127.0.0.1:9393")
if server == nil {
t.Fatalf("server was not created on the given endpoint")
}
assert.False(t, server.GQLAllowed)
// create http request
body := strings.NewReader("{\"query\": \"{block{number}}\",\"variables\": null}")
- gqlReq, err := http.NewRequest(http.MethodPost, fmt.Sprintf("http://%s/graphql", "127.0.0.1:9797"), body)
+ gqlReq, err := http.NewRequest(http.MethodPost, fmt.Sprintf("http://%s/graphql", "127.0.0.1:9393"), body)
if err != nil {
t.Error("could not issue new http request ", err)
}
From dce47808d4dfdc745030d2202bcf1f031da51138 Mon Sep 17 00:00:00 2001
From: rene <41963722+renaynay@users.noreply.github.com>
Date: Thu, 2 Jul 2020 16:56:40 +0200
Subject: [PATCH 073/160] use int32 instead of bool when checking whether to
handle requests (#25)
---
graphql/graphql_test.go | 65 -----------------------------------------
graphql/service.go | 8 ++---
node/api.go | 19 ++++++------
node/node.go | 35 +++++++++-------------
node/node_test.go | 6 ++--
node/rpcstack.go | 8 ++---
node/rpcstack_test.go | 7 +++--
7 files changed, 40 insertions(+), 108 deletions(-)
diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go
index c8c1d6e6be90..08c1e4c8b576 100644
--- a/graphql/graphql_test.go
+++ b/graphql/graphql_test.go
@@ -37,40 +37,6 @@ func TestBuildSchema(t *testing.T) {
}
}
-// Tests that a graphql handler can be added to an existing HTTPServer
-func TestGQLAllowed(t *testing.T) {
- stack := createNode(t, true)
- defer stack.Close()
- // start node
- if err := stack.Start(); err != nil {
- t.Fatalf("could not start node: %v", err)
- }
- // check that server was created
- server := stack.ExistingHTTPServer("127.0.0.1:9393")
- if server == nil {
- t.Errorf("server was not created on the given endpoint")
- }
- // assert that server allows GQL requests
- assert.True(t, server.GQLAllowed)
-}
-
-// Tests to make sure an HTTPServer is created that handles for http, ws, and graphQL
-func TestMultiplexedServer(t *testing.T) {
- stack := createNode(t, true)
- defer stack.Close()
- // start the node
- if err := stack.Start(); err != nil {
- t.Error("could not start http service on node ", err)
- }
- server := stack.ExistingHTTPServer("127.0.0.1:9393")
- if server == nil {
- t.Fatalf("server was not configured on the given endpoint")
- }
- assert.True(t, server.RPCAllowed)
- assert.True(t, server.WSAllowed)
- assert.True(t, server.GQLAllowed)
-}
-
// Tests that a graphQL request is successfully handled when graphql is enabled on the specified endpoint
func TestGraphQLHTTPOnSamePort_GQLRequest_Successful(t *testing.T) {
stack := createNode(t, true)
@@ -109,7 +75,6 @@ func TestGraphQLHTTPOnSamePort_GQLRequest_Unsuccessful(t *testing.T) {
if server == nil {
t.Fatalf("server was not created on the given endpoint")
}
- assert.False(t, server.GQLAllowed)
// create http request
body := strings.NewReader("{\"query\": \"{block{number}}\",\"variables\": null}")
gqlReq, err := http.NewRequest(http.MethodPost, fmt.Sprintf("http://%s/graphql", "127.0.0.1:9393"), body)
@@ -128,36 +93,6 @@ func TestGraphQLHTTPOnSamePort_GQLRequest_Unsuccessful(t *testing.T) {
assert.Equal(t, string(bodyBytes), expected)
}
-// Tests that graphql can be successfully enabled on a separate port than rpc and ws.
-func TestGraphqlOnSeparatePort(t *testing.T) {
- stack := createNode(t, false)
- defer stack.Close()
-
- separateTestEndpoint := "127.0.0.1:7474"
-
- createGQLService(t, stack, separateTestEndpoint)
- // start node
- if err := stack.Start(); err != nil {
- t.Fatalf("could not start node: %v", err)
- }
- // create http request
- body := strings.NewReader("{\"query\": \"{block{number}}\",\"variables\": null}")
- gqlReq, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s/graphql", separateTestEndpoint), body)
- if err != nil {
- t.Error("could not issue new http request ", err)
- }
- gqlReq.Header.Set("Content-Type", "application/json")
- // read from response
- resp := doHTTPRequest(t, gqlReq)
- bodyBytes, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- t.Fatalf("could not read from response body: %v", err)
- }
- expected := "{\"data\":{\"block\":{\"number\":\"0x0\"}}}"
- assert.Equal(t, expected, string(bodyBytes))
-
-}
-
func createNode(t *testing.T, gqlEnabled bool) *node.Node {
stack, err := node.New(&node.Config{
HTTPHost: "127.0.0.1",
diff --git a/graphql/service.go b/graphql/service.go
index f93f12a545e3..5c3d872842d9 100644
--- a/graphql/service.go
+++ b/graphql/service.go
@@ -17,13 +17,12 @@
package graphql
import (
- "net/http"
-
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/rpc"
"github.com/graph-gophers/graphql-go"
"github.com/graph-gophers/graphql-go/relay"
+ "net/http"
)
// New constructs a new GraphQL service instance.
@@ -34,7 +33,7 @@ func New(stack *node.Node, backend ethapi.Backend, endpoint string, cors, vhosts
// check if http server with given endpoint exists and enable graphQL on it
server := stack.ExistingHTTPServer(endpoint)
if server != nil {
- server.GQLAllowed = true
+ // set vhosts, cors and timeouts
server.Vhosts = append(server.Vhosts, vhosts...)
server.CorsAllowedOrigins = append(server.CorsAllowedOrigins, cors...)
server.Timeouts = timeouts
@@ -54,10 +53,11 @@ func New(stack *node.Node, backend ethapi.Backend, endpoint string, cors, vhosts
}
// create the http server
gqlServer := &node.HTTPServer{
+ RPCAllowed: 0,
+ WSAllowed: 0,
Vhosts: vhosts,
CorsAllowedOrigins: cors,
Timeouts: timeouts,
- GQLAllowed: true,
GQLHandler: handler,
Srv: rpc.NewServer(),
}
diff --git a/node/api.go b/node/api.go
index d6f1901907aa..e359357bd016 100644
--- a/node/api.go
+++ b/node/api.go
@@ -20,6 +20,7 @@ import (
"context"
"fmt"
"strings"
+ "sync/atomic"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
@@ -160,7 +161,7 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
endpoint := fmt.Sprintf("%s:%d", *host, *port)
// check if HTTP server already exists
if server, exists := api.node.httpServers[endpoint]; exists {
- if server.RPCAllowed {
+ if atomic.LoadInt32(&server.RPCAllowed) == 1 {
return false, fmt.Errorf("HTTP RPC already running on %v", server.Listener.Addr())
}
}
@@ -221,7 +222,7 @@ func (api *PrivateAdminAPI) StopRPC() (bool, error) {
defer api.node.lock.Unlock()
for _, httpServer := range api.node.httpServers {
- if httpServer.RPCAllowed {
+ if atomic.LoadInt32(&httpServer.RPCAllowed) == 1 {
api.node.stopServer(httpServer)
return true, nil
}
@@ -236,7 +237,7 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
defer api.node.lock.Unlock()
// check if an existing WS server already exists
for _, server := range api.node.httpServers {
- if server.WSAllowed {
+ if atomic.LoadInt32(&server.WSAllowed) == 1 {
return false, fmt.Errorf("WebSocket RPC already running on %v", server.Listener.Addr())
}
}
@@ -255,7 +256,7 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
// check if there is an existing server on the specified port, and if there is, enable ws on it
if server, exists := api.node.httpServers[endpoint]; exists {
// else configure ws on the existing server
- server.WSAllowed = true
+ atomic.AddInt32(&server.WSAllowed, 1)
// configure origins
origins := api.node.config.WSOrigins
if allowedOrigins != nil {
@@ -280,7 +281,7 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
// check if an HTTP server exists on the given endpoint, and if so, enable websocket on that HTTP server
existingServer := api.node.ExistingHTTPServer(endpoint)
if existingServer != nil {
- existingServer.WSAllowed = true
+ atomic.AddInt32(&existingServer.WSAllowed, 1)
existingServer.WsOrigins = origins
}
@@ -300,7 +301,7 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
port: *port,
Whitelist: modules,
WsOrigins: origins,
- WSAllowed: true,
+ WSAllowed: 1,
}
// create handler
wsServer.handler = wsServer.Srv.WebsocketHandler(wsServer.WsOrigins)
@@ -323,10 +324,10 @@ func (api *PrivateAdminAPI) StopWS() (bool, error) {
defer api.node.lock.Unlock()
for _, httpServer := range api.node.httpServers {
- if httpServer.WSAllowed {
- httpServer.WSAllowed = false
+ if atomic.LoadInt32(&httpServer.WSAllowed) == 1 {
+ atomic.AddInt32(&httpServer.WSAllowed, int32(-1))
// if RPC is not enabled on the WS http server, shut it down
- if !httpServer.RPCAllowed && !httpServer.GQLAllowed { // TODO is the gql check necessary? Can GQL ever be on a WS server that doesn't also support regular http?
+ if atomic.LoadInt32(&httpServer.RPCAllowed) == 0 {
api.node.stopServer(httpServer)
return true, nil
}
diff --git a/node/node.go b/node/node.go
index d347c7fbaa69..196d83f7d953 100644
--- a/node/node.go
+++ b/node/node.go
@@ -29,6 +29,7 @@ import (
"runtime"
"strings"
"sync"
+ "sync/atomic"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/core/rawdb"
@@ -142,11 +143,11 @@ func New(conf *Config) (*Node, error) {
endpoint: conf.HTTPEndpoint(),
host: conf.HTTPHost,
port: conf.HTTPPort,
- RPCAllowed: true,
+ RPCAllowed: 1,
}
// check if ws is enabled and if ws port is the same as http port
if conf.WSHost != "" && conf.WSPort == conf.HTTPPort {
- httpServ.WSAllowed = true
+ httpServ.WSAllowed = 1
httpServ.WsOrigins = conf.WSOrigins
httpServ.Whitelist = append(httpServ.Whitelist, conf.WSModules...)
@@ -157,13 +158,13 @@ func New(conf *Config) (*Node, error) {
}
if conf.WSHost != "" {
node.httpServers[conf.WSEndpoint()] = &HTTPServer{
- WsOrigins: conf.WSOrigins,
- Whitelist: conf.WSModules,
- Srv: rpc.NewServer(),
- endpoint: conf.WSEndpoint(),
- host: conf.WSHost,
- port: conf.WSPort,
- WSAllowed: true,
+ WsOrigins: conf.WSOrigins,
+ Whitelist: conf.WSModules,
+ Srv: rpc.NewServer(),
+ endpoint: conf.WSEndpoint(),
+ host: conf.WSHost,
+ port: conf.WSPort,
+ WSAllowed: 1,
}
}
@@ -352,29 +353,21 @@ func (n *Node) configureRPC() error {
for _, server := range n.httpServers {
// configure the handlers
- if server.RPCAllowed {
+ if atomic.LoadInt32(&server.RPCAllowed) == 1 {
server.handler = NewHTTPHandlerStack(server.Srv, server.CorsAllowedOrigins, server.Vhosts)
// wrap ws handler just in case ws is enabled through the console after start-up
wsHandler := server.Srv.WebsocketHandler(server.WsOrigins)
server.handler = server.NewWebsocketUpgradeHandler(server.handler, wsHandler)
n.log.Info("HTTP configured on endpoint ", "endpoint", server.endpoint)
- if server.WSAllowed {
+ if atomic.LoadInt32(&server.WSAllowed) == 1 {
n.log.Info("Websocket configured on endpoint ", "endpoint", server.endpoint)
}
}
- if server.WSAllowed && server.handler == nil {
+ if (atomic.LoadInt32(&server.WSAllowed) == 1) && server.handler == nil {
server.handler = server.Srv.WebsocketHandler(server.WsOrigins)
n.log.Info("Websocket configured on endpoint ", "endpoint", server.endpoint)
}
- if server.GQLAllowed {
- if server.handler == nil {
- server.handler = server.GQLHandler
- } else {
- server.handler = NewGQLUpgradeHandler(server.handler, server.GQLHandler)
- }
- n.log.Info("GraphQL configured on endpoint ", "endpoint", server.endpoint)
- }
// create the HTTP server
if err := n.CreateHTTPServer(server, false); err != nil {
return err
@@ -580,7 +573,7 @@ func (n *Node) WSEndpoint() string {
defer n.lock.Unlock()
for _, httpServer := range n.httpServers {
- if httpServer.WSAllowed {
+ if atomic.LoadInt32(&httpServer.WSAllowed) == 1 {
if httpServer.Listener != nil {
return httpServer.Listener.Addr().String()
}
diff --git a/node/node_test.go b/node/node_test.go
index d87a5612a5ce..bb1543650894 100644
--- a/node/node_test.go
+++ b/node/node_test.go
@@ -23,6 +23,7 @@ import (
"net/http"
"os"
"reflect"
+ "sync/atomic"
"testing"
"github.com/ethereum/go-ethereum/crypto"
@@ -423,7 +424,8 @@ func TestHTTPServerCreateAndStop(t *testing.T) {
}
// check to make sure http servers are configured properly
for _, server := range node1.httpServers {
- if !(server.WSAllowed && server.RPCAllowed) {
+
+ if atomic.LoadInt32(&server.WSAllowed) == 0 && atomic.LoadInt32(&server.RPCAllowed) == 0 {
t.Fatalf("node's http server is not configured to handle both rpc and ws")
}
node1.stopServer(server)
@@ -450,7 +452,7 @@ func TestHTTPServerCreateAndStop(t *testing.T) {
}
// check that neither http server has both ws and rpc enabled
for _, server := range node2.httpServers {
- if server.WSAllowed && server.RPCAllowed {
+ if atomic.LoadInt32(&server.WSAllowed) == 1 && atomic.LoadInt32(&server.RPCAllowed) == 1 {
t.Fatalf("both rpc and ws allowed on a single http server")
}
node2.stopServer(server)
diff --git a/node/rpcstack.go b/node/rpcstack.go
index d12089274b8d..32e4cd74d79d 100644
--- a/node/rpcstack.go
+++ b/node/rpcstack.go
@@ -26,6 +26,7 @@ import (
"net/http"
"strings"
"sync"
+ "sync/atomic"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc"
@@ -52,9 +53,8 @@ type HTTPServer struct {
WsOrigins []string
Timeouts rpc.HTTPTimeouts
- RPCAllowed bool
- WSAllowed bool // TODO discuss this later bc possible race condition
- GQLAllowed bool
+ RPCAllowed int32
+ WSAllowed int32
GQLHandler http.Handler
}
@@ -224,7 +224,7 @@ func newGzipHandler(next http.Handler) http.Handler {
func (hs *HTTPServer) NewWebsocketUpgradeHandler(h http.Handler, ws http.Handler) http.Handler {
// TODO make sure you protect the pointer
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- if hs.WSAllowed && isWebsocket(r) {
+ if atomic.LoadInt32(&hs.WSAllowed) == 1 && isWebsocket(r) {
ws.ServeHTTP(w, r)
log.Debug("serving websocket request")
return
diff --git a/node/rpcstack_test.go b/node/rpcstack_test.go
index 799b138a6917..f745e350afe9 100644
--- a/node/rpcstack_test.go
+++ b/node/rpcstack_test.go
@@ -4,6 +4,7 @@ import (
"fmt"
"net/http"
"net/http/httptest"
+ "sync/atomic"
"testing"
"github.com/ethereum/go-ethereum/rpc"
@@ -13,7 +14,7 @@ import (
func TestNewWebsocketUpgradeHandler_websocket(t *testing.T) {
h := &HTTPServer{
Srv: rpc.NewServer(),
- WSAllowed: true,
+ WSAllowed: 1,
}
handler := h.NewWebsocketUpgradeHandler(nil, h.Srv.WebsocketHandler([]string{}))
ts := httptest.NewServer(handler)
@@ -63,6 +64,6 @@ func TestWSAllowed(t *testing.T) {
t.Fatalf("server was not started on the given endpoint: %v", err)
}
// assert that both RPC and WS are allowed on the HTTP Server
- assert.True(t, server.RPCAllowed)
- assert.True(t, server.WSAllowed)
+ assert.Equal(t, atomic.LoadInt32(&server.RPCAllowed), int32(1))
+ assert.Equal(t, atomic.LoadInt32(&server.WSAllowed), int32(1))
}
From 0e7b866b581a8e109bb15d321fff4f86b6e72e4d Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Fri, 3 Jul 2020 16:23:51 +0200
Subject: [PATCH 074/160] make sure to register all APIs when registering
services apis on node
---
eth/backend.go | 6 +++---
les/client.go | 4 ++--
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/eth/backend.go b/eth/backend.go
index b9b356d20bee..82aef22944a2 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -236,6 +236,9 @@ func New(stack *node.Node, config *Config) (*Ethereum, error) {
return nil, err
}
+ // Start the RPC service
+ eth.netRPCService = ethapi.NewPublicNetAPI(eth.p2pServer, eth.NetVersion())
+
// Register the backend on the node
stack.RegisterAPIs(eth.APIs())
stack.RegisterProtocols(eth.Protocols())
@@ -548,9 +551,6 @@ func (s *Ethereum) Start() error {
// Start the bloom bits servicing goroutines
s.startBloomHandlers(params.BloomBitsBlocks)
- // Start the RPC service
- s.netRPCService = ethapi.NewPublicNetAPI(s.p2pServer, s.NetVersion())
-
// Figure out a max peers count based on the server limits
maxPeers := s.p2pServer.MaxPeers
if s.config.LightServ > 0 {
diff --git a/les/client.go b/les/client.go
index 0ae6700d0bb4..07f7acaa3d28 100644
--- a/les/client.go
+++ b/les/client.go
@@ -171,6 +171,8 @@ func New(stack *node.Node, config *eth.Config) (*LightEthereum, error) {
}
leth.ApiBackend.gpo = gasprice.NewOracle(leth.ApiBackend, gpoParams)
+ leth.netRPCService = ethapi.NewPublicNetAPI(leth.p2pServer, leth.config.NetworkId)
+
// Register the backend on the node
stack.RegisterAPIs(leth.APIs())
stack.RegisterProtocols(leth.Protocols())
@@ -299,8 +301,6 @@ func (s *LightEthereum) Start() error {
s.startBloomHandlers(params.BloomBitsBlocksClient)
s.handler.start()
- s.netRPCService = ethapi.NewPublicNetAPI(s.p2pServer, s.config.NetworkId)
-
return nil
}
From a5204a4ea7894d12096ec24f8fa55c3e944a1d89 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Mon, 6 Jul 2020 12:31:23 +0200
Subject: [PATCH 075/160] store int32
---
node/api.go | 11 +++++------
node/node.go | 45 +++++++++++++++++++--------------------------
node/rpcstack.go | 1 -
3 files changed, 24 insertions(+), 33 deletions(-)
diff --git a/node/api.go b/node/api.go
index e359357bd016..17adc19695b6 100644
--- a/node/api.go
+++ b/node/api.go
@@ -147,6 +147,7 @@ func (api *PrivateAdminAPI) PeerEvents(ctx context.Context) (*rpc.Subscription,
func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis *string, vhosts *string) (bool, error) {
api.node.lock.Lock()
defer api.node.lock.Unlock()
+
// set host, port, and endpoint
if host == nil {
h := DefaultHTTPHost
@@ -235,6 +236,7 @@ func (api *PrivateAdminAPI) StopRPC() (bool, error) {
func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *string, apis *string) (bool, error) {
api.node.lock.Lock()
defer api.node.lock.Unlock()
+
// check if an existing WS server already exists
for _, server := range api.node.httpServers {
if atomic.LoadInt32(&server.WSAllowed) == 1 {
@@ -256,7 +258,7 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
// check if there is an existing server on the specified port, and if there is, enable ws on it
if server, exists := api.node.httpServers[endpoint]; exists {
// else configure ws on the existing server
- atomic.AddInt32(&server.WSAllowed, 1)
+ atomic.StoreInt32(&server.WSAllowed, 1)
// configure origins
origins := api.node.config.WSOrigins
if allowedOrigins != nil {
@@ -281,7 +283,7 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
// check if an HTTP server exists on the given endpoint, and if so, enable websocket on that HTTP server
existingServer := api.node.ExistingHTTPServer(endpoint)
if existingServer != nil {
- atomic.AddInt32(&existingServer.WSAllowed, 1)
+ atomic.StoreInt32(&existingServer.WSAllowed, 1)
existingServer.WsOrigins = origins
}
@@ -324,14 +326,11 @@ func (api *PrivateAdminAPI) StopWS() (bool, error) {
defer api.node.lock.Unlock()
for _, httpServer := range api.node.httpServers {
- if atomic.LoadInt32(&httpServer.WSAllowed) == 1 {
- atomic.AddInt32(&httpServer.WSAllowed, int32(-1))
+ if atomic.SwapInt32(&httpServer.WSAllowed, 0) == 1 {
// if RPC is not enabled on the WS http server, shut it down
if atomic.LoadInt32(&httpServer.RPCAllowed) == 0 {
api.node.stopServer(httpServer)
- return true, nil
}
-
return true, nil
}
}
diff --git a/node/node.go b/node/node.go
index 196d83f7d953..f9bc79e5688f 100644
--- a/node/node.go
+++ b/node/node.go
@@ -44,28 +44,21 @@ import (
// Node is a container on which services can be registered.
type Node struct {
- eventmux *event.TypeMux // Event multiplexer used between the services of a stack
- config *Config
- accman *accounts.Manager
-
+ eventmux *event.TypeMux // Event multiplexer used between the services of a stack
+ config *Config
+ accman *accounts.Manager
+ log log.Logger
ephemeralKeystore string // if non-empty, the key directory that will be removed by Stop
instanceDirLock fileutil.Releaser // prevents concurrent use of instance directory
- server *p2p.Server // Currently running P2P networking layer
-
- lifecycles map[reflect.Type]Lifecycle // All registered backends, services, and auxiliary services that have a lifecycle
-
- httpServers serverMap // serverMap stores information about the node's rpc, ws, and graphQL http servers.
-
- rpcAPIs []rpc.API // List of APIs currently provided by the node
- inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
-
- ipc *HTTPServer // Stores information about the ipc http server
-
- stop chan struct{} // Channel to wait for termination notifications
- lock sync.RWMutex
-
- log log.Logger
+ lock sync.RWMutex
+ stop chan struct{} // Channel to wait for termination notifications
+ server *p2p.Server // Currently running P2P networking layer
+ lifecycles map[reflect.Type]Lifecycle // All registered backends, services, and auxiliary services that have a lifecycle
+ httpServers serverMap // serverMap stores information about the node's rpc, ws, and graphQL http servers.
+ inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
+ rpcAPIs []rpc.API // List of APIs currently provided by the node
+ ipc *HTTPServer // Stores information about the ipc http server
}
// New creates a new P2P node, ready for protocol registration.
@@ -158,13 +151,13 @@ func New(conf *Config) (*Node, error) {
}
if conf.WSHost != "" {
node.httpServers[conf.WSEndpoint()] = &HTTPServer{
- WsOrigins: conf.WSOrigins,
- Whitelist: conf.WSModules,
- Srv: rpc.NewServer(),
- endpoint: conf.WSEndpoint(),
- host: conf.WSHost,
- port: conf.WSPort,
- WSAllowed: 1,
+ WsOrigins: conf.WSOrigins,
+ Whitelist: conf.WSModules,
+ Srv: rpc.NewServer(),
+ endpoint: conf.WSEndpoint(),
+ host: conf.WSHost,
+ port: conf.WSPort,
+ WSAllowed: 1,
}
}
diff --git a/node/rpcstack.go b/node/rpcstack.go
index 32e4cd74d79d..cb39a1c4f822 100644
--- a/node/rpcstack.go
+++ b/node/rpcstack.go
@@ -222,7 +222,6 @@ func newGzipHandler(next http.Handler) http.Handler {
// NewWebsocketUpgradeHandler returns a websocket handler that serves an incoming request only if it contains an upgrade
// request to the websocket protocol. If not, serves the the request with the http handler.
func (hs *HTTPServer) NewWebsocketUpgradeHandler(h http.Handler, ws http.Handler) http.Handler {
- // TODO make sure you protect the pointer
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if atomic.LoadInt32(&hs.WSAllowed) == 1 && isWebsocket(r) {
ws.ServeHTTP(w, r)
From 71d95904eea47aaa8f2519dacea9712ef67cb8f7 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Mon, 6 Jul 2020 19:11:28 +0200
Subject: [PATCH 076/160] remove P2PServer method from les, unnecessary
---
les/client.go | 10 ----------
1 file changed, 10 deletions(-)
diff --git a/les/client.go b/les/client.go
index 07f7acaa3d28..96b9fffcd7f0 100644
--- a/les/client.go
+++ b/les/client.go
@@ -18,7 +18,6 @@
package les
import (
- "errors"
"fmt"
"time"
@@ -281,15 +280,6 @@ func (s *LightEthereum) Protocols() []p2p.Protocol {
}, s.dialCandidates)
}
-// P2PServer registers the node's running p2p server with the Backend.
-func (s *LightEthereum) P2PServer(server *p2p.Server) error {
- if server == nil {
- return errors.New("p2p server is not running, cannot register with les backend") // TODO is this error message okay?
- }
- s.p2pServer = server
- return nil
-}
-
// Start implements node.Lifecycle, starting all internal goroutines needed by the
// light ethereum protocol implementation.
func (s *LightEthereum) Start() error {
From 7661eb87b2f5b92a1f9556eda7ebc765267122e7 Mon Sep 17 00:00:00 2001
From: rene <41963722+renaynay@users.noreply.github.com>
Date: Tue, 7 Jul 2020 13:39:04 +0200
Subject: [PATCH 077/160] refactor http servers + graphql (#26)
---
cmd/geth/main.go | 2 -
cmd/geth/usage.go | 4 +-
cmd/utils/flags.go | 47 +++++++-------------
cmd/utils/flags_legacy.go | 13 ++++++
go.mod | 2 +-
go.sum | 15 +++++++
graphql/graphql_test.go | 10 +++--
graphql/service.go | 71 +++++++-----------------------
node/api.go | 37 +++++-----------
node/config.go | 20 +--------
node/defaults.go | 1 -
node/node.go | 91 ++++++++++++++++++++++++---------------
node/node_test.go | 67 +++++++++++++++++++++++++---
node/rpcstack.go | 28 ++++--------
node/rpcstack_test.go | 2 +-
15 files changed, 208 insertions(+), 202 deletions(-)
diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index bbbc1b70d4ea..c475c9c66105 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -170,8 +170,6 @@ var (
utils.LegacyRPCCORSDomainFlag,
utils.LegacyRPCVirtualHostsFlag,
utils.GraphQLEnabledFlag,
- utils.GraphQLListenAddrFlag,
- utils.GraphQLPortFlag,
utils.GraphQLCORSDomainFlag,
utils.GraphQLVirtualHostsFlag,
utils.HTTPApiFlag,
diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go
index 277774b0cc5b..44f5750fee82 100644
--- a/cmd/geth/usage.go
+++ b/cmd/geth/usage.go
@@ -142,8 +142,6 @@ var AppHelpFlagGroups = []flags.FlagGroup{
utils.WSApiFlag,
utils.WSAllowedOriginsFlag,
utils.GraphQLEnabledFlag,
- utils.GraphQLListenAddrFlag,
- utils.GraphQLPortFlag,
utils.GraphQLCORSDomainFlag,
utils.GraphQLVirtualHostsFlag,
utils.RPCGlobalGasCap,
@@ -231,6 +229,8 @@ var AppHelpFlagGroups = []flags.FlagGroup{
utils.LegacyWSApiFlag,
utils.LegacyGpoBlocksFlag,
utils.LegacyGpoPercentileFlag,
+ utils.LegacyGraphQLListenAddrFlag,
+ utils.LegacyGraphQLPortFlag,
}, debug.DeprecatedFlags...),
},
{
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index e177df569261..1a20dc6189cc 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -516,6 +516,20 @@ var (
Usage: "API's offered over the HTTP-RPC interface",
Value: "",
}
+ GraphQLEnabledFlag = cli.BoolFlag{
+ Name: "graphql",
+ Usage: "Enable GraphQL on the HTTP-RPC server. Note that GraphQL can only be started if an HTTP server is started as well.",
+ }
+ GraphQLCORSDomainFlag = cli.StringFlag{
+ Name: "graphql.corsdomain",
+ Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)",
+ Value: "",
+ }
+ GraphQLVirtualHostsFlag = cli.StringFlag{
+ Name: "graphql.vhosts",
+ Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.",
+ Value: strings.Join(node.DefaultConfig.GraphQLVirtualHosts, ","),
+ }
WSEnabledFlag = cli.BoolFlag{
Name: "ws",
Usage: "Enable the WS-RPC server",
@@ -540,30 +554,6 @@ var (
Usage: "Origins from which to accept websockets requests",
Value: "",
}
- GraphQLEnabledFlag = cli.BoolFlag{
- Name: "graphql",
- Usage: "Enable the GraphQL server",
- }
- GraphQLListenAddrFlag = cli.StringFlag{
- Name: "graphql.addr",
- Usage: "GraphQL server listening interface",
- Value: node.DefaultGraphQLHost,
- }
- GraphQLPortFlag = cli.IntFlag{
- Name: "graphql.port",
- Usage: "GraphQL server listening port",
- Value: node.DefaultGraphQLPort,
- }
- GraphQLCORSDomainFlag = cli.StringFlag{
- Name: "graphql.corsdomain",
- Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)",
- Value: "",
- }
- GraphQLVirtualHostsFlag = cli.StringFlag{
- Name: "graphql.vhosts",
- Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.",
- Value: strings.Join(node.DefaultConfig.GraphQLVirtualHosts, ","),
- }
ExecFlag = cli.StringFlag{
Name: "exec",
Usage: "Execute JavaScript statement",
@@ -950,13 +940,6 @@ func setHTTP(ctx *cli.Context, cfg *node.Config) {
// setGraphQL creates the GraphQL listener interface string from the set
// command line flags, returning empty if the GraphQL endpoint is disabled.
func setGraphQL(ctx *cli.Context, cfg *node.Config) {
- if ctx.GlobalBool(GraphQLEnabledFlag.Name) && cfg.GraphQLHost == "" {
- cfg.GraphQLHost = "127.0.0.1"
- if ctx.GlobalIsSet(GraphQLListenAddrFlag.Name) {
- cfg.GraphQLHost = ctx.GlobalString(GraphQLListenAddrFlag.Name)
- }
- }
- cfg.GraphQLPort = ctx.GlobalInt(GraphQLPortFlag.Name)
if ctx.GlobalIsSet(GraphQLCORSDomainFlag.Name) {
cfg.GraphQLCors = splitAndTrim(ctx.GlobalString(GraphQLCORSDomainFlag.Name))
}
@@ -1728,7 +1711,7 @@ func RegisterEthStatsService(stack *node.Node, backend ethapi.Backend, url strin
// RegisterGraphQLService is a utility function to construct a new service and register it against a node.
func RegisterGraphQLService(stack *node.Node, backend ethapi.Backend, cfg node.Config) {
- if err := graphql.New(stack, backend, cfg.GraphQLEndpoint(), cfg.GraphQLCors, cfg.GraphQLVirtualHosts, cfg.HTTPTimeouts); err != nil {
+ if err := graphql.New(stack, backend, cfg.GraphQLCors, cfg.GraphQLVirtualHosts); err != nil {
Fatalf("Failed to register the GraphQL service: %v", err)
}
}
diff --git a/cmd/utils/flags_legacy.go b/cmd/utils/flags_legacy.go
index c39664d24984..1376d47c0554 100644
--- a/cmd/utils/flags_legacy.go
+++ b/cmd/utils/flags_legacy.go
@@ -89,6 +89,8 @@ var (
Name: "testnet",
Usage: "Pre-configured test network (Deprecated: Please choose one of --goerli, --rinkeby, or --ropsten.)",
}
+
+ // (Deprecated May 2020, shown in aliased flags section)
LegacyRPCEnabledFlag = cli.BoolFlag{
Name: "rpc",
Usage: "Enable the HTTP-RPC server (deprecated, use --http)",
@@ -158,6 +160,17 @@ var (
Usage: "Comma separated enode URLs for P2P v5 discovery bootstrap (light server, light nodes) (deprecated, use --bootnodes)",
Value: "",
}
+
+ // (Deprecated July 2020, shown in aliased flags section)
+ LegacyGraphQLListenAddrFlag = cli.StringFlag{
+ Name: "graphql.addr",
+ Usage: "GraphQL server listening interface (deprecated, graphql can only be enabled on the HTTP-RPC server endpoint, use --graphql)",
+ }
+ LegacyGraphQLPortFlag = cli.IntFlag{
+ Name: "graphql.port",
+ Usage: "GraphQL server listening port (deprecated, graphql can only be enabled on the HTTP-RPC server endpoint, use --graphql)",
+ Value: node.DefaultHTTPPort,
+ }
)
// showDeprecated displays deprecated flags that will be soon removed from the codebase.
diff --git a/go.mod b/go.mod
index db16cd3cb592..eaff1e2ac5e6 100644
--- a/go.mod
+++ b/go.mod
@@ -60,7 +60,7 @@ require (
github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
golang.org/x/net v0.0.0-20200625001655-4c5254603344 // indirect
- golang.org/x/sync v0.0.0-20181108010431-42b317875d0f
+ golang.org/x/sync v0.0.0-20190423024810-112230192c58
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd
golang.org/x/text v0.3.2
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4
diff --git a/go.sum b/go.sum
index acb104673937..d0e87bd69cc3 100644
--- a/go.sum
+++ b/go.sum
@@ -193,30 +193,45 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX
github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208 h1:1cngl9mPEoITZG8s8cVcUy5CeIBYhEESkOB7m6Gmkrk=
github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
+gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6 h1:a6cXbcDDUkSBlpnkWV1bJ+vv3mOgQEltEJ2rPxroVu0=
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0=
gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go
index 08c1e4c8b576..366685151014 100644
--- a/graphql/graphql_test.go
+++ b/graphql/graphql_test.go
@@ -25,14 +25,16 @@ import (
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/node"
- "github.com/ethereum/go-ethereum/rpc"
-
"github.com/stretchr/testify/assert"
)
func TestBuildSchema(t *testing.T) {
+ stack, err := node.New(&node.DefaultConfig)
+ if err != nil {
+ t.Fatalf("could not create new node: %v", err)
+ }
// Make sure the schema can be parsed and matched up to the object model.
- if _, err := newHandler(nil); err != nil {
+ if err := newHandler(stack, nil, []string{}, []string{}); err != nil {
t.Errorf("Could not construct GraphQL handler: %v", err)
}
}
@@ -120,7 +122,7 @@ func createGQLService(t *testing.T, stack *node.Node, endpoint string) {
}
// create gql service
- err = New(stack, ethBackend.APIBackend, endpoint, []string{}, []string{}, rpc.DefaultHTTPTimeouts)
+ err = New(stack, ethBackend.APIBackend,[]string{}, []string{})
if err != nil {
t.Fatalf("could not create graphql service: %v", err)
}
diff --git a/graphql/service.go b/graphql/service.go
index 5c3d872842d9..72ecf35bcb22 100644
--- a/graphql/service.go
+++ b/graphql/service.go
@@ -17,81 +17,42 @@
package graphql
import (
+ "fmt"
"github.com/ethereum/go-ethereum/internal/ethapi"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
- "github.com/ethereum/go-ethereum/rpc"
"github.com/graph-gophers/graphql-go"
"github.com/graph-gophers/graphql-go/relay"
- "net/http"
)
// New constructs a new GraphQL service instance.
-func New(stack *node.Node, backend ethapi.Backend, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) error {
+func New(stack *node.Node, backend ethapi.Backend, cors, vhosts []string) error {
if backend == nil {
stack.Fatalf("missing backend")
}
// check if http server with given endpoint exists and enable graphQL on it
- server := stack.ExistingHTTPServer(endpoint)
- if server != nil {
- // set vhosts, cors and timeouts
- server.Vhosts = append(server.Vhosts, vhosts...)
- server.CorsAllowedOrigins = append(server.CorsAllowedOrigins, cors...)
- server.Timeouts = timeouts
- // create handler
- handler, err := createHandler(backend, cors, vhosts)
- if err != nil {
- return err
- }
- server.GQLHandler = handler
- // don't register lifecycle if registering on existing http server
- return nil
- }
- // otherwise create a new server
- handler, err := createHandler(backend, cors, vhosts)
- if err != nil {
- return err
- }
- // create the http server
- gqlServer := &node.HTTPServer{
- RPCAllowed: 0,
- WSAllowed: 0,
- Vhosts: vhosts,
- CorsAllowedOrigins: cors,
- Timeouts: timeouts,
- GQLHandler: handler,
- Srv: rpc.NewServer(),
- }
- gqlServer.SetEndpoint(endpoint)
- stack.RegisterHTTPServer(endpoint, gqlServer)
-
- return nil
-}
-
-func createHandler(backend ethapi.Backend, cors, vhosts []string) (http.Handler, error) {
- // create handler stack and wrap the graphql handler
- handler, err := newHandler(backend)
- if err != nil {
- return nil, err
- }
- handler = node.NewHTTPHandlerStack(handler, cors, vhosts)
-
- return handler, nil
+ return newHandler(stack, backend, cors, vhosts)
}
// newHandler returns a new `http.Handler` that will answer GraphQL queries.
// It additionally exports an interactive query browser on the / endpoint.
-func newHandler(backend ethapi.Backend) (http.Handler, error) {
+func newHandler(stack *node.Node, backend ethapi.Backend, cors, vhosts []string) error {
q := Resolver{backend}
s, err := graphql.ParseSchema(schema, &q)
if err != nil {
- return nil, err
+ return err
}
h := &relay.Handler{Schema: s}
+ handler := node.NewHTTPHandlerStack(h, cors, vhosts)
+
+ endpoint := stack.RegisterPath("/graphql/ui", GraphiQL{})
+ endpoint = stack.RegisterPath("/graphql", handler)
+ endpoint = stack.RegisterPath("/graphql/", handler)
- mux := http.NewServeMux()
- mux.Handle("/", GraphiQL{})
- mux.Handle("/graphql", h)
- mux.Handle("/graphql/", h)
- return mux, nil
+ if endpoint != "" {
+ log.Info("GraphQL configured on endpoint", "endpoint", fmt.Sprintf("http://%s/graphql", endpoint))
+ log.Info("GraphQL web UI enabled", "endpoint", fmt.Sprintf("http://%s/graphql/ui", endpoint))
+ }
+ return nil
}
diff --git a/node/api.go b/node/api.go
index 17adc19695b6..55956f63ded0 100644
--- a/node/api.go
+++ b/node/api.go
@@ -191,7 +191,7 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
}
}
// configure http server
- httpServer := &HTTPServer{
+ httpServer := &httpServer{
host: *host,
port: *port,
endpoint: endpoint,
@@ -201,7 +201,8 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
Whitelist: modules,
}
// create handler
- httpServer.handler = NewHTTPHandlerStack(httpServer.Srv, httpServer.CorsAllowedOrigins, httpServer.Vhosts)
+ handler := NewHTTPHandlerStack(httpServer.Srv, httpServer.CorsAllowedOrigins, httpServer.Vhosts)
+ httpServer.srvMux.Handle("/", handler)
// create HTTP server
if err := api.node.CreateHTTPServer(httpServer, false); err != nil {
return false, err
@@ -213,7 +214,6 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
api.node.log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%v/", httpServer.Listener.Addr()),
"cors", strings.Join(httpServer.CorsAllowedOrigins, ","),
"vhosts", strings.Join(httpServer.Vhosts, ","))
-
return true, nil
}
@@ -228,7 +228,6 @@ func (api *PrivateAdminAPI) StopRPC() (bool, error) {
return true, nil
}
}
-
return false, fmt.Errorf("HTTP RPC not running")
}
@@ -255,23 +254,6 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
port = &api.node.config.WSPort
}
endpoint := fmt.Sprintf("%s:%d", *host, *port)
- // check if there is an existing server on the specified port, and if there is, enable ws on it
- if server, exists := api.node.httpServers[endpoint]; exists {
- // else configure ws on the existing server
- atomic.StoreInt32(&server.WSAllowed, 1)
- // configure origins
- origins := api.node.config.WSOrigins
- if allowedOrigins != nil {
- origins = nil
- for _, origin := range strings.Split(*allowedOrigins, ",") {
- origins = append(origins, strings.TrimSpace(origin))
- }
- }
- server.WsOrigins = origins
-
- api.node.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", server.Listener.Addr()))
- return true, nil
- }
origins := api.node.config.WSOrigins
if allowedOrigins != nil {
@@ -286,6 +268,8 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
atomic.StoreInt32(&existingServer.WSAllowed, 1)
existingServer.WsOrigins = origins
+ api.node.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", existingServer.Listener.Addr()))
+ return true, nil
}
modules := api.node.config.WSModules
@@ -296,7 +280,7 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
}
}
// configure http server
- wsServer := &HTTPServer{
+ wsServer := &httpServer{
Srv: rpc.NewServer(),
endpoint: endpoint,
host: *host,
@@ -306,7 +290,8 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
WSAllowed: 1,
}
// create handler
- wsServer.handler = wsServer.Srv.WebsocketHandler(wsServer.WsOrigins)
+ handler := wsServer.Srv.WebsocketHandler(wsServer.WsOrigins)
+ wsServer.srvMux.Handle("/", handler)
// create the HTTP server
if err := api.node.CreateHTTPServer(wsServer, api.node.config.WSExposeAll); err != nil {
return false, err
@@ -314,9 +299,10 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
// register the HTTP server
api.node.RegisterHTTPServer(endpoint, wsServer)
// start the HTTP server
- wsServer.Start()
+ if err := wsServer.Start(); err != nil {
+ return false, err
+ }
api.node.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", wsServer.Listener.Addr()))
-
return true, nil
}
@@ -334,7 +320,6 @@ func (api *PrivateAdminAPI) StopWS() (bool, error) {
return true, nil
}
}
-
return false, fmt.Errorf("WebSocket RPC not running")
}
diff --git a/node/config.go b/node/config.go
index 61566b7bee9b..55532632cd1b 100644
--- a/node/config.go
+++ b/node/config.go
@@ -162,15 +162,6 @@ type Config struct {
// private APIs to untrusted users is a major security risk.
WSExposeAll bool `toml:",omitempty"`
- // GraphQLHost is the host interface on which to start the GraphQL server. If this
- // field is empty, no GraphQL API endpoint will be started.
- GraphQLHost string
-
- // GraphQLPort is the TCP port number on which to start the GraphQL server. The
- // default zero value is/ valid and will pick a port number randomly (useful
- // for ephemeral nodes).
- GraphQLPort int `toml:",omitempty"`
-
// GraphQLCors is the Cross-Origin Resource Sharing header to send to requesting
// clients. Please be aware that CORS is a browser enforced security, it's fully
// useless for custom HTTP clients.
@@ -247,15 +238,6 @@ func (c *Config) HTTPEndpoint() string {
return fmt.Sprintf("%s:%d", c.HTTPHost, c.HTTPPort)
}
-// GraphQLEndpoint resolves a GraphQL endpoint based on the configured host interface
-// and port parameters.
-func (c *Config) GraphQLEndpoint() string {
- if c.GraphQLHost == "" {
- return ""
- }
- return fmt.Sprintf("%s:%d", c.GraphQLHost, c.GraphQLPort)
-}
-
// DefaultHTTPEndpoint returns the HTTP endpoint used by default.
func DefaultHTTPEndpoint() string {
config := &Config{HTTPHost: DefaultHTTPHost, HTTPPort: DefaultHTTPPort}
@@ -280,7 +262,7 @@ func DefaultWSEndpoint() string {
// ExtRPCEnabled returns the indicator whether node enables the external
// RPC(http, ws or graphql).
func (c *Config) ExtRPCEnabled() bool {
- return c.HTTPHost != "" || c.WSHost != "" || c.GraphQLHost != ""
+ return c.HTTPHost != "" || c.WSHost != ""
}
// NodeName returns the devp2p node identifier.
diff --git a/node/defaults.go b/node/defaults.go
index f84a5d547998..c685dde5d127 100644
--- a/node/defaults.go
+++ b/node/defaults.go
@@ -45,7 +45,6 @@ var DefaultConfig = Config{
HTTPTimeouts: rpc.DefaultHTTPTimeouts,
WSPort: DefaultWSPort,
WSModules: []string{"net", "web3"},
- GraphQLPort: DefaultGraphQLPort,
GraphQLVirtualHosts: []string{"localhost"},
P2P: p2p.Config{
ListenAddr: ":30303",
diff --git a/node/node.go b/node/node.go
index f9bc79e5688f..af0c71b1bc3a 100644
--- a/node/node.go
+++ b/node/node.go
@@ -58,7 +58,7 @@ type Node struct {
httpServers serverMap // serverMap stores information about the node's rpc, ws, and graphQL http servers.
inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
rpcAPIs []rpc.API // List of APIs currently provided by the node
- ipc *HTTPServer // Stores information about the ipc http server
+ ipc *httpServer // Stores information about the ipc http server
}
// New creates a new P2P node, ready for protocol registration.
@@ -102,7 +102,7 @@ func New(conf *Config) (*Node, error) {
config: conf,
lifecycles: make(map[reflect.Type]Lifecycle),
httpServers: make(serverMap),
- ipc: &HTTPServer{
+ ipc: &httpServer{
endpoint: conf.IPCEndpoint(),
},
eventmux: new(event.TypeMux),
@@ -127,7 +127,7 @@ func New(conf *Config) (*Node, error) {
// Configure HTTP server(s)
if conf.HTTPHost != "" {
- httpServ := &HTTPServer{
+ httpServ := &httpServer{
CorsAllowedOrigins: conf.HTTPCors,
Vhosts: conf.HTTPVirtualHosts,
Whitelist: conf.HTTPModules,
@@ -150,7 +150,7 @@ func New(conf *Config) (*Node, error) {
node.httpServers[conf.HTTPEndpoint()] = httpServ
}
if conf.WSHost != "" {
- node.httpServers[conf.WSEndpoint()] = &HTTPServer{
+ node.httpServers[conf.WSEndpoint()] = &httpServer{
WsOrigins: conf.WSOrigins,
Whitelist: conf.WSModules,
Srv: rpc.NewServer(),
@@ -187,7 +187,7 @@ func (n *Node) Close() error {
}
}
-// RegisterLifecycle registers the given Lifecycle on the node
+// RegisterLifecycle registers the given Lifecycle on the node.
func (n *Node) RegisterLifecycle(lifecycle Lifecycle) {
kind := reflect.TypeOf(lifecycle)
if _, exists := n.lifecycles[kind]; exists {
@@ -197,31 +197,43 @@ func (n *Node) RegisterLifecycle(lifecycle Lifecycle) {
n.lifecycles[kind] = lifecycle
}
-// RegisterProtocols adds backend's protocols to the node's p2p server
+// RegisterProtocols adds backend's protocols to the node's p2p server.
func (n *Node) RegisterProtocols(protocols []p2p.Protocol) {
n.server.Protocols = append(n.server.Protocols, protocols...)
}
-// RegisterAPIs registers the APIs a service provides on the node
+// RegisterAPIs registers the APIs a service provides on the node.
func (n *Node) RegisterAPIs(apis []rpc.API) {
n.rpcAPIs = append(n.rpcAPIs, apis...)
}
-// RegisterHTTPServer registers the given HTTP server on the node
-func (n *Node) RegisterHTTPServer(endpoint string, server *HTTPServer) {
+// RegisterHTTPServer registers the given HTTP server on the node.
+func (n *Node) RegisterHTTPServer(endpoint string, server *httpServer) {
n.httpServers[endpoint] = server
}
-// ExistingHTTPServer checks if an HTTP server is already configured on the given endpoint
-func (n *Node) ExistingHTTPServer(endpoint string) *HTTPServer {
+// RegisterPath mounts the given handler on the given path on the canonical HTTP server.
+func (n *Node) RegisterPath(path string, handler http.Handler) string {
+ for _, server := range n.httpServers {
+ if atomic.LoadInt32(&server.RPCAllowed) == 1 {
+ server.srvMux.Handle(path, handler)
+ return server.endpoint
+ }
+ }
+ n.log.Warn(fmt.Sprintf("HTTP server not configured on node, path %s cannot be enabled", path))
+ return ""
+}
+
+// ExistingHTTPServer checks if an HTTP server is already configured on the given endpoint.
+func (n *Node) ExistingHTTPServer(endpoint string) *httpServer {
if server, exists := n.httpServers[endpoint]; exists {
return server
}
return nil
}
-// CreateHTTPServer creates an http.Server and adds it to the given HTTPServer
-func (n *Node) CreateHTTPServer(h *HTTPServer, exposeAll bool) error {
+// CreateHTTPServer creates an http.Server and adds it to the given httpServer.
+func (n *Node) CreateHTTPServer(h *httpServer, exposeAll bool) error {
// register apis and create handler stack
err := RegisterApisFromWhitelist(n.rpcAPIs, h.Whitelist, h.Srv, exposeAll)
if err != nil {
@@ -234,7 +246,7 @@ func (n *Node) CreateHTTPServer(h *HTTPServer, exposeAll bool) error {
return err
}
// create the HTTP server
- httpSrv := &http.Server{Handler: h.handler}
+ httpSrv := &http.Server{Handler: &h.srvMux}
// check timeouts if they exist
if h.Timeouts != (rpc.HTTPTimeouts{}) {
CheckTimeouts(&h.Timeouts)
@@ -242,14 +254,14 @@ func (n *Node) CreateHTTPServer(h *HTTPServer, exposeAll bool) error {
httpSrv.WriteTimeout = h.Timeouts.WriteTimeout
httpSrv.IdleTimeout = h.Timeouts.IdleTimeout
}
- // add listener and http.Server to HTTPServer
+ // add listener and http.Server to httpServer
h.Listener = listener
h.Server = httpSrv
return nil
}
-// running returns true if the node's p2p server is already running
+// running returns true if the node's p2p server is already running.
func (n *Node) running() bool {
return n.server.Running()
}
@@ -298,7 +310,7 @@ func (n *Node) Start() error {
return nil
}
-// stopLifecycles stops the node's running Lifecycles
+// stopLifecycles stops the node's running Lifecycles.
func (n *Node) stopLifecycles(started []Lifecycle) {
for _, lifecycle := range started {
lifecycle.Stop()
@@ -343,23 +355,12 @@ func (n *Node) configureRPC() error {
n.stopInProc()
return err
}
-
+ // configure HTTPServers
for _, server := range n.httpServers {
// configure the handlers
- if atomic.LoadInt32(&server.RPCAllowed) == 1 {
- server.handler = NewHTTPHandlerStack(server.Srv, server.CorsAllowedOrigins, server.Vhosts)
- // wrap ws handler just in case ws is enabled through the console after start-up
- wsHandler := server.Srv.WebsocketHandler(server.WsOrigins)
- server.handler = server.NewWebsocketUpgradeHandler(server.handler, wsHandler)
-
- n.log.Info("HTTP configured on endpoint ", "endpoint", server.endpoint)
- if atomic.LoadInt32(&server.WSAllowed) == 1 {
- n.log.Info("Websocket configured on endpoint ", "endpoint", server.endpoint)
- }
- }
- if (atomic.LoadInt32(&server.WSAllowed) == 1) && server.handler == nil {
- server.handler = server.Srv.WebsocketHandler(server.WsOrigins)
- n.log.Info("Websocket configured on endpoint ", "endpoint", server.endpoint)
+ handler := n.createHandler(server)
+ if handler != nil {
+ server.srvMux.Handle("/", handler)
}
// create the HTTP server
if err := n.CreateHTTPServer(server, false); err != nil {
@@ -374,6 +375,28 @@ func (n *Node) configureRPC() error {
return nil
}
+// createHandler creates the http.Handler for the given httpServer.
+func (n *Node) createHandler(server *httpServer) http.Handler {
+ var handler http.Handler
+ if atomic.LoadInt32(&server.RPCAllowed) == 1 {
+ handler = NewHTTPHandlerStack(server.Srv, server.CorsAllowedOrigins, server.Vhosts)
+ // wrap ws handler just in case ws is enabled through the console after start-up
+ wsHandler := server.Srv.WebsocketHandler(server.WsOrigins)
+ handler = server.NewWebsocketUpgradeHandler(handler, wsHandler)
+
+ n.log.Info("HTTP configured on endpoint ", "endpoint", fmt.Sprintf("http://%s/", server.endpoint))
+ if atomic.LoadInt32(&server.WSAllowed) == 1 {
+ n.log.Info("Websocket configured on endpoint ", "endpoint", fmt.Sprintf("ws://%s/", server.endpoint))
+ }
+ }
+ if (atomic.LoadInt32(&server.WSAllowed) == 1) && handler == nil {
+ handler = server.Srv.WebsocketHandler(server.WsOrigins)
+ n.log.Info("Websocket configured on endpoint ", "endpoint", fmt.Sprintf("ws://%s/", server.endpoint))
+ }
+
+ return handler
+}
+
// startInProc initializes an in-process RPC endpoint.
func (n *Node) startInProc() error {
// Register all the APIs exposed by the services
@@ -426,7 +449,7 @@ func (n *Node) stopIPC() {
}
// stopServers terminates the given HTTP servers' endpoints
-func (n *Node) stopServer(server *HTTPServer) {
+func (n *Node) stopServer(server *httpServer) {
if server.Server != nil {
url := fmt.Sprintf("http://%v/", server.Listener.Addr())
// Don't bother imposing a timeout here.
@@ -437,7 +460,7 @@ func (n *Node) stopServer(server *HTTPServer) {
server.Srv.Stop()
server.Srv = nil
}
- // remove stopped http server from node's http servers // TODO is this preferable?
+ // remove stopped http server from node's http servers
delete(n.httpServers, server.endpoint)
}
diff --git a/node/node_test.go b/node/node_test.go
index bb1543650894..f417eb18215d 100644
--- a/node/node_test.go
+++ b/node/node_test.go
@@ -19,6 +19,7 @@ package node
import (
"errors"
"fmt"
+ "io"
"io/ioutil"
"net/http"
"os"
@@ -365,7 +366,7 @@ func TestLifecycleTerminationGuarantee(t *testing.T) {
stack.server.PrivateKey = testNodeKey
}
-// Tests whether a given HTTPServer can be registered on the node
+// Tests whether a given httpServer can be registered on the node
func TestRegisterHTTPServer(t *testing.T) {
stack, err := New(testNodeConfig())
if err != nil {
@@ -373,21 +374,21 @@ func TestRegisterHTTPServer(t *testing.T) {
}
defer stack.Close()
- srv1 := &HTTPServer{
+ srv1 := &httpServer{
host: "test1",
port: 0001,
}
endpoint1 := fmt.Sprintf("%s:%d", srv1.host, srv1.port)
stack.RegisterHTTPServer(endpoint1, srv1)
- srv2 := &HTTPServer{
+ srv2 := &httpServer{
host: "test2",
port: 0002,
}
endpoint2 := fmt.Sprintf("%s:%d", srv2.host, srv2.port)
stack.RegisterHTTPServer(endpoint2, srv2)
- noop := &HTTPServer{
+ noop := &httpServer{
host: "test",
port: 0000,
}
@@ -404,6 +405,55 @@ func TestRegisterHTTPServer(t *testing.T) {
}
}
+// Tests whether a handler can be successfully mounted on the canonical HTTP server
+// on the given path
+func TestRegisterPath_Successful(t *testing.T) {
+ node := createNode(t, 7878, 7979)
+
+ // create and mount handler
+ handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Write([]byte("success"))
+ })
+ endpoint := node.RegisterPath("/test", handler)
+ assert.Equal(t, "127.0.0.1:7878", endpoint)
+
+ // start node
+ if err := node.Start(); err != nil {
+ t.Fatalf("could not start node: %v", err)
+ }
+
+ // create HTTP request
+ httpReq, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:7878/test", nil)
+ if err != nil {
+ t.Error("could not issue new http request ", err)
+ }
+
+ // check response
+ resp := doHTTPRequest(t, httpReq)
+ buf := make([]byte, 7)
+ _, err = io.ReadFull(resp.Body, buf)
+ if err != nil {
+ t.Fatalf("could not read response: %v", err)
+ }
+ assert.Equal(t, "success", string(buf))
+}
+
+// Tests that the given handler will not be successfully mounted since no HTTP server
+// is enabled for RPC
+func TestRegisterPath_Unsuccessful(t *testing.T) {
+ node, err := New(&DefaultConfig)
+ if err != nil {
+ t.Fatalf("could not create new node: %v", err)
+ }
+
+ // create and mount handler
+ handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Write([]byte("success"))
+ })
+ endpoint := node.RegisterPath("/test", handler)
+ assert.Equal(t, "", endpoint)
+}
+
// Tests whether a node can successfully create and register HTTP server
// lifecycles on the node.
func TestHTTPServerCreateAndStop(t *testing.T) {
@@ -496,7 +546,7 @@ func TestWebsocketHTTPOnSamePort_HTTPRequest(t *testing.T) {
assert.Equal(t, "gzip", resp.Header.Get("Content-Encoding"))
}
-func startHTTP(t *testing.T, httpPort, wsPort int) *Node {
+func createNode(t *testing.T, httpPort, wsPort int) *Node {
conf := &Config{
HTTPHost: "127.0.0.1",
HTTPPort: httpPort,
@@ -507,7 +557,12 @@ func startHTTP(t *testing.T, httpPort, wsPort int) *Node {
if err != nil {
t.Fatalf("could not create a new node: %v", err)
}
- err = node.Start()
+ return node
+}
+
+func startHTTP(t *testing.T, httpPort, wsPort int) *Node {
+ node := createNode(t, httpPort, wsPort)
+ err := node.Start()
if err != nil {
t.Fatalf("could not start http service on node: %v", err)
}
diff --git a/node/rpcstack.go b/node/rpcstack.go
index cb39a1c4f822..fe2d2673af71 100644
--- a/node/rpcstack.go
+++ b/node/rpcstack.go
@@ -33,9 +33,11 @@ import (
"github.com/rs/cors"
)
-type serverMap map[string]*HTTPServer // Stores information about all http servers (if any) by their endpoint, including http, ws, and graphql
+type serverMap map[string]*httpServer // Stores information about all http servers (if any) by their endpoint, including http, ws, and graphql
+
+type httpServer struct {
+ srvMux http.ServeMux
-type HTTPServer struct {
handler http.Handler
Srv *rpc.Server
Server *http.Server
@@ -55,8 +57,6 @@ type HTTPServer struct {
RPCAllowed int32
WSAllowed int32
-
- GQLHandler http.Handler
}
func (sm serverMap) Start() error {
@@ -77,15 +77,15 @@ func (sm serverMap) Stop() error {
return nil
}
-// Start starts the serverMap's HTTP server. // TODO I don't like the way this is written
-func (h *HTTPServer) Start() error {
+// Start starts the httpServer's http.Server
+func (h *httpServer) Start() error {
go h.Server.Serve(h.Listener)
log.Info("HTTP endpoint successfully opened", "url", fmt.Sprintf("http://%v/", h.Listener.Addr()))
return nil
}
-// Stop shuts down the serverMap's HTTP server. // TODO I don't like the way this is written
-func (h *HTTPServer) Stop() error {
+// Stop shuts down the httpServer's http.Server
+func (h *httpServer) Stop() error {
if h.Server != nil {
url := fmt.Sprintf("http://%v/", h.Listener.Addr())
// Don't bother imposing a timeout here.
@@ -100,16 +100,6 @@ func (h *HTTPServer) Stop() error {
return nil
}
-// SetHandler assigns the given handler to the serverMap.
-func (h *HTTPServer) SetHandler(handler http.Handler) {
- h.handler = handler
-}
-
-// SetEndpoints assigns the given endpoint to the serverMap.
-func (h *HTTPServer) SetEndpoint(endpoint string) {
- h.endpoint = endpoint
-}
-
// NewHTTPHandlerStack returns wrapped http-related handlers
func NewHTTPHandlerStack(srv http.Handler, cors []string, vhosts []string) http.Handler {
// Wrap the CORS-handler within a host-handler
@@ -221,7 +211,7 @@ func newGzipHandler(next http.Handler) http.Handler {
// NewWebsocketUpgradeHandler returns a websocket handler that serves an incoming request only if it contains an upgrade
// request to the websocket protocol. If not, serves the the request with the http handler.
-func (hs *HTTPServer) NewWebsocketUpgradeHandler(h http.Handler, ws http.Handler) http.Handler {
+func (hs *httpServer) NewWebsocketUpgradeHandler(h http.Handler, ws http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if atomic.LoadInt32(&hs.WSAllowed) == 1 && isWebsocket(r) {
ws.ServeHTTP(w, r)
diff --git a/node/rpcstack_test.go b/node/rpcstack_test.go
index f745e350afe9..3dfaf53ed6bc 100644
--- a/node/rpcstack_test.go
+++ b/node/rpcstack_test.go
@@ -12,7 +12,7 @@ import (
)
func TestNewWebsocketUpgradeHandler_websocket(t *testing.T) {
- h := &HTTPServer{
+ h := &httpServer{
Srv: rpc.NewServer(),
WSAllowed: 1,
}
From d96b2800e847effd0c970ba7f4e6c5e6499c22d8 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Tue, 7 Jul 2020 13:46:38 +0200
Subject: [PATCH 078/160] removed some TODOs
---
node/node.go | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/node/node.go b/node/node.go
index af0c71b1bc3a..76d52ca67d36 100644
--- a/node/node.go
+++ b/node/node.go
@@ -111,7 +111,7 @@ func New(conf *Config) (*Node, error) {
// Initialize the p2p server. This creates the node key and
// discovery databases.
- node.server = &p2p.Server{Config: conf.P2P} // TODO add init step for p2p server
+ node.server = &p2p.Server{Config: conf.P2P}
node.server.Config.PrivateKey = node.config.NodeKey()
node.server.Config.Name = node.config.NodeName()
node.server.Config.Logger = node.log
@@ -285,8 +285,6 @@ func (n *Node) Start() error {
}
n.log.Info("Starting peer-to-peer node", "instance", n.server.Name)
- // TODO running p2p server needs to somehow be added to the backend
-
// Configure the RPC interfaces
if err := n.configureRPC(); err != nil {
n.httpServers.Stop()
@@ -597,7 +595,7 @@ func (n *Node) WSEndpoint() string {
}
}
- return n.config.WSEndpoint() // TODO should it return the endpoint from the node's config? Or just an empty string?
+ return n.config.WSEndpoint()
}
// EventMux retrieves the event multiplexer used by all the network services in
From ff002b1a61fcd9699b76eeda91d2fc1d3222a42b Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Thu, 9 Jul 2020 15:09:17 +0200
Subject: [PATCH 079/160] init leth handler
---
les/client.go | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/les/client.go b/les/client.go
index 96b9fffcd7f0..198cda1b6b91 100644
--- a/les/client.go
+++ b/les/client.go
@@ -170,6 +170,12 @@ func New(stack *node.Node, config *eth.Config) (*LightEthereum, error) {
}
leth.ApiBackend.gpo = gasprice.NewOracle(leth.ApiBackend, gpoParams)
+ leth.handler = newClientHandler(config.UltraLightServers, config.UltraLightFraction, checkpoint, leth)
+ if leth.handler.ulc != nil {
+ log.Warn("Ultra light client is enabled", "trustedNodes", len(leth.handler.ulc.keys), "minTrustedFraction", leth.handler.ulc.fraction)
+ leth.blockchain.DisableCheckFreq()
+ }
+
leth.netRPCService = ethapi.NewPublicNetAPI(leth.p2pServer, leth.config.NetworkId)
// Register the backend on the node
From bafc12adba292eb7b506005b419070ed8eb44684 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Thu, 9 Jul 2020 16:27:12 +0200
Subject: [PATCH 080/160] register protocols and apis of les on eth backend
---
cmd/utils/flags.go | 2 ++
1 file changed, 2 insertions(+)
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index 1a20dc6189cc..2f54c5d97b73 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -1688,6 +1688,8 @@ func RegisterEthService(stack *node.Node, cfg *eth.Config) ethapi.Backend {
}
if cfg.LightServ > 0 {
ls, _ := les.NewLesServer(backend, cfg)
+ stack.RegisterProtocols(ls.Protocols()) // TODO should this happen?
+ stack.RegisterAPIs(ls.APIs())
backend.AddLesServer(ls)
}
return backend.APIBackend
From 975061ca36f7a03daec8be3c3626f0d9c90a361e Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Fri, 10 Jul 2020 13:30:52 +0200
Subject: [PATCH 081/160] node: make Node.Attach work before Node.Start
---
node/node.go | 24 ++++++------------------
1 file changed, 6 insertions(+), 18 deletions(-)
diff --git a/node/node.go b/node/node.go
index 76d52ca67d36..63409fa169d8 100644
--- a/node/node.go
+++ b/node/node.go
@@ -105,8 +105,9 @@ func New(conf *Config) (*Node, error) {
ipc: &httpServer{
endpoint: conf.IPCEndpoint(),
},
- eventmux: new(event.TypeMux),
- log: conf.Logger,
+ inprocHandler: rpc.NewServer(),
+ eventmux: new(event.TypeMux),
+ log: conf.Logger,
}
// Initialize the p2p server. This creates the node key and
@@ -395,26 +396,19 @@ func (n *Node) createHandler(server *httpServer) http.Handler {
return handler
}
-// startInProc initializes an in-process RPC endpoint.
+// startInProc registers all RPC APIs on the inproc server.
func (n *Node) startInProc() error {
- // Register all the APIs exposed by the services
- handler := rpc.NewServer()
for _, api := range n.rpcAPIs {
- if err := handler.RegisterName(api.Namespace, api.Service); err != nil {
+ if err := n.inprocHandler.RegisterName(api.Namespace, api.Service); err != nil {
return err
}
- n.log.Debug("InProc registered", "namespace", api.Namespace)
}
- n.inprocHandler = handler
return nil
}
// stopInProc terminates the in-process RPC endpoint.
func (n *Node) stopInProc() {
- if n.inprocHandler != nil {
- n.inprocHandler.Stop()
- n.inprocHandler = nil
- }
+ n.inprocHandler.Stop()
}
// startIPC initializes and starts the IPC RPC endpoint.
@@ -530,12 +524,6 @@ func (n *Node) Wait() {
// Attach creates an RPC client attached to an in-process API handler.
func (n *Node) Attach() (*rpc.Client, error) {
- n.lock.RLock()
- defer n.lock.RUnlock()
-
- if n.server == nil {
- return nil, ErrNodeStopped
- }
return rpc.DialInProc(n.inprocHandler), nil
}
From 8a568a42889d89d8f10a8faab84b8449b62b2ec9 Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Fri, 10 Jul 2020 13:47:44 +0200
Subject: [PATCH 082/160] all: excise SetContractBackend
---
cmd/geth/main.go | 12 +-----------
cmd/utils/flags.go | 2 +-
eth/api_backend.go | 5 -----
eth/backend.go | 10 ----------
internal/ethapi/backend.go | 3 ---
les/api_backend.go | 5 -----
les/api_test.go | 2 +-
les/client.go | 17 ++---------------
les/commons.go | 15 +++++++++++++++
les/server.go | 20 +++-----------------
10 files changed, 23 insertions(+), 68 deletions(-)
diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index c475c9c66105..8a155a76a6df 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -378,18 +378,8 @@ func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend) {
if err != nil {
utils.Fatalf("Failed to attach to self: %v", err)
}
- ethClient := ethclient.NewClient(rpcClient)
- // Set contract backend for ethereum service if local node
- // is serving LES requests.
- if ctx.GlobalInt(utils.LegacyLightServFlag.Name) > 0 || ctx.GlobalInt(utils.LightServeFlag.Name) > 0 {
- backend.SetContractBackend(ethClient)
- }
- // Set contract backend for les service if local node is
- // running as a light client.
- if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" {
- backend.SetContractBackend(ethClient)
- }
+ ethClient := ethclient.NewClient(rpcClient)
go func() {
// Open any wallets already attached
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index 2f54c5d97b73..7d837eaf2839 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -1687,7 +1687,7 @@ func RegisterEthService(stack *node.Node, cfg *eth.Config) ethapi.Backend {
Fatalf("Failed to register the Ethereum service: %w", err)
}
if cfg.LightServ > 0 {
- ls, _ := les.NewLesServer(backend, cfg)
+ ls, _ := les.NewLesServer(stack, backend, cfg)
stack.RegisterProtocols(ls.Protocols()) // TODO should this happen?
stack.RegisterAPIs(ls.APIs())
backend.AddLesServer(ls)
diff --git a/eth/api_backend.go b/eth/api_backend.go
index 46f41e7cd678..1b0e841d80db 100644
--- a/eth/api_backend.go
+++ b/eth/api_backend.go
@@ -32,7 +32,6 @@ import (
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/eth/gasprice"
- "github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/miner"
@@ -334,7 +333,3 @@ func (b *EthAPIBackend) Miner() *miner.Miner {
func (b *EthAPIBackend) StartMining(threads int) error {
return b.eth.StartMining(threads)
}
-
-func (b *EthAPIBackend) SetContractBackend(client *ethclient.Client) {
- b.eth.SetContractBackend(client)
-}
diff --git a/eth/backend.go b/eth/backend.go
index 82aef22944a2..a76191a6a2ec 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -26,7 +26,6 @@ import (
"sync/atomic"
"github.com/ethereum/go-ethereum/accounts"
- "github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/consensus"
@@ -60,7 +59,6 @@ type LesServer interface {
APIs() []rpc.API
Protocols() []p2p.Protocol
SetBloomBitsIndexer(bbIndexer *core.ChainIndexer)
- SetContractBackend(bind.ContractBackend)
}
// Ethereum implements the Ethereum full node service.
@@ -104,14 +102,6 @@ func (s *Ethereum) AddLesServer(ls LesServer) {
ls.SetBloomBitsIndexer(s.bloomIndexer)
}
-// SetClient sets a rpc client which connecting to our local node.
-func (s *Ethereum) SetContractBackend(backend bind.ContractBackend) {
- // Pass the rpc client to les server if it is enabled.
- if s.lesServer != nil {
- s.lesServer.SetContractBackend(backend)
- }
-}
-
// New creates a new Ethereum object (including the
// initialisation of the common Ethereum object)
func New(stack *node.Node, config *Config) (*Ethereum, error) {
diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go
index 6d8374eb53c9..12faa307171e 100644
--- a/internal/ethapi/backend.go
+++ b/internal/ethapi/backend.go
@@ -30,7 +30,6 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/downloader"
- "github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/miner"
@@ -96,8 +95,6 @@ type Backend interface {
ChainConfig() *params.ChainConfig
Engine() consensus.Engine
-
- SetContractBackend(client *ethclient.Client)
}
func GetAPIs(apiBackend Backend) []rpc.API {
diff --git a/les/api_backend.go b/les/api_backend.go
index d905081077a6..25dde0a2cd57 100644
--- a/les/api_backend.go
+++ b/les/api_backend.go
@@ -33,7 +33,6 @@ import (
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/eth/gasprice"
- "github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/light"
@@ -308,10 +307,6 @@ func (b *LesApiBackend) StartMining(threads int) error {
return fmt.Errorf("Light clients do not support mining") // TODO is this okay?
}
-func (b *LesApiBackend) SetContractBackend(client *ethclient.Client) {
- b.eth.SetContractBackend(client)
-}
-
func (b *LesApiBackend) TxPool() *core.TxPool {
return nil // TODO is this okay?
}
diff --git a/les/api_test.go b/les/api_test.go
index 1fcef8edacc2..0d8baac85491 100644
--- a/les/api_test.go
+++ b/les/api_test.go
@@ -508,7 +508,7 @@ func newLesServerService(ctx *adapters.ServiceContext, stack *node.Node) (node.L
if err != nil {
return nil, err
}
- server, err := NewLesServer(ethereum, &config)
+ server, err := NewLesServer(stack, ethereum, &config)
if err != nil {
return nil, err
}
diff --git a/les/client.go b/les/client.go
index 198cda1b6b91..a2f7c56dfd57 100644
--- a/les/client.go
+++ b/les/client.go
@@ -22,7 +22,6 @@ import (
"time"
"github.com/ethereum/go-ethereum/accounts"
- "github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/mclock"
@@ -37,7 +36,6 @@ import (
"github.com/ethereum/go-ethereum/eth/gasprice"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/internal/ethapi"
- "github.com/ethereum/go-ethereum/les/checkpointoracle"
lpc "github.com/ethereum/go-ethereum/les/lespay/client"
"github.com/ethereum/go-ethereum/light"
"github.com/ethereum/go-ethereum/log"
@@ -76,6 +74,7 @@ type LightEthereum struct {
p2pServer *p2p.Server
}
+// New creates an instance of the light client.
func New(stack *node.Node, config *eth.Config) (*LightEthereum, error) {
chainDb, err := stack.OpenDatabase("lightchaindata", config.DatabaseCache, config.DatabaseHandles, "eth/db/chaindata/")
if err != nil {
@@ -142,11 +141,7 @@ func New(stack *node.Node, config *eth.Config) (*LightEthereum, error) {
leth.txPool = light.NewTxPool(leth.chainConfig, leth.blockchain, leth.relay)
// Set up checkpoint oracle.
- oracle := config.CheckpointOracle
- if oracle == nil {
- oracle = params.CheckpointOracles[genesisHash]
- }
- leth.oracle = checkpointoracle.New(oracle, leth.localCheckpoint)
+ leth.oracle = leth.setupOracle(stack, genesisHash, config)
// Note: AddChildIndexer starts the update process for the child
leth.bloomIndexer.AddChildIndexer(leth.bloomTrieIndexer)
@@ -323,11 +318,3 @@ func (s *LightEthereum) Stop() error {
log.Info("Light ethereum stopped")
return nil
}
-
-// SetClient sets the rpc client and binds the registrar contract.
-func (s *LightEthereum) SetContractBackend(backend bind.ContractBackend) {
- if s.oracle == nil {
- return
- }
- s.oracle.Start(backend)
-}
diff --git a/les/commons.go b/les/commons.go
index cd8a2283493b..9f14f82a473a 100644
--- a/les/commons.go
+++ b/les/commons.go
@@ -26,9 +26,11 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth"
+ "github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/les/checkpointoracle"
"github.com/ethereum/go-ethereum/light"
+ "github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/ethereum/go-ethereum/p2p/enode"
@@ -145,3 +147,16 @@ func (c *lesCommons) localCheckpoint(index uint64) params.TrustedCheckpoint {
BloomRoot: light.GetBloomTrieRoot(c.chainDb, index, sectionHead),
}
}
+
+// setupOracle sets up the checkpoint oracle contract client.
+func (c *lesCommons) setupOracle(node *node.Node, genesis common.Hash, config *eth.Config) *checkpointoracle.CheckpointOracle {
+ cfg := config.CheckpointOracle
+ if cfg == nil {
+ cfg = params.CheckpointOracles[genesis]
+ }
+ oracle := checkpointoracle.New(cfg, c.localCheckpoint)
+ rpcClient, _ := node.Attach()
+ client := ethclient.NewClient(rpcClient)
+ oracle.Start(client)
+ return oracle
+}
diff --git a/les/server.go b/les/server.go
index 609a24fd2b4a..76c906e8b21f 100644
--- a/les/server.go
+++ b/les/server.go
@@ -20,14 +20,13 @@ import (
"crypto/ecdsa"
"time"
- "github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common/mclock"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/eth"
- "github.com/ethereum/go-ethereum/les/checkpointoracle"
"github.com/ethereum/go-ethereum/les/flowcontrol"
"github.com/ethereum/go-ethereum/light"
"github.com/ethereum/go-ethereum/log"
+ "github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/ethereum/go-ethereum/p2p/enode"
@@ -57,7 +56,7 @@ type LesServer struct {
threadsBusy int // Request serving threads count when system is busy(block insertion).
}
-func NewLesServer(e *eth.Ethereum, config *eth.Config) (*LesServer, error) {
+func NewLesServer(node *node.Node, e *eth.Ethereum, config *eth.Config) (*LesServer, error) {
// Collect les protocol version information supported by local node.
lesTopics := make([]discv5.Topic, len(AdvertiseProtocolVersions))
for i, pv := range AdvertiseProtocolVersions {
@@ -93,12 +92,7 @@ func NewLesServer(e *eth.Ethereum, config *eth.Config) (*LesServer, error) {
srv.costTracker, srv.minCapacity = newCostTracker(e.ChainDb(), config)
srv.freeCapacity = srv.minCapacity
- // Set up checkpoint oracle.
- oracle := config.CheckpointOracle
- if oracle == nil {
- oracle = params.CheckpointOracles[e.BlockChain().Genesis().Hash()]
- }
- srv.oracle = checkpointoracle.New(oracle, srv.localCheckpoint)
+ srv.oracle = srv.setupOracle(node, e.BlockChain().Genesis().Hash(), config)
// Initialize server capacity management fields.
srv.defParams = flowcontrol.ServerParams{
@@ -213,14 +207,6 @@ func (s *LesServer) SetBloomBitsIndexer(bloomIndexer *core.ChainIndexer) {
bloomIndexer.AddChildIndexer(s.bloomTrieIndexer)
}
-// SetClient sets the rpc client and starts running checkpoint contract if it is not yet watched.
-func (s *LesServer) SetContractBackend(backend bind.ContractBackend) {
- if s.oracle == nil {
- return
- }
- s.oracle.Start(backend)
-}
-
// capacityManagement starts an event handler loop that updates the recharge curve of
// the client manager and adjusts the client pool's size according to the total
// capacity updates coming from the client manager
From e930d38b74a5065f408347b9edd91cf0c0da4223 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Fri, 10 Jul 2020 13:55:44 +0200
Subject: [PATCH 083/160] revert blackbox test for ethclient
---
ethclient/ethclient.go | 8 --------
ethclient/ethclient_test.go | 33 ++++++++++++++++-----------------
2 files changed, 16 insertions(+), 25 deletions(-)
diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go
index e869f492e575..bc0305fc229d 100644
--- a/ethclient/ethclient.go
+++ b/ethclient/ethclient.go
@@ -397,14 +397,6 @@ func (ec *Client) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuer
return ec.c.EthSubscribe(ctx, ch, "logs", arg)
}
-// ToFilterArg is for testing purposes only.
-func ToFilterArg(q ethereum.FilterQuery, test bool) (interface{}, error) {
- if test {
- return toFilterArg(q)
- }
- return nil, fmt.Errorf("functionality reserved for testing") // TODO is this okay?
-}
-
func toFilterArg(q ethereum.FilterQuery) (interface{}, error) {
arg := map[string]interface{}{
"address": q.Addresses,
diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go
index 09cbdefa7e72..b49abe917732 100644
--- a/ethclient/ethclient_test.go
+++ b/ethclient/ethclient_test.go
@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see .
-package ethclient_test
+package ethclient
import (
"context"
@@ -33,24 +33,23 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth"
- "github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params"
)
// Verify that Client implements the ethereum interfaces.
var (
- _ = ethereum.ChainReader(ðclient.Client{})
- _ = ethereum.TransactionReader(ðclient.Client{})
- _ = ethereum.ChainStateReader(ðclient.Client{})
- _ = ethereum.ChainSyncReader(ðclient.Client{})
- _ = ethereum.ContractCaller(ðclient.Client{})
- _ = ethereum.GasEstimator(ðclient.Client{})
- _ = ethereum.GasPricer(ðclient.Client{})
- _ = ethereum.LogFilterer(ðclient.Client{})
- _ = ethereum.PendingStateReader(ðclient.Client{})
+ _ = ethereum.ChainReader(&Client{})
+ _ = ethereum.TransactionReader(&Client{})
+ _ = ethereum.ChainStateReader(&Client{})
+ _ = ethereum.ChainSyncReader(&Client{})
+ _ = ethereum.ContractCaller(&Client{})
+ _ = ethereum.GasEstimator(&Client{})
+ _ = ethereum.GasPricer(&Client{})
+ _ = ethereum.LogFilterer(&Client{})
+ _ = ethereum.PendingStateReader(&Client{})
// _ = ethereum.PendingStateEventer(&Client{})
- _ = ethereum.PendingContractCaller(ðclient.Client{})
+ _ = ethereum.PendingContractCaller(&Client{})
)
func TestToFilterArg(t *testing.T) {
@@ -164,7 +163,7 @@ func TestToFilterArg(t *testing.T) {
},
} {
t.Run(testCase.name, func(t *testing.T) {
- output, err := ethclient.ToFilterArg(testCase.input, true)
+ output, err := toFilterArg(testCase.input)
if (testCase.err == nil) != (err == nil) {
t.Fatalf("expected error %v but got %v", testCase.err, err)
}
@@ -256,7 +255,7 @@ func TestHeader(t *testing.T) {
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
- ec := ethclient.NewClient(client)
+ ec := NewClient(client)
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
@@ -305,7 +304,7 @@ func TestBalanceAt(t *testing.T) {
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
- ec := ethclient.NewClient(client)
+ ec := NewClient(client)
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
@@ -326,7 +325,7 @@ func TestTransactionInBlockInterrupted(t *testing.T) {
defer backend.Stop()
defer client.Close()
- ec := ethclient.NewClient(client)
+ ec := NewClient(client)
ctx, cancel := context.WithCancel(context.Background())
cancel()
tx, err := ec.TransactionInBlock(ctx, common.Hash{1}, 1)
@@ -343,7 +342,7 @@ func TestChainID(t *testing.T) {
client, _ := backend.Attach()
defer backend.Stop()
defer client.Close()
- ec := ethclient.NewClient(client)
+ ec := NewClient(client)
id, err := ec.ChainID(context.Background())
if err != nil {
From 54b8389cd9bccbd3aa2bef7435fb5f7718f2d9ad Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Fri, 10 Jul 2020 14:14:39 +0200
Subject: [PATCH 084/160] les: fix setOracle for chains without checkpoint
---
les/checkpointoracle/oracle.go | 10 ----------
les/commons.go | 21 ++++++++++++++++-----
2 files changed, 16 insertions(+), 15 deletions(-)
diff --git a/les/checkpointoracle/oracle.go b/les/checkpointoracle/oracle.go
index 73bd8f35d409..8f2dda3937f7 100644
--- a/les/checkpointoracle/oracle.go
+++ b/les/checkpointoracle/oracle.go
@@ -51,16 +51,6 @@ type CheckpointOracle struct {
// New creates a checkpoint oracle handler with given configs and callback.
func New(config *params.CheckpointOracleConfig, getLocal func(uint64) params.TrustedCheckpoint) *CheckpointOracle {
- if config == nil {
- log.Info("Checkpoint registrar is not enabled")
- return nil
- }
- if config.Address == (common.Address{}) || uint64(len(config.Signers)) < config.Threshold {
- log.Warn("Invalid checkpoint registrar config")
- return nil
- }
- log.Info("Configured checkpoint registrar", "address", config.Address, "signers", len(config.Signers), "threshold", config.Threshold)
-
return &CheckpointOracle{
config: config,
getLocal: getLocal,
diff --git a/les/commons.go b/les/commons.go
index 9f14f82a473a..003e196d2b82 100644
--- a/les/commons.go
+++ b/les/commons.go
@@ -30,6 +30,7 @@ import (
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/les/checkpointoracle"
"github.com/ethereum/go-ethereum/light"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discv5"
@@ -149,14 +150,24 @@ func (c *lesCommons) localCheckpoint(index uint64) params.TrustedCheckpoint {
}
// setupOracle sets up the checkpoint oracle contract client.
-func (c *lesCommons) setupOracle(node *node.Node, genesis common.Hash, config *eth.Config) *checkpointoracle.CheckpointOracle {
- cfg := config.CheckpointOracle
- if cfg == nil {
- cfg = params.CheckpointOracles[genesis]
+func (c *lesCommons) setupOracle(node *node.Node, genesis common.Hash, ethconfig *eth.Config) *checkpointoracle.CheckpointOracle {
+ config := ethconfig.CheckpointOracle
+ if config == nil {
+ // Try loading default config.
+ config = params.CheckpointOracles[genesis]
}
- oracle := checkpointoracle.New(cfg, c.localCheckpoint)
+ if config == nil {
+ log.Info("Checkpoint registrar is not enabled")
+ return nil
+ }
+ if config.Address == (common.Address{}) || uint64(len(config.Signers)) < config.Threshold {
+ log.Warn("Invalid checkpoint registrar config")
+ return nil
+ }
+ oracle := checkpointoracle.New(config, c.localCheckpoint)
rpcClient, _ := node.Attach()
client := ethclient.NewClient(rpcClient)
oracle.Start(client)
+ log.Info("Configured checkpoint registrar", "address", config.Address, "signers", len(config.Signers), "threshold", config.Threshold)
return oracle
}
From 212bb78b1fdff5e109f95d7d739bbef6e8c493b4 Mon Sep 17 00:00:00 2001
From: rene <41963722+renaynay@users.noreply.github.com>
Date: Fri, 10 Jul 2020 14:18:29 +0200
Subject: [PATCH 085/160] les --> lifecycle decoupled from ethbackend (#29)
---
eth/backend.go | 25 +------------------------
les/server.go | 22 +++++++++++++++++-----
2 files changed, 18 insertions(+), 29 deletions(-)
diff --git a/eth/backend.go b/eth/backend.go
index a76191a6a2ec..e29844211c56 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -54,10 +54,6 @@ import (
)
type LesServer interface {
- Start(srvr *p2p.Server)
- Stop()
- APIs() []rpc.API
- Protocols() []p2p.Protocol
SetBloomBitsIndexer(bbIndexer *core.ChainIndexer)
}
@@ -98,7 +94,6 @@ type Ethereum struct {
}
func (s *Ethereum) AddLesServer(ls LesServer) {
- s.lesServer = ls
ls.SetBloomBitsIndexer(s.bloomIndexer)
}
@@ -290,19 +285,10 @@ func CreateConsensusEngine(stack *node.Node, chainConfig *params.ChainConfig, co
// NOTE, some of these services probably need to be moved to somewhere else.
func (s *Ethereum) APIs() []rpc.API {
apis := ethapi.GetAPIs(s.APIBackend)
-
- // Append any APIs exposed explicitly by the les server
- if s.lesServer != nil {
- apis = append(apis, s.lesServer.APIs()...)
- }
+
// Append any APIs exposed explicitly by the consensus engine
apis = append(apis, s.engine.APIs(s.BlockChain())...)
- // Append any APIs exposed explicitly by the les server
- if s.lesServer != nil {
- apis = append(apis, s.lesServer.APIs()...)
- }
-
// Append all the local APIs and return
return append(apis, []rpc.API{
{
@@ -527,9 +513,6 @@ func (s *Ethereum) Protocols() []p2p.Protocol {
protos[i].Attributes = []enr.Entry{s.currentEthEntry()}
protos[i].DialCandidates = s.dialCandidates
}
- if s.lesServer != nil {
- protos = append(protos, s.lesServer.Protocols()...)
- }
return protos
}
@@ -551,9 +534,6 @@ func (s *Ethereum) Start() error {
}
// Start the networking layer and the light server if requested
s.protocolManager.Start(maxPeers)
- if s.lesServer != nil {
- s.lesServer.Start(s.p2pServer)
- }
return nil
}
@@ -562,9 +542,6 @@ func (s *Ethereum) Start() error {
func (s *Ethereum) Stop() error {
// Stop all the peer-related stuff first.
s.protocolManager.Stop()
- if s.lesServer != nil {
- s.lesServer.Stop()
- }
// Then stop everything else.
s.bloomIndexer.Close()
diff --git a/les/server.go b/les/server.go
index 76c906e8b21f..57d335f8a9c3 100644
--- a/les/server.go
+++ b/les/server.go
@@ -54,6 +54,8 @@ type LesServer struct {
minCapacity, maxCapacity, freeCapacity uint64
threadsIdle int // Request serving threads count when system is idle.
threadsBusy int // Request serving threads count when system is busy(block insertion).
+
+ p2pSrv *p2p.Server
}
func NewLesServer(node *node.Node, e *eth.Ethereum, config *eth.Config) (*LesServer, error) {
@@ -87,6 +89,7 @@ func NewLesServer(node *node.Node, e *eth.Ethereum, config *eth.Config) (*LesSer
servingQueue: newServingQueue(int64(time.Millisecond*10), float64(config.LightServ)/100),
threadsBusy: config.LightServ/100 + 1,
threadsIdle: threads,
+ p2pSrv: node.Server(),
}
srv.handler = newServerHandler(srv, e.BlockChain(), e.ChainDb(), e.TxPool(), e.Synced)
srv.costTracker, srv.minCapacity = newCostTracker(e.ChainDb(), config)
@@ -119,6 +122,11 @@ func NewLesServer(node *node.Node, e *eth.Ethereum, config *eth.Config) (*LesSer
"chtroot", checkpoint.CHTRoot, "bloomroot", checkpoint.BloomRoot)
}
srv.chtIndexer.Start(e.BlockChain())
+
+ node.RegisterProtocols(srv.Protocols())
+ node.RegisterAPIs(srv.APIs())
+ node.RegisterLifecycle(srv)
+
return srv, nil
}
@@ -160,14 +168,14 @@ func (s *LesServer) Protocols() []p2p.Protocol {
}
// Start starts the LES server
-func (s *LesServer) Start(srvr *p2p.Server) {
- s.privateKey = srvr.PrivateKey
+func (s *LesServer) Start() error {
+ s.privateKey = s.p2pSrv.PrivateKey
s.handler.start()
s.wg.Add(1)
go s.capacityManagement()
- if srvr.DiscV5 != nil {
+ if s.p2pSrv.DiscV5 != nil {
for _, topic := range s.lesTopics {
topic := topic
go func() {
@@ -175,14 +183,16 @@ func (s *LesServer) Start(srvr *p2p.Server) {
logger.Info("Starting topic registration")
defer logger.Info("Terminated topic registration")
- srvr.DiscV5.RegisterTopic(topic, s.closeCh)
+ s.p2pSrv.DiscV5.RegisterTopic(topic, s.closeCh)
}()
}
}
+
+ return nil
}
// Stop stops the LES service
-func (s *LesServer) Stop() {
+func (s *LesServer) Stop() error {
close(s.closeCh)
// Disconnect existing sessions.
@@ -201,6 +211,8 @@ func (s *LesServer) Stop() {
s.chtIndexer.Close()
s.wg.Wait()
log.Info("Les server stopped")
+
+ return nil
}
func (s *LesServer) SetBloomBitsIndexer(bloomIndexer *core.ChainIndexer) {
From 1844d22469df9e9b023325b481d14e21f7eebdd7 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Fri, 10 Jul 2020 14:41:07 +0200
Subject: [PATCH 086/160] remove Fatalf from node, should panic instead
---
graphql/service.go | 2 +-
node/node.go | 24 +-----------------------
2 files changed, 2 insertions(+), 24 deletions(-)
diff --git a/graphql/service.go b/graphql/service.go
index 72ecf35bcb22..61d097bb3f25 100644
--- a/graphql/service.go
+++ b/graphql/service.go
@@ -28,7 +28,7 @@ import (
// New constructs a new GraphQL service instance.
func New(stack *node.Node, backend ethapi.Backend, cors, vhosts []string) error {
if backend == nil {
- stack.Fatalf("missing backend")
+ panic("missing backend")
}
// check if http server with given endpoint exists and enable graphQL on it
return newHandler(stack, backend, cors, vhosts)
diff --git a/node/node.go b/node/node.go
index 63409fa169d8..377685ac38e3 100644
--- a/node/node.go
+++ b/node/node.go
@@ -20,13 +20,11 @@ import (
"context"
"errors"
"fmt"
- "io"
"net"
"net/http"
"os"
"path/filepath"
"reflect"
- "runtime"
"strings"
"sync"
"sync/atomic"
@@ -192,7 +190,7 @@ func (n *Node) Close() error {
func (n *Node) RegisterLifecycle(lifecycle Lifecycle) {
kind := reflect.TypeOf(lifecycle)
if _, exists := n.lifecycles[kind]; exists {
- n.Fatalf("Lifecycle cannot be registered more than once", kind)
+ panic(fmt.Sprintf("Lifecycle cannot be registered more than once: %v", kind))
}
n.lifecycles[kind] = lifecycle
@@ -673,23 +671,3 @@ func RegisterApisFromWhitelist(apis []rpc.API, modules []string, srv *rpc.Server
}
return nil
}
-
-// Fatalf formats a message to standard error and exits the program.
-// The message is also printed to standard output if standard error
-// is redirected to a different file.
-func (n *Node) Fatalf(format string, args ...interface{}) {
- w := io.MultiWriter(os.Stdout, os.Stderr)
- if runtime.GOOS == "windows" {
- // The SameFile check below doesn't work on Windows.
- // stdout is unlikely to get redirected though, so just print there.
- w = os.Stdout
- } else {
- outf, _ := os.Stdout.Stat()
- errf, _ := os.Stderr.Stat()
- if outf != nil && errf != nil && os.SameFile(outf, errf) {
- w = os.Stderr
- }
- }
- fmt.Fprintf(w, "Fatal: "+format+"\n", args...)
- os.Exit(1)
-}
From a24c7b802c7f13225b53daa58bc86394af548948 Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Fri, 10 Jul 2020 14:23:05 +0200
Subject: [PATCH 087/160] eth: remove AddLesServer
---
cmd/utils/flags.go | 1 -
eth/backend.go | 12 ++----------
les/api_test.go | 1 -
les/server.go | 9 +++++----
4 files changed, 7 insertions(+), 16 deletions(-)
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index 7d837eaf2839..e4536366407a 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -1690,7 +1690,6 @@ func RegisterEthService(stack *node.Node, cfg *eth.Config) ethapi.Backend {
ls, _ := les.NewLesServer(stack, backend, cfg)
stack.RegisterProtocols(ls.Protocols()) // TODO should this happen?
stack.RegisterAPIs(ls.APIs())
- backend.AddLesServer(ls)
}
return backend.APIBackend
}
diff --git a/eth/backend.go b/eth/backend.go
index e29844211c56..fa03f547e167 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -53,10 +53,6 @@ import (
"github.com/ethereum/go-ethereum/rpc"
)
-type LesServer interface {
- SetBloomBitsIndexer(bbIndexer *core.ChainIndexer)
-}
-
// Ethereum implements the Ethereum full node service.
type Ethereum struct {
config *Config
@@ -65,7 +61,6 @@ type Ethereum struct {
txPool *core.TxPool
blockchain *core.BlockChain
protocolManager *ProtocolManager
- lesServer LesServer
dialCandidates enode.Iterator
// DB interfaces
@@ -93,10 +88,6 @@ type Ethereum struct {
lock sync.RWMutex // Protects the variadic fields (e.g. gas price and etherbase)
}
-func (s *Ethereum) AddLesServer(ls LesServer) {
- ls.SetBloomBitsIndexer(s.bloomIndexer)
-}
-
// New creates a new Ethereum object (including the
// initialisation of the common Ethereum object)
func New(stack *node.Node, config *Config) (*Ethereum, error) {
@@ -285,7 +276,7 @@ func CreateConsensusEngine(stack *node.Node, chainConfig *params.ChainConfig, co
// NOTE, some of these services probably need to be moved to somewhere else.
func (s *Ethereum) APIs() []rpc.API {
apis := ethapi.GetAPIs(s.APIBackend)
-
+
// Append any APIs exposed explicitly by the consensus engine
apis = append(apis, s.engine.APIs(s.BlockChain())...)
@@ -503,6 +494,7 @@ func (s *Ethereum) NetVersion() uint64 { return s.networkID }
func (s *Ethereum) Downloader() *downloader.Downloader { return s.protocolManager.downloader }
func (s *Ethereum) Synced() bool { return atomic.LoadUint32(&s.protocolManager.acceptTxs) == 1 }
func (s *Ethereum) ArchiveMode() bool { return s.config.NoPruning }
+func (s *Ethereum) BloomIndexer() *core.ChainIndexer { return s.bloomIndexer }
// Protocols returns all the currently configured
// network protocols to start.
diff --git a/les/api_test.go b/les/api_test.go
index 0d8baac85491..14387865facf 100644
--- a/les/api_test.go
+++ b/les/api_test.go
@@ -512,6 +512,5 @@ func newLesServerService(ctx *adapters.ServiceContext, stack *node.Node) (node.L
if err != nil {
return nil, err
}
- ethereum.AddLesServer(server)
return ethereum, nil
}
diff --git a/les/server.go b/les/server.go
index 57d335f8a9c3..b856d24306ff 100644
--- a/les/server.go
+++ b/les/server.go
@@ -55,7 +55,7 @@ type LesServer struct {
threadsIdle int // Request serving threads count when system is idle.
threadsBusy int // Request serving threads count when system is busy(block insertion).
- p2pSrv *p2p.Server
+ p2pSrv *p2p.Server
}
func NewLesServer(node *node.Node, e *eth.Ethereum, config *eth.Config) (*LesServer, error) {
@@ -89,14 +89,16 @@ func NewLesServer(node *node.Node, e *eth.Ethereum, config *eth.Config) (*LesSer
servingQueue: newServingQueue(int64(time.Millisecond*10), float64(config.LightServ)/100),
threadsBusy: config.LightServ/100 + 1,
threadsIdle: threads,
- p2pSrv: node.Server(),
+ p2pSrv: node.Server(),
}
srv.handler = newServerHandler(srv, e.BlockChain(), e.ChainDb(), e.TxPool(), e.Synced)
srv.costTracker, srv.minCapacity = newCostTracker(e.ChainDb(), config)
srv.freeCapacity = srv.minCapacity
-
srv.oracle = srv.setupOracle(node, e.BlockChain().Genesis().Hash(), config)
+ // Initialize the bloom trie indexer.
+ e.BloomIndexer().AddChildIndexer(srv.bloomTrieIndexer)
+
// Initialize server capacity management fields.
srv.defParams = flowcontrol.ServerParams{
BufLimit: srv.freeCapacity * bufLimitRatio,
@@ -216,7 +218,6 @@ func (s *LesServer) Stop() error {
}
func (s *LesServer) SetBloomBitsIndexer(bloomIndexer *core.ChainIndexer) {
- bloomIndexer.AddChildIndexer(s.bloomTrieIndexer)
}
// capacityManagement starts an event handler loop that updates the recharge curve of
From aaee36b21cf4bca40728d60171217c447becb352 Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Fri, 10 Jul 2020 14:24:33 +0200
Subject: [PATCH 088/160] cmd/utils: remove duplicate protocol/API registration
---
cmd/utils/flags.go | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index e4536366407a..6af946dffe8a 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -1684,12 +1684,13 @@ func RegisterEthService(stack *node.Node, cfg *eth.Config) ethapi.Backend {
} else {
backend, err := eth.New(stack, cfg)
if err != nil {
- Fatalf("Failed to register the Ethereum service: %w", err)
+ Fatalf("Failed to register the Ethereum service: %v", err)
}
if cfg.LightServ > 0 {
- ls, _ := les.NewLesServer(stack, backend, cfg)
- stack.RegisterProtocols(ls.Protocols()) // TODO should this happen?
- stack.RegisterAPIs(ls.APIs())
+ _, err := les.NewLesServer(stack, backend, cfg)
+ if err != nil {
+ Fatalf("Failed to create the LES server: %v", err)
+ }
}
return backend.APIBackend
}
From ebc70617a158609f0969393cf20eaf6825db93d9 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Fri, 10 Jul 2020 14:47:20 +0200
Subject: [PATCH 089/160] remove newgqlhandler from rpcstack
---
node/rpcstack.go | 18 ------------------
1 file changed, 18 deletions(-)
diff --git a/node/rpcstack.go b/node/rpcstack.go
index fe2d2673af71..6d4c536caa0f 100644
--- a/node/rpcstack.go
+++ b/node/rpcstack.go
@@ -228,21 +228,3 @@ func isWebsocket(r *http.Request) bool {
return strings.ToLower(r.Header.Get("Upgrade")) == "websocket" &&
strings.ToLower(r.Header.Get("Connection")) == "upgrade"
}
-
-// NewGQLUpgradeHandler wraps the given handler, h, in the given graphQL handler.
-func NewGQLUpgradeHandler(h http.Handler, gql http.Handler) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- if isGQL(r) {
- gql.ServeHTTP(w, r)
- log.Debug("serving graphql request")
- return
- }
-
- h.ServeHTTP(w, r)
- })
-}
-
-// isGQL checks if the given request is a graphQL request.
-func isGQL(r *http.Request) bool {
- return r.URL.Path == "/graphql" || r.URL.Path == "/graphql/"
-}
From 5d2e75539187db6673d1fe08fe78098c4c7478b6 Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Fri, 10 Jul 2020 14:46:41 +0200
Subject: [PATCH 090/160] node: stop lifecycles in reverse order
---
node/node.go | 67 +++++++++++++++++++++++++++--------------------
node/node_test.go | 19 +++-----------
2 files changed, 41 insertions(+), 45 deletions(-)
diff --git a/node/node.go b/node/node.go
index 377685ac38e3..d909b8c06e17 100644
--- a/node/node.go
+++ b/node/node.go
@@ -50,13 +50,13 @@ type Node struct {
instanceDirLock fileutil.Releaser // prevents concurrent use of instance directory
lock sync.RWMutex
- stop chan struct{} // Channel to wait for termination notifications
- server *p2p.Server // Currently running P2P networking layer
- lifecycles map[reflect.Type]Lifecycle // All registered backends, services, and auxiliary services that have a lifecycle
- httpServers serverMap // serverMap stores information about the node's rpc, ws, and graphQL http servers.
- inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
- rpcAPIs []rpc.API // List of APIs currently provided by the node
- ipc *httpServer // Stores information about the ipc http server
+ stop chan struct{} // Channel to wait for termination notifications
+ server *p2p.Server // Currently running P2P networking layer
+ lifecycles []Lifecycle // All registered backends, services, and auxiliary services that have a lifecycle
+ httpServers serverMap // serverMap stores information about the node's rpc, ws, and graphQL http servers.
+ inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
+ rpcAPIs []rpc.API // List of APIs currently provided by the node
+ ipc *httpServer // Stores information about the ipc http server
}
// New creates a new P2P node, ready for protocol registration.
@@ -98,7 +98,6 @@ func New(conf *Config) (*Node, error) {
accman: am,
ephemeralKeystore: ephemeralKeystore,
config: conf,
- lifecycles: make(map[reflect.Type]Lifecycle),
httpServers: make(serverMap),
ipc: &httpServer{
endpoint: conf.IPCEndpoint(),
@@ -188,12 +187,12 @@ func (n *Node) Close() error {
// RegisterLifecycle registers the given Lifecycle on the node.
func (n *Node) RegisterLifecycle(lifecycle Lifecycle) {
- kind := reflect.TypeOf(lifecycle)
- if _, exists := n.lifecycles[kind]; exists {
- panic(fmt.Sprintf("Lifecycle cannot be registered more than once: %v", kind))
+ for _, obj := range n.lifecycles {
+ if obj == lifecycle {
+ panic(fmt.Sprintf("attempt to register lifecycle %T more than once", lifecycle))
+ }
}
-
- n.lifecycles[kind] = lifecycle
+ n.lifecycles = append(n.lifecycles, lifecycle)
}
// RegisterProtocols adds backend's protocols to the node's p2p server.
@@ -295,7 +294,7 @@ func (n *Node) Start() error {
var started []Lifecycle
for _, lifecycle := range n.lifecycles {
if err := lifecycle.Start(); err != nil {
- n.stopLifecycles(started)
+ stopLifecycles(started)
n.server.Stop()
return err
}
@@ -307,11 +306,25 @@ func (n *Node) Start() error {
return nil
}
-// stopLifecycles stops the node's running Lifecycles.
-func (n *Node) stopLifecycles(started []Lifecycle) {
- for _, lifecycle := range started {
- lifecycle.Stop()
+// containsLifecycle checks if 'lfs' contains 'l'.
+func containsLifecycle(lfs []Lifecycle, l Lifecycle) bool {
+ for _, obj := range lfs {
+ if obj == l {
+ return true
+ }
+ }
+ return false
+}
+
+// stopLifecycles stops the given lifecycles in reverse order.
+func stopLifecycles(lfs []Lifecycle) map[reflect.Type]error {
+ errors := make(map[reflect.Type]error)
+ for i := len(lfs) - 1; i >= 0; i-- {
+ if err := lfs[i].Stop(); err != nil {
+ errors[reflect.TypeOf(lfs[i])] = err
+ }
}
+ return errors
}
// Config returns the configuration of node.
@@ -364,10 +377,12 @@ func (n *Node) configureRPC() error {
return err
}
}
+
// only register http server as a lifecycle if it has not already been registered
- if _, exists := n.lifecycles[reflect.TypeOf(n.httpServers)]; !exists {
- n.RegisterLifecycle(n.httpServers)
+ if !containsLifecycle(n.lifecycles, &n.httpServers) {
+ n.RegisterLifecycle(&n.httpServers)
}
+
// All API endpoints started successfully
return nil
}
@@ -468,15 +483,9 @@ func (n *Node) Stop() error {
// Terminate the API, services and the p2p server.
n.stopIPC()
n.rpcAPIs = nil
- failure := &StopError{
- Services: make(map[reflect.Type]error),
- }
- for kind, lifecycle := range n.lifecycles {
- if err := lifecycle.Stop(); err != nil {
- failure.Services[reflect.TypeOf(lifecycle)] = err
- }
- delete(n.lifecycles, kind)
- }
+ failure := new(StopError)
+ failure.Services = stopLifecycles(n.lifecycles)
+
n.server.Stop()
n.server = nil
diff --git a/node/node_test.go b/node/node_test.go
index f417eb18215d..d1a40658a8f9 100644
--- a/node/node_test.go
+++ b/node/node_test.go
@@ -119,7 +119,7 @@ func TestLifecycleRegistry_Successful(t *testing.T) {
noop := NewNoop()
stack.RegisterLifecycle(noop)
- if _, exists := stack.lifecycles[reflect.TypeOf(noop)]; !exists {
+ if !containsLifecycle(stack.lifecycles, noop) {
t.Fatalf("lifecycle was not properly registered on the node, %v", err)
}
}
@@ -463,18 +463,11 @@ func TestHTTPServerCreateAndStop(t *testing.T) {
t.Fatalf("node has more than 1 http server")
}
// check to make sure http servers are registered
- var exists bool
- for _, lifecycle := range node1.lifecycles {
- if reflect.DeepEqual(node1.httpServers, lifecycle) {
- exists = true
- }
- }
- if !exists {
+ if !containsLifecycle(node1.lifecycles, &node1.httpServers) {
t.Fatal("HTTP servers not registered as lifecycles on the node")
}
// check to make sure http servers are configured properly
for _, server := range node1.httpServers {
-
if atomic.LoadInt32(&server.WSAllowed) == 0 && atomic.LoadInt32(&server.RPCAllowed) == 0 {
t.Fatalf("node's http server is not configured to handle both rpc and ws")
}
@@ -491,13 +484,7 @@ func TestHTTPServerCreateAndStop(t *testing.T) {
t.Fatalf("amount of http servers on the node is not equal to 2")
}
// check to make sure http servers are registered
- exists = false
- for _, lifecycle := range node2.lifecycles {
- if reflect.DeepEqual(node2.httpServers, lifecycle) {
- exists = true
- }
- }
- if !exists {
+ if !containsLifecycle(node2.lifecycles, &node2.httpServers) {
t.Fatal("HTTP servers not registered as lifecycles on the node")
}
// check that neither http server has both ws and rpc enabled
From 1b50b554ed7dbb77c6a8bfc17ace9006ffb73e4f Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Fri, 10 Jul 2020 14:50:17 +0200
Subject: [PATCH 091/160] node: simplify RegisterLifecycle
---
node/node.go | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/node/node.go b/node/node.go
index d909b8c06e17..4692d81172d8 100644
--- a/node/node.go
+++ b/node/node.go
@@ -187,10 +187,8 @@ func (n *Node) Close() error {
// RegisterLifecycle registers the given Lifecycle on the node.
func (n *Node) RegisterLifecycle(lifecycle Lifecycle) {
- for _, obj := range n.lifecycles {
- if obj == lifecycle {
- panic(fmt.Sprintf("attempt to register lifecycle %T more than once", lifecycle))
- }
+ if containsLifecycle(n.lifecycles, lifecycle) {
+ panic(fmt.Sprintf("attempt to register lifecycle %T more than once", lifecycle))
}
n.lifecycles = append(n.lifecycles, lifecycle)
}
From 489bb0580371ca41d26ae1f7e419d7e2a7cae45e Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Fri, 10 Jul 2020 14:54:35 +0200
Subject: [PATCH 092/160] donnt check ls
---
les/api_test.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/les/api_test.go b/les/api_test.go
index 14387865facf..7f6aca55cc5a 100644
--- a/les/api_test.go
+++ b/les/api_test.go
@@ -508,7 +508,7 @@ func newLesServerService(ctx *adapters.ServiceContext, stack *node.Node) (node.L
if err != nil {
return nil, err
}
- server, err := NewLesServer(stack, ethereum, &config)
+ _, err = NewLesServer(stack, ethereum, &config)
if err != nil {
return nil, err
}
From b2931b65b845df63a92a03f54c5ca3d10ba4e966 Mon Sep 17 00:00:00 2001
From: rene <41963722+renaynay@users.noreply.github.com>
Date: Fri, 10 Jul 2020 15:46:02 +0200
Subject: [PATCH 093/160] Explicit type check for backend (#27)
---
cmd/geth/main.go | 17 ++++---
eth/api_backend.go | 4 --
ethstats/ethstats.go | 100 +++++++++++++++++++++++++------------
go.sum | 5 --
internal/ethapi/backend.go | 9 +---
les/api_backend.go | 19 -------
6 files changed, 79 insertions(+), 75 deletions(-)
diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index 8a155a76a6df..735aeb653db0 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -19,6 +19,7 @@ package main
import (
"fmt"
+ "github.com/ethereum/go-ethereum/eth"
"math"
"os"
godebug "runtime/debug"
@@ -378,7 +379,6 @@ func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend) {
if err != nil {
utils.Fatalf("Failed to attach to self: %v", err)
}
-
ethClient := ethclient.NewClient(rpcClient)
go func() {
@@ -444,23 +444,24 @@ func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend) {
if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" {
utils.Fatalf("Light clients do not support mining")
}
+ ethBackend, ok := backend.(*eth.EthAPIBackend)
+ if !ok {
+ utils.Fatalf("Ethereum service not running: %v", err)
+ }
+
// Set the gas price to the limits from the CLI and start mining
gasprice := utils.GlobalBig(ctx, utils.MinerGasPriceFlag.Name)
if ctx.GlobalIsSet(utils.LegacyMinerGasPriceFlag.Name) && !ctx.GlobalIsSet(utils.MinerGasPriceFlag.Name) {
gasprice = utils.GlobalBig(ctx, utils.LegacyMinerGasPriceFlag.Name)
}
- txpool := backend.TxPool()
- if txpool == nil {
- utils.Fatalf("Ethereum service not running: %v", err)
- }
- txpool.SetGasPrice(gasprice)
-
+ ethBackend.TxPool().SetGasPrice(gasprice)
+ // start mining
threads := ctx.GlobalInt(utils.MinerThreadsFlag.Name)
if ctx.GlobalIsSet(utils.LegacyMinerThreadsFlag.Name) && !ctx.GlobalIsSet(utils.MinerThreadsFlag.Name) {
threads = ctx.GlobalInt(utils.LegacyMinerThreadsFlag.Name)
log.Warn("The flag --minerthreads is deprecated and will be removed in the future, please use --miner.threads")
}
- if err := backend.StartMining(threads); err != nil {
+ if err := ethBackend.StartMining(threads); err != nil {
utils.Fatalf("Failed to start mining: %v", err)
}
}
diff --git a/eth/api_backend.go b/eth/api_backend.go
index 1b0e841d80db..0e91691d8f51 100644
--- a/eth/api_backend.go
+++ b/eth/api_backend.go
@@ -318,10 +318,6 @@ func (b *EthAPIBackend) Engine() consensus.Engine {
return b.eth.engine
}
-func (b *EthAPIBackend) GetBlockByNumber(ctx context.Context, number uint64) (*types.Block, error) {
- return b.eth.blockchain.GetBlockByNumber(number), nil
-}
-
func (b *EthAPIBackend) CurrentHeader() *types.Header {
return b.eth.blockchain.CurrentHeader()
}
diff --git a/ethstats/ethstats.go b/ethstats/ethstats.go
index 2f8766ef8cca..b1e42d18da1e 100644
--- a/ethstats/ethstats.go
+++ b/ethstats/ethstats.go
@@ -22,6 +22,10 @@ import (
"encoding/json"
"errors"
"fmt"
+ "github.com/ethereum/go-ethereum/eth/downloader"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/ethereum/go-ethereum/miner"
+ "github.com/ethereum/go-ethereum/rpc"
"math/big"
"net/http"
"regexp"
@@ -36,7 +40,6 @@ import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth"
- "github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/les"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
@@ -56,14 +59,29 @@ const (
chainHeadChanSize = 10
)
-// Backend encompasses the backend behaviors needed for the ethstats service.
-type Backend ethapi.Backend
+type backend interface{
+ SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription
+ SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription
+ CurrentHeader() *types.Header
+ HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error)
+ GetTd(blockHash common.Hash) *big.Int
+ Stats() (pending int, queued int)
+ Downloader() *downloader.Downloader
+}
+
+type fullNodeBackend interface{
+ backend
+ Miner() *miner.Miner
+ BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error)
+ CurrentBlock() *types.Block
+ SuggestPrice(ctx context.Context) (*big.Int, error)
+}
// Service implements an Ethereum netstats reporting daemon that pushes local
// chain statistics up to a monitoring server.
type Service struct {
server *p2p.Server // Peer-to-peer server to retrieve networking infos
- backend Backend
+ backend backend
engine consensus.Engine // Consensus engine to retrieve variadic block fields
node string // Name of the node to display on the monitoring page
@@ -75,7 +93,7 @@ type Service struct {
}
// New returns a monitoring service ready for stats reporting.
-func New(node *node.Node, backend Backend, engine consensus.Engine, url string) error {
+func New(node *node.Node, backend backend, engine consensus.Engine, url string) error {
// Parse the netstats connection url
re := regexp.MustCompile("([^:@]*)(:([^@]*))?@(.+)")
parts := re.FindStringSubmatch(url)
@@ -530,18 +548,30 @@ func (s *Service) assembleBlockStats(block *types.Block) *blockStats {
uncles []*types.Header
)
- // Full nodes have all needed information available
- if block == nil {
- block = s.backend.CurrentBlock()
- }
- header = block.Header()
- td = s.backend.GetTd(header.Hash()) // TODO is it okay to just call `GetTD` with just the hash and not number?
+ // check if backend is a full node
+ fullBackend, ok := s.backend.(fullNodeBackend)
+ if ok {
+ if block == nil {
+ block = fullBackend.CurrentBlock()
+ }
+ header = block.Header()
+ td = fullBackend.GetTd(header.Hash())
- txs = make([]txStats, len(block.Transactions()))
- for i, tx := range block.Transactions() {
- txs[i].Hash = tx.Hash()
+ txs = make([]txStats, len(block.Transactions()))
+ for i, tx := range block.Transactions() {
+ txs[i].Hash = tx.Hash()
+ }
+ uncles = block.Uncles()
+ } else {
+ // Light nodes would need on-demand lookups for transactions/uncles, skip
+ if block != nil {
+ header = block.Header()
+ } else {
+ header = s.backend.CurrentHeader()
+ }
+ td = s.backend.GetTd(header.Hash())
+ txs = []txStats{}
}
- uncles = block.Uncles()
// Assemble and return the block stats
author, _ := s.engine.Author(header)
@@ -585,12 +615,16 @@ func (s *Service) reportHistory(conn *websocket.Conn, list []uint64) error {
// Gather the batch of blocks to report
history := make([]*blockStats, len(indexes))
for i, number := range indexes {
+ fullBackend, ok := s.backend.(fullNodeBackend)
// Retrieve the next block if it's known to us
- block, err := s.backend.GetBlockByNumber(context.Background(), number)
- if err != nil {
- return err
+ var block *types.Block
+ if ok {
+ block, _ = fullBackend.BlockByNumber(context.Background(), rpc.BlockNumber(number)) // TODO ignore error here ?
+ } else {
+ if header, _ := s.backend.HeaderByNumber(context.Background(), rpc.BlockNumber(number)); header != nil {
+ block = types.NewBlockWithHeader(header)
+ }
}
-
// If we do have the block, add to the history and continue
if block != nil {
history[len(history)-1-i] = s.assembleBlockStats(block)
@@ -652,27 +686,31 @@ type nodeStats struct {
Uptime int `json:"uptime"`
}
-// reportPending retrieves various stats about the node at the networking and
+// reportStats retrieves various stats about the node at the networking and
// mining layer and reports it to the stats server.
func (s *Service) reportStats(conn *websocket.Conn) error {
// Gather the syncing and mining infos from the local miner instance
var (
mining bool
hashrate int
+ syncing bool
+ gasprice int
)
+ // check if backend is a full node
+ fullBackend, ok := s.backend.(fullNodeBackend)
+ if ok {
+ mining = fullBackend.Miner().Mining()
+ hashrate = int(fullBackend.Miner().HashRate())
- mine := s.backend.Miner()
- if mine != nil {
- mining = mine.Mining()
- hashrate = int(s.backend.Miner().HashRate())
- }
-
- sync := s.backend.Downloader().Progress()
- syncing := s.backend.CurrentHeader().Number.Uint64() >= sync.HighestBlock
-
- price, _ := s.backend.SuggestPrice(context.Background())
- gasprice := int(price.Uint64())
+ sync := fullBackend.Downloader().Progress()
+ syncing = fullBackend.CurrentHeader().Number.Uint64() >= sync.HighestBlock
+ price, _ := fullBackend.SuggestPrice(context.Background())
+ gasprice = int(price.Uint64())
+ } else {
+ sync := s.backend.Downloader().Progress()
+ syncing = s.backend.CurrentHeader().Number.Uint64() >= sync.HighestBlock
+ }
// Assemble the node stats and send it to the server
log.Trace("Sending node details to ethstats")
diff --git a/go.sum b/go.sum
index d0e87bd69cc3..7546ca177394 100644
--- a/go.sum
+++ b/go.sum
@@ -218,20 +218,15 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
-gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6 h1:a6cXbcDDUkSBlpnkWV1bJ+vv3mOgQEltEJ2rPxroVu0=
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns=
-gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0=
gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go
index 12faa307171e..c92d8b20c48a 100644
--- a/internal/ethapi/backend.go
+++ b/internal/ethapi/backend.go
@@ -32,7 +32,6 @@ import (
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
- "github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
)
@@ -47,8 +46,8 @@ type Backend interface {
ChainDb() ethdb.Database
AccountManager() *accounts.Manager
ExtRPCEnabled() bool
+ RPCGasCap() uint64 // global gas cap for eth_call over rpc: DoS protection
RPCTxFeeCap() float64 // global tx fee cap for all transaction related APIs
- RPCGasCap() uint64 // global gas cap for eth_call over rpc: DoS protection
// Blockchain API
SetHead(number uint64)
@@ -60,7 +59,6 @@ type Backend interface {
BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error)
BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error)
BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error)
- GetBlockByNumber(ctx context.Context, number uint64) (*types.Block, error)
StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error)
StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error)
GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error)
@@ -78,13 +76,8 @@ type Backend interface {
GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error)
Stats() (pending int, queued int)
TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions)
- TxPool() *core.TxPool
SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription
- // Mining API
- Miner() *miner.Miner
- StartMining(threads int) error
-
// Filter API
BloomStatus() (uint64, uint64)
GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error)
diff --git a/les/api_backend.go b/les/api_backend.go
index 25dde0a2cd57..75bea56da67a 100644
--- a/les/api_backend.go
+++ b/les/api_backend.go
@@ -19,7 +19,6 @@ package les
import (
"context"
"errors"
- "fmt"
"math/big"
"github.com/ethereum/go-ethereum/accounts"
@@ -36,7 +35,6 @@ import (
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/light"
- "github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
)
@@ -290,23 +288,6 @@ func (b *LesApiBackend) Engine() consensus.Engine {
return b.eth.engine
}
-func (b *LesApiBackend) GetBlockByNumber(ctx context.Context, number uint64) (*types.Block, error) {
- header := b.eth.blockchain.GetHeaderByNumber(number)
- return types.NewBlockWithHeader(header), nil // TODO is this okay?
-}
-
func (b *LesApiBackend) CurrentHeader() *types.Header {
return b.eth.blockchain.CurrentHeader()
}
-
-func (b *LesApiBackend) Miner() *miner.Miner {
- return nil
-}
-
-func (b *LesApiBackend) StartMining(threads int) error {
- return fmt.Errorf("Light clients do not support mining") // TODO is this okay?
-}
-
-func (b *LesApiBackend) TxPool() *core.TxPool {
- return nil // TODO is this okay?
-}
From e7602e3feb97d91d061801c3b1fa04caec4fc2d3 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Fri, 10 Jul 2020 15:50:25 +0200
Subject: [PATCH 094/160] go mod tidy
---
go.sum | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/go.sum b/go.sum
index 7546ca177394..d0e87bd69cc3 100644
--- a/go.sum
+++ b/go.sum
@@ -218,15 +218,20 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6 h1:a6cXbcDDUkSBlpnkWV1bJ+vv3mOgQEltEJ2rPxroVu0=
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0=
gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
From 9ee9bbea2a67d79d4c865e587b010f64e565f741 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Mon, 13 Jul 2020 13:46:19 +0200
Subject: [PATCH 095/160] linted
---
cmd/geth/main.go | 2 +-
ethstats/ethstats.go | 17 ++++++++++-------
graphql/graphql_test.go | 2 +-
graphql/service.go | 7 ++++---
internal/ethapi/backend.go | 2 +-
node/rpcstack.go | 2 +-
6 files changed, 18 insertions(+), 14 deletions(-)
diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index 735aeb653db0..71a1c19e1d84 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -19,7 +19,6 @@ package main
import (
"fmt"
- "github.com/ethereum/go-ethereum/eth"
"math"
"os"
godebug "runtime/debug"
@@ -33,6 +32,7 @@ import (
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/console/prompt"
+ "github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/internal/debug"
diff --git a/ethstats/ethstats.go b/ethstats/ethstats.go
index b1e42d18da1e..a32ae71d491f 100644
--- a/ethstats/ethstats.go
+++ b/ethstats/ethstats.go
@@ -22,10 +22,6 @@ import (
"encoding/json"
"errors"
"fmt"
- "github.com/ethereum/go-ethereum/eth/downloader"
- "github.com/ethereum/go-ethereum/event"
- "github.com/ethereum/go-ethereum/miner"
- "github.com/ethereum/go-ethereum/rpc"
"math/big"
"net/http"
"regexp"
@@ -40,10 +36,14 @@ import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth"
+ "github.com/ethereum/go-ethereum/eth/downloader"
+ "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/les"
"github.com/ethereum/go-ethereum/log"
+ "github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p"
+ "github.com/ethereum/go-ethereum/rpc"
"github.com/gorilla/websocket"
)
@@ -59,7 +59,8 @@ const (
chainHeadChanSize = 10
)
-type backend interface{
+// backend encompasses the bare-minimum functionality needed for ethstats reporting
+type backend interface {
SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription
SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription
CurrentHeader() *types.Header
@@ -69,7 +70,9 @@ type backend interface{
Downloader() *downloader.Downloader
}
-type fullNodeBackend interface{
+// fullNodeBackend encompasses the functionality necessary for a full node
+// reporting to ethstats
+type fullNodeBackend interface {
backend
Miner() *miner.Miner
BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error)
@@ -693,7 +696,7 @@ func (s *Service) reportStats(conn *websocket.Conn) error {
var (
mining bool
hashrate int
- syncing bool
+ syncing bool
gasprice int
)
// check if backend is a full node
diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go
index 366685151014..203bdea82bde 100644
--- a/graphql/graphql_test.go
+++ b/graphql/graphql_test.go
@@ -122,7 +122,7 @@ func createGQLService(t *testing.T, stack *node.Node, endpoint string) {
}
// create gql service
- err = New(stack, ethBackend.APIBackend,[]string{}, []string{})
+ err = New(stack, ethBackend.APIBackend, []string{}, []string{})
if err != nil {
t.Fatalf("could not create graphql service: %v", err)
}
diff --git a/graphql/service.go b/graphql/service.go
index 61d097bb3f25..302fd678f1d9 100644
--- a/graphql/service.go
+++ b/graphql/service.go
@@ -18,6 +18,7 @@ package graphql
import (
"fmt"
+
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
@@ -46,9 +47,9 @@ func newHandler(stack *node.Node, backend ethapi.Backend, cors, vhosts []string)
h := &relay.Handler{Schema: s}
handler := node.NewHTTPHandlerStack(h, cors, vhosts)
- endpoint := stack.RegisterPath("/graphql/ui", GraphiQL{})
- endpoint = stack.RegisterPath("/graphql", handler)
- endpoint = stack.RegisterPath("/graphql/", handler)
+ _ = stack.RegisterPath("/graphql/ui", GraphiQL{})
+ _ = stack.RegisterPath("/graphql", handler)
+ endpoint := stack.RegisterPath("/graphql/", handler)
if endpoint != "" {
log.Info("GraphQL configured on endpoint", "endpoint", fmt.Sprintf("http://%s/graphql", endpoint))
diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go
index c92d8b20c48a..10e716bf200d 100644
--- a/internal/ethapi/backend.go
+++ b/internal/ethapi/backend.go
@@ -46,7 +46,7 @@ type Backend interface {
ChainDb() ethdb.Database
AccountManager() *accounts.Manager
ExtRPCEnabled() bool
- RPCGasCap() uint64 // global gas cap for eth_call over rpc: DoS protection
+ RPCGasCap() uint64 // global gas cap for eth_call over rpc: DoS protection
RPCTxFeeCap() float64 // global tx fee cap for all transaction related APIs
// Blockchain API
diff --git a/node/rpcstack.go b/node/rpcstack.go
index 6d4c536caa0f..43716a4dbd66 100644
--- a/node/rpcstack.go
+++ b/node/rpcstack.go
@@ -36,7 +36,7 @@ import (
type serverMap map[string]*httpServer // Stores information about all http servers (if any) by their endpoint, including http, ws, and graphql
type httpServer struct {
- srvMux http.ServeMux
+ srvMux http.ServeMux
handler http.Handler
Srv *rpc.Server
From b26ea835bbefc1bffa0f8e512212aed54c3b4f3c Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Wed, 15 Jul 2020 12:58:34 +0200
Subject: [PATCH 096/160] changes requested by gary
---
les/server.go | 4 ----
miner/stress_clique.go | 10 +++++-----
2 files changed, 5 insertions(+), 9 deletions(-)
diff --git a/les/server.go b/les/server.go
index b856d24306ff..ec856c977c7c 100644
--- a/les/server.go
+++ b/les/server.go
@@ -21,7 +21,6 @@ import (
"time"
"github.com/ethereum/go-ethereum/common/mclock"
- "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/les/flowcontrol"
"github.com/ethereum/go-ethereum/light"
@@ -217,9 +216,6 @@ func (s *LesServer) Stop() error {
return nil
}
-func (s *LesServer) SetBloomBitsIndexer(bloomIndexer *core.ChainIndexer) {
-}
-
// capacityManagement starts an event handler loop that updates the recharge curve of
// the client manager and adjusts the client pool's size according to the total
// capacity updates coming from the client manager
diff --git a/miner/stress_clique.go b/miner/stress_clique.go
index 143ce3f5eb2e..d09538050164 100644
--- a/miner/stress_clique.go
+++ b/miner/stress_clique.go
@@ -22,7 +22,6 @@ package main
import (
"bytes"
"crypto/ecdsa"
- "github.com/ethereum/go-ethereum/internal/ethapi"
"io/ioutil"
"math/big"
"math/rand"
@@ -36,6 +35,7 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth"
+ "github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p"
@@ -60,8 +60,8 @@ func main() {
genesis := makeGenesis(faucets, sealers)
var (
- nodes []struct{
- node *node.Node
+ nodes []struct {
+ node *node.Node
backend ethapi.Backend
}
enodes []*enode.Node
@@ -83,8 +83,8 @@ func main() {
node.Server().AddPeer(n)
}
// Start tracking the node and it's enode
- nodes = append(nodes, struct{
- node *node.Node
+ nodes = append(nodes, struct {
+ node *node.Node
backend ethapi.Backend
}{
node,
From dd06152fbf027d704ec9d3d4554ba98887af37b2 Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Mon, 13 Jul 2020 12:56:41 +0200
Subject: [PATCH 097/160] node: unexport CreateHTTPServer
---
node/api.go | 4 ++--
node/node.go | 6 +++---
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/node/api.go b/node/api.go
index 55956f63ded0..60a960fe0e87 100644
--- a/node/api.go
+++ b/node/api.go
@@ -204,7 +204,7 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
handler := NewHTTPHandlerStack(httpServer.Srv, httpServer.CorsAllowedOrigins, httpServer.Vhosts)
httpServer.srvMux.Handle("/", handler)
// create HTTP server
- if err := api.node.CreateHTTPServer(httpServer, false); err != nil {
+ if err := api.node.createHTTPServer(httpServer, false); err != nil {
return false, err
}
// register the HTTP server
@@ -293,7 +293,7 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
handler := wsServer.Srv.WebsocketHandler(wsServer.WsOrigins)
wsServer.srvMux.Handle("/", handler)
// create the HTTP server
- if err := api.node.CreateHTTPServer(wsServer, api.node.config.WSExposeAll); err != nil {
+ if err := api.node.createHTTPServer(wsServer, api.node.config.WSExposeAll); err != nil {
return false, err
}
// register the HTTP server
diff --git a/node/node.go b/node/node.go
index 4692d81172d8..25daaf3fa6da 100644
--- a/node/node.go
+++ b/node/node.go
@@ -228,8 +228,8 @@ func (n *Node) ExistingHTTPServer(endpoint string) *httpServer {
return nil
}
-// CreateHTTPServer creates an http.Server and adds it to the given httpServer.
-func (n *Node) CreateHTTPServer(h *httpServer, exposeAll bool) error {
+// createHTTPServer creates an http.Server and adds it to the given httpServer.
+func (n *Node) createHTTPServer(h *httpServer, exposeAll bool) error {
// register apis and create handler stack
err := RegisterApisFromWhitelist(n.rpcAPIs, h.Whitelist, h.Srv, exposeAll)
if err != nil {
@@ -371,7 +371,7 @@ func (n *Node) configureRPC() error {
server.srvMux.Handle("/", handler)
}
// create the HTTP server
- if err := n.CreateHTTPServer(server, false); err != nil {
+ if err := n.createHTTPServer(server, false); err != nil {
return err
}
}
From 57ffd7c91eab5a8f7a187221905227183e4b5bfe Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Mon, 13 Jul 2020 12:57:00 +0200
Subject: [PATCH 098/160] graphql: don't check for HTTP server creation
The test request will just fail if the server isn't there.
---
graphql/graphql_test.go | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go
index 203bdea82bde..091102889144 100644
--- a/graphql/graphql_test.go
+++ b/graphql/graphql_test.go
@@ -68,15 +68,10 @@ func TestGraphQLHTTPOnSamePort_GQLRequest_Successful(t *testing.T) {
func TestGraphQLHTTPOnSamePort_GQLRequest_Unsuccessful(t *testing.T) {
stack := createNode(t, false)
defer stack.Close()
- // start node
if err := stack.Start(); err != nil {
t.Fatalf("could not start node: %v", err)
}
- // make sure GQL is not enabled
- server := stack.ExistingHTTPServer("127.0.0.1:9393")
- if server == nil {
- t.Fatalf("server was not created on the given endpoint")
- }
+
// create http request
body := strings.NewReader("{\"query\": \"{block{number}}\",\"variables\": null}")
gqlReq, err := http.NewRequest(http.MethodPost, fmt.Sprintf("http://%s/graphql", "127.0.0.1:9393"), body)
From c8b01c431e22549d4df1cdeaf87ce2869a1f1ff5 Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Mon, 13 Jul 2020 12:58:11 +0200
Subject: [PATCH 099/160] node: unexport ExistingHTTPServer
---
node/api.go | 2 +-
node/node.go | 4 ++--
node/node_test.go | 10 +++++-----
node/rpcstack_test.go | 2 +-
4 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/node/api.go b/node/api.go
index 60a960fe0e87..810697fafb35 100644
--- a/node/api.go
+++ b/node/api.go
@@ -263,7 +263,7 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
}
}
// check if an HTTP server exists on the given endpoint, and if so, enable websocket on that HTTP server
- existingServer := api.node.ExistingHTTPServer(endpoint)
+ existingServer := api.node.existingHTTPServer(endpoint)
if existingServer != nil {
atomic.StoreInt32(&existingServer.WSAllowed, 1)
existingServer.WsOrigins = origins
diff --git a/node/node.go b/node/node.go
index 25daaf3fa6da..a91a3cc50b5d 100644
--- a/node/node.go
+++ b/node/node.go
@@ -220,8 +220,8 @@ func (n *Node) RegisterPath(path string, handler http.Handler) string {
return ""
}
-// ExistingHTTPServer checks if an HTTP server is already configured on the given endpoint.
-func (n *Node) ExistingHTTPServer(endpoint string) *httpServer {
+// existingHTTPServer checks if an HTTP server is already configured on the given endpoint.
+func (n *Node) existingHTTPServer(endpoint string) *httpServer {
if server, exists := n.httpServers[endpoint]; exists {
return server
}
diff --git a/node/node_test.go b/node/node_test.go
index d1a40658a8f9..5f10e9ffcab9 100644
--- a/node/node_test.go
+++ b/node/node_test.go
@@ -394,13 +394,13 @@ func TestRegisterHTTPServer(t *testing.T) {
}
endpointNoop := fmt.Sprintf("%s:%d", noop.host, noop.port)
- if srv1 != stack.ExistingHTTPServer(endpoint1) {
+ if srv1 != stack.existingHTTPServer(endpoint1) {
t.Fatalf("server %v was not properly registered on the given endpoint %s", srv1, endpoint1)
}
- if srv2 != stack.ExistingHTTPServer(endpoint2) {
+ if srv2 != stack.existingHTTPServer(endpoint2) {
t.Fatalf("server %v was not properly registered on the given endpoint %s", srv2, endpoint2)
}
- if noop == stack.ExistingHTTPServer(endpointNoop) {
+ if noop == stack.existingHTTPServer(endpointNoop) {
t.Fatalf("server %v was incorrectly registered on the given endpoint %s", noop, endpointNoop)
}
}
@@ -472,7 +472,7 @@ func TestHTTPServerCreateAndStop(t *testing.T) {
t.Fatalf("node's http server is not configured to handle both rpc and ws")
}
node1.stopServer(server)
- if node1.ExistingHTTPServer(server.endpoint) != nil {
+ if node1.existingHTTPServer(server.endpoint) != nil {
t.Fatalf("failed to remove server %v from node after stopping it", server)
}
}
@@ -493,7 +493,7 @@ func TestHTTPServerCreateAndStop(t *testing.T) {
t.Fatalf("both rpc and ws allowed on a single http server")
}
node2.stopServer(server)
- if node2.ExistingHTTPServer(server.endpoint) != nil {
+ if node2.existingHTTPServer(server.endpoint) != nil {
t.Fatalf("failed to remove server %v from node after stopping it", server)
}
}
diff --git a/node/rpcstack_test.go b/node/rpcstack_test.go
index 3dfaf53ed6bc..c00c4d665896 100644
--- a/node/rpcstack_test.go
+++ b/node/rpcstack_test.go
@@ -59,7 +59,7 @@ func TestWSAllowed(t *testing.T) {
t.Fatalf("could not start node: %v", err)
}
// check that server was configured on the given endpoint
- server := stack.ExistingHTTPServer(fmt.Sprintf("%s:%d", DefaultHTTPHost, 9393))
+ server := stack.existingHTTPServer(fmt.Sprintf("%s:%d", DefaultHTTPHost, 9393))
if server == nil {
t.Fatalf("server was not started on the given endpoint: %v", err)
}
From 783ad61f28587007c17acf4ace1fe17ff53d302a Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Tue, 21 Jul 2020 12:02:01 +0200
Subject: [PATCH 100/160] node: add new lifecycle docs
---
node/doc.go | 37 +++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/node/doc.go b/node/doc.go
index e3cc58e5f49c..b257f412fed1 100644
--- a/node/doc.go
+++ b/node/doc.go
@@ -22,6 +22,43 @@ resources to provide RPC APIs. Services can also offer devp2p protocols, which a
up to the devp2p network when the node instance is started.
+Node Lifecycle
+
+The Node object has a lifecycle consisting of three basic states, INITIALIZING, RUNNING
+and CLOSED.
+
+
+ ●───────┐
+ New()
+ │
+ ▼
+ INITIALIZING ────Start()─┐
+ │ │
+ │ ▼
+ Close() RUNNING
+ │ │
+ ▼ │
+ CLOSED ◀──────Close()─┘
+
+
+Creating a Node allocates basic resources such as the data directory and returns the node
+in its INITIALIZING state. Lifecycle objects, RPC APIs and peer-to-peer networking
+protocols can be registered in this state. Basic operations such as opening a key-value
+database are permitted while initializing.
+
+Once everything is registered, the node can be started, which moves it into the RUNNING
+state. Starting the node starts all registered Lifecycle objects and enables RPC and
+peer-to-peer networking. Note that no additional Lifecycles, APIs or p2p protocols can be
+registered while the node is running.
+
+Closing the node releases all held resources. The actions performed by Close depend on the
+state it was in. When closing a node in INITIALIZING state, resources related to the data
+directory are released. If the node was RUNNING, closing it also stops all Lifecycle
+objects and shuts down RPC and peer-to-peer networking.
+
+You must always call Close on Node, even if the node was not started.
+
+
Resources Managed By Node
All file-system resources used by a node instance are located in a directory called the
From af82314eb1861e97a7b46f718a45007aa988222e Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Tue, 21 Jul 2020 12:02:30 +0200
Subject: [PATCH 101/160] node: fix comment on Start
---
node/node.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/node/node.go b/node/node.go
index a91a3cc50b5d..2a848568c7bf 100644
--- a/node/node.go
+++ b/node/node.go
@@ -262,7 +262,7 @@ func (n *Node) running() bool {
return n.server.Running()
}
-// Start creates a live P2P node and starts running it.
+// Start starts all registered lifecycles, RPC services and p2p networking.
func (n *Node) Start() error {
n.lock.Lock()
defer n.lock.Unlock()
From 33ffe5bcac6c3c2e25901b404252fc3250d37fb8 Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Tue, 21 Jul 2020 12:25:48 +0200
Subject: [PATCH 102/160] node: move datadir cleanup from Stop to Close
---
node/node.go | 75 +++++++++++++++++++++++++----------------------
node/node_test.go | 11 ++-----
2 files changed, 43 insertions(+), 43 deletions(-)
diff --git a/node/node.go b/node/node.go
index 2a848568c7bf..43f587fb6009 100644
--- a/node/node.go
+++ b/node/node.go
@@ -83,22 +83,13 @@ func New(conf *Config) (*Node, error) {
if strings.HasSuffix(conf.Name, ".ipc") {
return nil, errors.New(`Config.Name cannot end in ".ipc"`)
}
- // Ensure that the AccountManager method works before the node has started.
- // We rely on this in cmd/geth.
- am, ephemeralKeystore, err := makeAccountManager(conf)
- if err != nil {
- return nil, err
- }
if conf.Logger == nil {
conf.Logger = log.New()
}
- // Note: any interaction with Config that would create/touch files
- // in the data directory or instance directory is delayed until Start.
+
node := &Node{
- accman: am,
- ephemeralKeystore: ephemeralKeystore,
- config: conf,
- httpServers: make(serverMap),
+ config: conf,
+ httpServers: make(serverMap),
ipc: &httpServer{
endpoint: conf.IPCEndpoint(),
},
@@ -107,6 +98,19 @@ func New(conf *Config) (*Node, error) {
log: conf.Logger,
}
+ // Acquire the instance directory lock.
+ if err := node.openDataDir(); err != nil {
+ return nil, err
+ }
+ // Ensure that the AccountManager method works before the node has started.
+ // We rely on this in cmd/geth.
+ am, ephemeralKeystore, err := makeAccountManager(conf)
+ if err != nil {
+ return nil, err
+ }
+ node.accman = am
+ node.ephemeralKeystore = ephemeralKeystore
+
// Initialize the p2p server. This creates the node key and
// discovery databases.
node.server = &p2p.Server{Config: conf.P2P}
@@ -167,13 +171,24 @@ func New(conf *Config) (*Node, error) {
func (n *Node) Close() error {
var errs []error
- // Terminate all subsystems and collect any errors
- if err := n.Stop(); err != nil && err != ErrNodeStopped {
- errs = append(errs, err)
+ if n.server != nil && n.running() {
+ // The node is in RUNNING state, stop lifecycles first.
+ if err := n.Stop(); err != nil && err != ErrNodeStopped {
+ errs = append(errs, err)
+ }
}
+
+ // Release resources acquired by New().
+ n.closeDataDir()
if err := n.accman.Close(); err != nil {
errs = append(errs, err)
}
+ if n.ephemeralKeystore != "" {
+ if err := os.RemoveAll(n.ephemeralKeystore); err != nil {
+ errs = append(errs, err)
+ }
+ }
+
// Report any errors that might have occurred
switch len(errs) {
case 0:
@@ -271,9 +286,6 @@ func (n *Node) Start() error {
if n.running() {
return ErrNodeRunning
}
- if err := n.openDataDir(); err != nil {
- return err
- }
// Start the p2p node
if err := n.server.Start(); err != nil {
@@ -349,6 +361,16 @@ func (n *Node) openDataDir() error {
return nil
}
+func (n *Node) closeDataDir() {
+ // Release instance directory lock.
+ if n.instanceDirLock != nil {
+ if err := n.instanceDirLock.Release(); err != nil {
+ n.log.Error("Can't release datadir lock", "err", err)
+ }
+ n.instanceDirLock = nil
+ }
+}
+
// configureRPC is a helper method to configure all the various RPC endpoints during node
// startup. It's not meant to be called at any time afterwards as it makes certain
// assumptions about the state of the node.
@@ -487,29 +509,12 @@ func (n *Node) Stop() error {
n.server.Stop()
n.server = nil
- // Release instance directory lock.
- if n.instanceDirLock != nil {
- if err := n.instanceDirLock.Release(); err != nil {
- n.log.Error("Can't release datadir lock", "err", err)
- }
- n.instanceDirLock = nil
- }
-
// unblock n.Wait
close(n.stop)
- // Remove the keystore if it was created ephemerally.
- var keystoreErr error
- if n.ephemeralKeystore != "" {
- keystoreErr = os.RemoveAll(n.ephemeralKeystore)
- }
-
if len(failure.Services) > 0 {
return failure
}
- if keystoreErr != nil {
- return keystoreErr
- }
return nil
}
diff --git a/node/node_test.go b/node/node_test.go
index 5f10e9ffcab9..4435265635ea 100644
--- a/node/node_test.go
+++ b/node/node_test.go
@@ -97,13 +97,8 @@ func TestNodeUsedDataDir(t *testing.T) {
defer original.Stop()
// Create a second node based on the same data directory and ensure failure
- duplicate, err := New(&Config{DataDir: dir})
- if err != nil {
- t.Fatalf("failed to create duplicate protocol stack: %v", err)
- }
- defer duplicate.Close()
-
- if err := duplicate.Start(); err != ErrDatadirUsed {
+ _, err = New(&Config{DataDir: dir})
+ if err != ErrDatadirUsed {
t.Fatalf("duplicate datadir failure mismatch: have %v, want %v", err, ErrDatadirUsed)
}
}
@@ -406,7 +401,7 @@ func TestRegisterHTTPServer(t *testing.T) {
}
// Tests whether a handler can be successfully mounted on the canonical HTTP server
-// on the given path
+// on the givenq path
func TestRegisterPath_Successful(t *testing.T) {
node := createNode(t, 7878, 7979)
From 767e3b173b8d9f734eb6260b71db2ed3c010113f Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Tue, 21 Jul 2020 12:29:50 +0200
Subject: [PATCH 103/160] node: simplify stop channel
---
node/node.go | 31 ++++++++++---------------------
1 file changed, 10 insertions(+), 21 deletions(-)
diff --git a/node/node.go b/node/node.go
index 43f587fb6009..0fdcbc1c6a6d 100644
--- a/node/node.go
+++ b/node/node.go
@@ -48,15 +48,15 @@ type Node struct {
log log.Logger
ephemeralKeystore string // if non-empty, the key directory that will be removed by Stop
instanceDirLock fileutil.Releaser // prevents concurrent use of instance directory
+ stop chan struct{} // Channel to wait for termination notifications
lock sync.RWMutex
- stop chan struct{} // Channel to wait for termination notifications
- server *p2p.Server // Currently running P2P networking layer
- lifecycles []Lifecycle // All registered backends, services, and auxiliary services that have a lifecycle
- httpServers serverMap // serverMap stores information about the node's rpc, ws, and graphQL http servers.
- inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
- rpcAPIs []rpc.API // List of APIs currently provided by the node
- ipc *httpServer // Stores information about the ipc http server
+ server *p2p.Server // Currently running P2P networking layer
+ lifecycles []Lifecycle // All registered backends, services, and auxiliary services that have a lifecycle
+ httpServers serverMap // serverMap stores information about the node's rpc, ws, and graphQL http servers.
+ inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
+ rpcAPIs []rpc.API // List of APIs currently provided by the node
+ ipc *httpServer // Stores information about the ipc http server
}
// New creates a new P2P node, ready for protocol registration.
@@ -96,6 +96,7 @@ func New(conf *Config) (*Node, error) {
inprocHandler: rpc.NewServer(),
eventmux: new(event.TypeMux),
log: conf.Logger,
+ stop: make(chan struct{}),
}
// Acquire the instance directory lock.
@@ -310,9 +311,6 @@ func (n *Node) Start() error {
}
started = append(started, lifecycle)
}
-
- // Finish initializing the startup
- n.stop = make(chan struct{})
return nil
}
@@ -518,18 +516,9 @@ func (n *Node) Stop() error {
return nil
}
-// Wait blocks the thread until the node is stopped. If the node is not running
-// at the time of invocation, the method immediately returns.
+// Wait blocks until the node is stopped.
func (n *Node) Wait() {
- n.lock.RLock()
- if n.server == nil {
- n.lock.RUnlock()
- return
- }
- stop := n.stop
- n.lock.RUnlock()
-
- <-stop
+ <-n.stop
}
// Attach creates an RPC client attached to an in-process API handler.
From ce38ec6dbc8ec2f416db32e5dc969dce6785700e Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Tue, 21 Jul 2020 13:45:25 +0200
Subject: [PATCH 104/160] node: remove Stop
This changes the Node lifecycle API to match the new documentation.
---
node/node.go | 62 +++++++++++++++++++++++----------------
node/node_example_test.go | 2 +-
node/node_test.go | 46 ++++++++++++++++-------------
3 files changed, 63 insertions(+), 47 deletions(-)
diff --git a/node/node.go b/node/node.go
index 0fdcbc1c6a6d..69be3aef86b6 100644
--- a/node/node.go
+++ b/node/node.go
@@ -51,6 +51,7 @@ type Node struct {
stop chan struct{} // Channel to wait for termination notifications
lock sync.RWMutex
+ runstate int
server *p2p.Server // Currently running P2P networking layer
lifecycles []Lifecycle // All registered backends, services, and auxiliary services that have a lifecycle
httpServers serverMap // serverMap stores information about the node's rpc, ws, and graphQL http servers.
@@ -59,6 +60,12 @@ type Node struct {
ipc *httpServer // Stores information about the ipc http server
}
+const (
+ initializingState = iota
+ runningState
+ stoppedState
+)
+
// New creates a new P2P node, ready for protocol registration.
func New(conf *Config) (*Node, error) {
// Copy config and resolve the datadir so future changes to the current
@@ -170,11 +177,16 @@ func New(conf *Config) (*Node, error) {
// Close stops the Node and releases resources acquired in
// Node constructor New.
func (n *Node) Close() error {
- var errs []error
+ n.lock.Lock()
+ defer n.lock.Unlock()
- if n.server != nil && n.running() {
- // The node is in RUNNING state, stop lifecycles first.
- if err := n.Stop(); err != nil && err != ErrNodeStopped {
+ var errs []error
+ switch n.runstate {
+ case stoppedState:
+ return ErrNodeStopped
+ case runningState:
+ // The node was started, release resources acquired by Start().
+ if err := n.stopServices(); err != nil {
errs = append(errs, err)
}
}
@@ -189,8 +201,12 @@ func (n *Node) Close() error {
errs = append(errs, err)
}
}
+ n.runstate = stoppedState
+
+ // Unblock n.Wait.
+ close(n.stop)
- // Report any errors that might have occurred
+ // Report any errors that might have occurred.
switch len(errs) {
case 0:
return nil
@@ -273,19 +289,17 @@ func (n *Node) createHTTPServer(h *httpServer, exposeAll bool) error {
return nil
}
-// running returns true if the node's p2p server is already running.
-func (n *Node) running() bool {
- return n.server.Running()
-}
-
// Start starts all registered lifecycles, RPC services and p2p networking.
func (n *Node) Start() error {
n.lock.Lock()
defer n.lock.Unlock()
- // Short circuit if the node's already running
- if n.running() {
+ // Node can only be started when it
+ switch n.runstate {
+ case runningState:
return ErrNodeRunning
+ case stoppedState:
+ return ErrNodeStopped
}
// Start the p2p node
@@ -298,6 +312,7 @@ func (n *Node) Start() error {
if err := n.configureRPC(); err != nil {
n.httpServers.Stop()
n.server.Stop()
+ n.runstate = stoppedState
return err
}
@@ -307,10 +322,13 @@ func (n *Node) Start() error {
if err := lifecycle.Start(); err != nil {
stopLifecycles(started)
n.server.Stop()
+ n.runstate = stoppedState
return err
}
started = append(started, lifecycle)
}
+
+ n.runstate = runningState
return nil
}
@@ -487,15 +505,11 @@ func (n *Node) stopServer(server *httpServer) {
delete(n.httpServers, server.endpoint)
}
-// Stop terminates a running node along with all it's services. In the node was
-// not started, an error is returned.
-func (n *Node) Stop() error {
- n.lock.Lock()
- defer n.lock.Unlock()
-
- // Short circuit if the node's not running
- if n.server == nil || !n.running() {
- return ErrNodeStopped
+// stopServices terminates running services, RPC and p2p networking.
+// It is the inverse of Start.
+func (n *Node) stopServices() error {
+ if n.runstate != runningState {
+ panic("call to stopServices on node that isn't running")
}
// Terminate the API, services and the p2p server.
@@ -503,13 +517,9 @@ func (n *Node) Stop() error {
n.rpcAPIs = nil
failure := new(StopError)
failure.Services = stopLifecycles(n.lifecycles)
-
n.server.Stop()
n.server = nil
- // unblock n.Wait
- close(n.stop)
-
if len(failure.Services) > 0 {
return failure
}
@@ -595,6 +605,8 @@ func (n *Node) EventMux() *event.TypeMux {
// previous can be found) from within the node's instance directory. If the node is
// ephemeral, a memory database is returned.
func (n *Node) OpenDatabase(name string, cache, handles int, namespace string) (ethdb.Database, error) {
+ // TODO: track databases so they can be closed later.
+
if n.config.DataDir == "" {
return rawdb.NewMemoryDatabase(), nil
}
diff --git a/node/node_example_test.go b/node/node_example_test.go
index 6ad74aaca885..d54fe03067df 100644
--- a/node/node_example_test.go
+++ b/node/node_example_test.go
@@ -50,7 +50,7 @@ func ExampleLifecycle() {
if err := stack.Start(); err != nil {
log.Fatalf("Failed to start the protocol stack: %v", err)
}
- if err := stack.Stop(); err != nil {
+ if err := stack.Close(); err != nil {
log.Fatalf("Failed to stop the protocol stack: %v", err)
}
// Output:
diff --git a/node/node_test.go b/node/node_test.go
index 4435265635ea..38222d91ae93 100644
--- a/node/node_test.go
+++ b/node/node_test.go
@@ -45,20 +45,28 @@ func testNodeConfig() *Config {
}
}
-// Tests that an empty protocol stack can be started and stopped.
-func TestNodeLifeCycle(t *testing.T) {
+// Tests that an empty protocol stack can be closed more than once.
+func TestNodeCloseMultipleTimes(t *testing.T) {
stack, err := New(testNodeConfig())
if err != nil {
t.Fatalf("failed to create protocol stack: %v", err)
}
- defer stack.Close()
+ stack.Close()
// Ensure that a stopped node can be stopped again
for i := 0; i < 3; i++ {
- if err := stack.Stop(); err != ErrNodeStopped {
+ if err := stack.Close(); err != ErrNodeStopped {
t.Fatalf("iter %d: stop failure mismatch: have %v, want %v", i, err, ErrNodeStopped)
}
}
+}
+
+func TestNodeStartMultipleTimes(t *testing.T) {
+ stack, err := New(testNodeConfig())
+ if err != nil {
+ t.Fatalf("failed to create protocol stack: %v", err)
+ }
+
// Ensure that a node can be successfully started, but only once
if err := stack.Start(); err != nil {
t.Fatalf("failed to start node: %v", err)
@@ -67,10 +75,10 @@ func TestNodeLifeCycle(t *testing.T) {
t.Fatalf("start failure mismatch: have %v, want %v ", err, ErrNodeRunning)
}
// Ensure that a node can be stopped, but only once
- if err := stack.Stop(); err != nil {
+ if err := stack.Close(); err != nil {
t.Fatalf("failed to stop node: %v", err)
}
- if err := stack.Stop(); err != ErrNodeStopped {
+ if err := stack.Close(); err != ErrNodeStopped {
t.Fatalf("stop failure mismatch: have %v, want %v ", err, ErrNodeStopped)
}
}
@@ -90,11 +98,9 @@ func TestNodeUsedDataDir(t *testing.T) {
t.Fatalf("failed to create original protocol stack: %v", err)
}
defer original.Close()
-
if err := original.Start(); err != nil {
t.Fatalf("failed to start original protocol stack: %v", err)
}
- defer original.Stop()
// Create a second node based on the same data directory and ensure failure
_, err = New(&Config{DataDir: dir})
@@ -212,7 +218,7 @@ func TestLifecycleLifeCycle(t *testing.T) {
}
}
// Stop the node and check that all services have been stopped
- if err := stack.Stop(); err != nil {
+ if err := stack.Close(); err != nil {
t.Fatalf("failed to stop protocol stack: %v", err)
}
for id := range lifecycles {
@@ -224,7 +230,7 @@ func TestLifecycleLifeCycle(t *testing.T) {
// Tests that if a Lifecycle fails to start, all others started before it will be
// shut down.
-func TestLifecycleStartupAbortion(t *testing.T) {
+func TestLifecycleStartupError(t *testing.T) {
stack, err := New(testNodeConfig())
if err != nil {
t.Fatalf("failed to create protocol stack: %v", err)
@@ -266,17 +272,15 @@ func TestLifecycleStartupAbortion(t *testing.T) {
stack.RegisterLifecycle(failer)
// Start the protocol stack and ensure all started services stop
- for i := 0; i < 100; i++ {
- if err := stack.Start(); err != failure {
- t.Fatalf("iter %d: stack startup failure mismatch: have %v, want %v", i, err, failure)
- }
- for id := range lifecycles {
- if started[id] && !stopped[id] {
- t.Fatalf("service %s: started but not stopped", id)
- }
- delete(started, id)
- delete(stopped, id)
+ if err := stack.Start(); err != failure {
+ t.Fatalf("stack startup failure mismatch: have %v, want %v", err, failure)
+ }
+ for id := range lifecycles {
+ if started[id] && !stopped[id] {
+ t.Fatalf("service %s: started but not stopped", id)
}
+ delete(started, id)
+ delete(stopped, id)
}
}
@@ -337,7 +341,7 @@ func TestLifecycleTerminationGuarantee(t *testing.T) {
}
}
// Stop the stack, verify failure and check all terminations
- err = stack.Stop()
+ err = stack.Close()
if err, ok := err.(*StopError); !ok {
t.Fatalf("termination failure mismatch: have %v, want StopError", err)
} else {
From cd46fce173e8a990ebe3031082f3875558e16e1d Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Tue, 21 Jul 2020 13:56:29 +0200
Subject: [PATCH 105/160] all: Node.Stop -> Node.Close
---
cmd/faucet/faucet.go | 2 +-
cmd/geth/main.go | 2 +-
cmd/utils/cmd.go | 2 +-
ethclient/ethclient_test.go | 8 ++++----
mobile/geth.go | 12 +++++++-----
p2p/simulations/adapters/exec.go | 2 +-
p2p/simulations/adapters/inproc.go | 2 +-
7 files changed, 16 insertions(+), 14 deletions(-)
diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go
index 65c71ce4eb03..7dc5536eba13 100644
--- a/cmd/faucet/faucet.go
+++ b/cmd/faucet/faucet.go
@@ -265,7 +265,7 @@ func newFaucet(genesis *core.Genesis, port int, enodes []*discv5.Node, network u
// Attach to the client and retrieve and interesting metadatas
api, err := stack.Attach()
if err != nil {
- stack.Stop()
+ stack.Close()
return nil, err
}
client := ethclient.NewClient(api)
diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index 71a1c19e1d84..da0b00c74464 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -432,7 +432,7 @@ func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend) {
if timestamp := time.Unix(int64(done.Latest.Time), 0); time.Since(timestamp) < 10*time.Minute {
log.Info("Synchronisation completed", "latestnum", done.Latest.Number, "latesthash", done.Latest.Hash(),
"age", common.PrettyAge(timestamp))
- stack.Stop()
+ stack.Close()
}
}
}()
diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go
index a40978bcb746..869cf90ea57b 100644
--- a/cmd/utils/cmd.go
+++ b/cmd/utils/cmd.go
@@ -73,7 +73,7 @@ func StartNode(stack *node.Node) {
defer signal.Stop(sigc)
<-sigc
log.Info("Got interrupt, shutting down...")
- go stack.Stop()
+ go stack.Close()
for i := 10; i > 0; i-- {
<-sigc
if i > 1 {
diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go
index b49abe917732..16cf5ce61cee 100644
--- a/ethclient/ethclient_test.go
+++ b/ethclient/ethclient_test.go
@@ -232,7 +232,7 @@ func generateTestChain() (*core.Genesis, []*types.Block) {
func TestHeader(t *testing.T) {
backend, chain := newTestBackend(t)
client, _ := backend.Attach()
- defer backend.Stop()
+ defer backend.Close()
defer client.Close()
tests := map[string]struct {
@@ -276,7 +276,7 @@ func TestHeader(t *testing.T) {
func TestBalanceAt(t *testing.T) {
backend, _ := newTestBackend(t)
client, _ := backend.Attach()
- defer backend.Stop()
+ defer backend.Close()
defer client.Close()
tests := map[string]struct {
@@ -322,7 +322,7 @@ func TestBalanceAt(t *testing.T) {
func TestTransactionInBlockInterrupted(t *testing.T) {
backend, _ := newTestBackend(t)
client, _ := backend.Attach()
- defer backend.Stop()
+ defer backend.Close()
defer client.Close()
ec := NewClient(client)
@@ -340,7 +340,7 @@ func TestTransactionInBlockInterrupted(t *testing.T) {
func TestChainID(t *testing.T) {
backend, _ := newTestBackend(t)
client, _ := backend.Attach()
- defer backend.Stop()
+ defer backend.Close()
defer client.Close()
ec := NewClient(client)
diff --git a/mobile/geth.go b/mobile/geth.go
index 22567a5d107b..42b62b718564 100644
--- a/mobile/geth.go
+++ b/mobile/geth.go
@@ -195,8 +195,8 @@ func NewNode(datadir string, config *NodeConfig) (stack *Node, _ error) {
return &Node{rawStack}, nil
}
-// Close terminates a running node along with all it's services, tearing internal
-// state doen too. It's not possible to restart a closed node.
+// Close terminates a running node along with all it's services, tearing internal state
+// down. It is not possible to restart a closed node.
func (n *Node) Close() error {
return n.node.Close()
}
@@ -206,10 +206,12 @@ func (n *Node) Start() error {
return n.node.Start()
}
-// Stop terminates a running node along with all it's services. If the node was
-// not started, an error is returned.
+// Stop terminates a running node along with all its services. If the node was not started,
+// an error is returned. It is not possible to restart a stopped node.
+//
+// Deprecated: use Close()
func (n *Node) Stop() error {
- return n.node.Stop()
+ return n.node.Close()
}
// GetEthereumClient retrieves a client to access the Ethereum subsystem.
diff --git a/p2p/simulations/adapters/exec.go b/p2p/simulations/adapters/exec.go
index 1f7a21470db0..ccb0d82e7d3d 100644
--- a/p2p/simulations/adapters/exec.go
+++ b/p2p/simulations/adapters/exec.go
@@ -400,7 +400,7 @@ func execP2PNode() {
defer signal.Stop(sigc)
<-sigc
log.Info("Received SIGTERM, shutting down...")
- stack.Stop()
+ stack.Close()
}()
stack.Wait() // Wait for the stack to exit.
}
diff --git a/p2p/simulations/adapters/inproc.go b/p2p/simulations/adapters/inproc.go
index c786b9f9ddc1..36e0a0450ed8 100644
--- a/p2p/simulations/adapters/inproc.go
+++ b/p2p/simulations/adapters/inproc.go
@@ -299,7 +299,7 @@ func (sn *SimNode) Stop() error {
sn.client = nil
}
sn.lock.Unlock()
- return sn.node.Stop()
+ return sn.node.Close()
}
// Service returns a running service by name
From d2c247465ca8a8cb4fb4673d664d7659c9ac3503 Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Tue, 21 Jul 2020 13:58:11 +0200
Subject: [PATCH 106/160] mobile: add TODO for restart
---
mobile/geth.go | 1 +
1 file changed, 1 insertion(+)
diff --git a/mobile/geth.go b/mobile/geth.go
index 42b62b718564..d614f8eb3666 100644
--- a/mobile/geth.go
+++ b/mobile/geth.go
@@ -203,6 +203,7 @@ func (n *Node) Close() error {
// Start creates a live P2P node and starts running it.
func (n *Node) Start() error {
+ // TODO: recreate the node so it can be started multiple times
return n.node.Start()
}
From 4fdd72babf50b30abb0762c9a79bce7b94f4a2ce Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Tue, 21 Jul 2020 14:00:13 +0200
Subject: [PATCH 107/160] node: add more runstate checks
---
node/node.go | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/node/node.go b/node/node.go
index 69be3aef86b6..a4875174cdbb 100644
--- a/node/node.go
+++ b/node/node.go
@@ -541,7 +541,7 @@ func (n *Node) RPCHandler() (*rpc.Server, error) {
n.lock.RLock()
defer n.lock.RUnlock()
- if n.inprocHandler == nil {
+ if n.runstate == stoppedState {
return nil, ErrNodeStopped
}
return n.inprocHandler, nil
@@ -607,6 +607,9 @@ func (n *Node) EventMux() *event.TypeMux {
func (n *Node) OpenDatabase(name string, cache, handles int, namespace string) (ethdb.Database, error) {
// TODO: track databases so they can be closed later.
+ if n.runstate == stoppedState {
+ return nil, ErrNodeStopped
+ }
if n.config.DataDir == "" {
return rawdb.NewMemoryDatabase(), nil
}
@@ -619,6 +622,9 @@ func (n *Node) OpenDatabase(name string, cache, handles int, namespace string) (
// database to immutable append-only files. If the node is an ephemeral one, a
// memory database is returned.
func (n *Node) OpenDatabaseWithFreezer(name string, cache, handles int, freezer, namespace string) (ethdb.Database, error) {
+ if n.runstate == stoppedState {
+ return nil, ErrNodeStopped
+ }
if n.config.DataDir == "" {
return rawdb.NewMemoryDatabase(), nil
}
From 068fe781ffeeb194c8b0b37e6e01d84820b94715 Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Tue, 21 Jul 2020 14:02:56 +0200
Subject: [PATCH 108/160] node: ensure Register* can only be used in
initializing state
---
node/node.go | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/node/node.go b/node/node.go
index a4875174cdbb..2be5b8ec34df 100644
--- a/node/node.go
+++ b/node/node.go
@@ -219,6 +219,9 @@ func (n *Node) Close() error {
// RegisterLifecycle registers the given Lifecycle on the node.
func (n *Node) RegisterLifecycle(lifecycle Lifecycle) {
+ if n.runstate != initializingState {
+ panic(fmt.Sprintf("can't register lifecycle on running/stopped node"))
+ }
if containsLifecycle(n.lifecycles, lifecycle) {
panic(fmt.Sprintf("attempt to register lifecycle %T more than once", lifecycle))
}
@@ -227,11 +230,17 @@ func (n *Node) RegisterLifecycle(lifecycle Lifecycle) {
// RegisterProtocols adds backend's protocols to the node's p2p server.
func (n *Node) RegisterProtocols(protocols []p2p.Protocol) {
+ if n.runstate != initializingState {
+ panic(fmt.Sprintf("can't register protocols on running/stopped node"))
+ }
n.server.Protocols = append(n.server.Protocols, protocols...)
}
// RegisterAPIs registers the APIs a service provides on the node.
func (n *Node) RegisterAPIs(apis []rpc.API) {
+ if n.runstate != initializingState {
+ panic(fmt.Sprintf("can't register APIs on running/stopped node"))
+ }
n.rpcAPIs = append(n.rpcAPIs, apis...)
}
@@ -242,6 +251,9 @@ func (n *Node) RegisterHTTPServer(endpoint string, server *httpServer) {
// RegisterPath mounts the given handler on the given path on the canonical HTTP server.
func (n *Node) RegisterPath(path string, handler http.Handler) string {
+ if n.runstate != initializingState {
+ panic(fmt.Sprintf("can't register HTTP handler on running/stopped node"))
+ }
for _, server := range n.httpServers {
if atomic.LoadInt32(&server.RPCAllowed) == 1 {
server.srvMux.Handle(path, handler)
From 81ecb44852dc250cedd582e7aeee0b8ff2fdd764 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Tue, 21 Jul 2020 16:30:32 +0200
Subject: [PATCH 109/160] removed unnecessary use of fmt.Sprintf
---
node/node.go | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/node/node.go b/node/node.go
index 2be5b8ec34df..0047cbb6f46b 100644
--- a/node/node.go
+++ b/node/node.go
@@ -220,7 +220,7 @@ func (n *Node) Close() error {
// RegisterLifecycle registers the given Lifecycle on the node.
func (n *Node) RegisterLifecycle(lifecycle Lifecycle) {
if n.runstate != initializingState {
- panic(fmt.Sprintf("can't register lifecycle on running/stopped node"))
+ panic("can't register lifecycle on running/stopped node")
}
if containsLifecycle(n.lifecycles, lifecycle) {
panic(fmt.Sprintf("attempt to register lifecycle %T more than once", lifecycle))
@@ -231,7 +231,7 @@ func (n *Node) RegisterLifecycle(lifecycle Lifecycle) {
// RegisterProtocols adds backend's protocols to the node's p2p server.
func (n *Node) RegisterProtocols(protocols []p2p.Protocol) {
if n.runstate != initializingState {
- panic(fmt.Sprintf("can't register protocols on running/stopped node"))
+ panic("can't register protocols on running/stopped node")
}
n.server.Protocols = append(n.server.Protocols, protocols...)
}
@@ -239,7 +239,7 @@ func (n *Node) RegisterProtocols(protocols []p2p.Protocol) {
// RegisterAPIs registers the APIs a service provides on the node.
func (n *Node) RegisterAPIs(apis []rpc.API) {
if n.runstate != initializingState {
- panic(fmt.Sprintf("can't register APIs on running/stopped node"))
+ panic("can't register APIs on running/stopped node")
}
n.rpcAPIs = append(n.rpcAPIs, apis...)
}
@@ -252,7 +252,7 @@ func (n *Node) RegisterHTTPServer(endpoint string, server *httpServer) {
// RegisterPath mounts the given handler on the given path on the canonical HTTP server.
func (n *Node) RegisterPath(path string, handler http.Handler) string {
if n.runstate != initializingState {
- panic(fmt.Sprintf("can't register HTTP handler on running/stopped node"))
+ panic("can't register HTTP handler on running/stopped node")
}
for _, server := range n.httpServers {
if atomic.LoadInt32(&server.RPCAllowed) == 1 {
From 0ea3bb4f12d0ca6f02dc87d70959d14c5a010870 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Tue, 21 Jul 2020 16:31:06 +0200
Subject: [PATCH 110/160] revert accidental q
---
node/node_test.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/node/node_test.go b/node/node_test.go
index 38222d91ae93..f18df593f91e 100644
--- a/node/node_test.go
+++ b/node/node_test.go
@@ -405,7 +405,7 @@ func TestRegisterHTTPServer(t *testing.T) {
}
// Tests whether a handler can be successfully mounted on the canonical HTTP server
-// on the givenq path
+// on the given path
func TestRegisterPath_Successful(t *testing.T) {
node := createNode(t, 7878, 7979)
From f3f11786be865edb71987def3eb1acfaa1a2bde8 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Tue, 21 Jul 2020 18:26:13 +0200
Subject: [PATCH 111/160] fixed ethstats backend interface
---
ethstats/ethstats.go | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/ethstats/ethstats.go b/ethstats/ethstats.go
index a32ae71d491f..f100af4d118e 100644
--- a/ethstats/ethstats.go
+++ b/ethstats/ethstats.go
@@ -65,7 +65,7 @@ type backend interface {
SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription
CurrentHeader() *types.Header
HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error)
- GetTd(blockHash common.Hash) *big.Int
+ GetTd(ctx context.Context, hash common.Hash) *big.Int
Stats() (pending int, queued int)
Downloader() *downloader.Downloader
}
@@ -558,7 +558,7 @@ func (s *Service) assembleBlockStats(block *types.Block) *blockStats {
block = fullBackend.CurrentBlock()
}
header = block.Header()
- td = fullBackend.GetTd(header.Hash())
+ td = fullBackend.GetTd(context.Background(), header.Hash())
txs = make([]txStats, len(block.Transactions()))
for i, tx := range block.Transactions() {
@@ -572,7 +572,7 @@ func (s *Service) assembleBlockStats(block *types.Block) *blockStats {
} else {
header = s.backend.CurrentHeader()
}
- td = s.backend.GetTd(header.Hash())
+ td = s.backend.GetTd(context.Background(), header.Hash())
txs = []txStats{}
}
From 3c0fb992ed3b7bd59d1272c0b6fc12db94a94562 Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Tue, 21 Jul 2020 16:53:30 +0200
Subject: [PATCH 112/160] node: whitespace changes
---
node/node.go | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/node/node.go b/node/node.go
index 0047cbb6f46b..760c490a8ace 100644
--- a/node/node.go
+++ b/node/node.go
@@ -79,6 +79,7 @@ func New(conf *Config) (*Node, error) {
}
conf.DataDir = absdatadir
}
+
// Ensure that the instance name doesn't cause weird conflicts with
// other files in the data directory.
if strings.ContainsAny(conf.Name, `/\`) {
@@ -90,10 +91,10 @@ func New(conf *Config) (*Node, error) {
if strings.HasSuffix(conf.Name, ".ipc") {
return nil, errors.New(`Config.Name cannot end in ".ipc"`)
}
+
if conf.Logger == nil {
conf.Logger = log.New()
}
-
node := &Node{
config: conf,
httpServers: make(serverMap),
@@ -104,14 +105,15 @@ func New(conf *Config) (*Node, error) {
eventmux: new(event.TypeMux),
log: conf.Logger,
stop: make(chan struct{}),
+ server: &p2p.Server{Config: conf.P2P},
}
// Acquire the instance directory lock.
if err := node.openDataDir(); err != nil {
return nil, err
}
- // Ensure that the AccountManager method works before the node has started.
- // We rely on this in cmd/geth.
+ // Ensure that the AccountManager method works before the node has started. We rely on
+ // this in cmd/geth.
am, ephemeralKeystore, err := makeAccountManager(conf)
if err != nil {
return nil, err
@@ -119,9 +121,7 @@ func New(conf *Config) (*Node, error) {
node.accman = am
node.ephemeralKeystore = ephemeralKeystore
- // Initialize the p2p server. This creates the node key and
- // discovery databases.
- node.server = &p2p.Server{Config: conf.P2P}
+ // Initialize the p2p server. This creates the node key and discovery databases.
node.server.Config.PrivateKey = node.config.NodeKey()
node.server.Config.Name = node.config.NodeName()
node.server.Config.Logger = node.log
@@ -135,7 +135,7 @@ func New(conf *Config) (*Node, error) {
node.server.Config.NodeDatabase = node.config.NodeDB()
}
- // Configure HTTP server(s)
+ // Configure HTTP servers.
if conf.HTTPHost != "" {
httpServ := &httpServer{
CorsAllowedOrigins: conf.HTTPCors,
@@ -148,7 +148,7 @@ func New(conf *Config) (*Node, error) {
port: conf.HTTPPort,
RPCAllowed: 1,
}
- // check if ws is enabled and if ws port is the same as http port
+ // Enable WebSocket on HTTP port if enabled.
if conf.WSHost != "" && conf.WSPort == conf.HTTPPort {
httpServ.WSAllowed = 1
httpServ.WsOrigins = conf.WSOrigins
From 7801fad1e6463e035e3a8681c5ced4a57db1b3a1 Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Tue, 21 Jul 2020 16:53:47 +0200
Subject: [PATCH 113/160] p2p/simulations/adapters: use Node.Attach where
possible
---
p2p/simulations/adapters/inproc.go | 11 +++--------
1 file changed, 3 insertions(+), 8 deletions(-)
diff --git a/p2p/simulations/adapters/inproc.go b/p2p/simulations/adapters/inproc.go
index 36e0a0450ed8..fd10da431929 100644
--- a/p2p/simulations/adapters/inproc.go
+++ b/p2p/simulations/adapters/inproc.go
@@ -147,11 +147,7 @@ func (s *SimAdapter) DialRPC(id enode.ID) (*rpc.Client, error) {
if !ok {
return nil, fmt.Errorf("unknown node: %s", id)
}
- handler, err := node.node.RPCHandler()
- if err != nil {
- return nil, err
- }
- return rpc.DialInProc(handler), nil
+ return node.node.Attach()
}
// GetNode returns the node with the given ID if it exists
@@ -279,13 +275,12 @@ func (sn *SimNode) Start(snapshots map[string][]byte) error {
}
// create an in-process RPC client
- handler, err := sn.node.RPCHandler()
+ client, err := sn.node.Attach()
if err != nil {
return err
}
-
sn.lock.Lock()
- sn.client = rpc.DialInProc(handler)
+ sn.client = client
sn.lock.Unlock()
return nil
From d4e2173c7c657f1080c392418697390d05677476 Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Tue, 21 Jul 2020 16:56:06 +0200
Subject: [PATCH 114/160] node: avoid setting server to nil
---
node/node.go | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
diff --git a/node/node.go b/node/node.go
index 760c490a8ace..f93f179af805 100644
--- a/node/node.go
+++ b/node/node.go
@@ -49,10 +49,10 @@ type Node struct {
ephemeralKeystore string // if non-empty, the key directory that will be removed by Stop
instanceDirLock fileutil.Releaser // prevents concurrent use of instance directory
stop chan struct{} // Channel to wait for termination notifications
+ server *p2p.Server // Currently running P2P networking layer
lock sync.RWMutex
runstate int
- server *p2p.Server // Currently running P2P networking layer
lifecycles []Lifecycle // All registered backends, services, and auxiliary services that have a lifecycle
httpServers serverMap // serverMap stores information about the node's rpc, ws, and graphQL http servers.
inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
@@ -530,7 +530,6 @@ func (n *Node) stopServices() error {
failure := new(StopError)
failure.Services = stopLifecycles(n.lifecycles)
n.server.Stop()
- n.server = nil
if len(failure.Services) > 0 {
return failure
@@ -560,12 +559,9 @@ func (n *Node) RPCHandler() (*rpc.Server, error) {
}
// Server retrieves the currently running P2P network layer. This method is meant
-// only to inspect fields of the currently running server, life cycle management
-// should be left to this Node entity.
+// only to inspect fields of the currently running server. Callers should not
+// start or stop the returned server.
func (n *Node) Server() *p2p.Server {
- n.lock.RLock()
- defer n.lock.RUnlock()
-
return n.server
}
From dab27f69b1dade758504be6d48851af9523b0fa8 Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Tue, 21 Jul 2020 16:57:02 +0200
Subject: [PATCH 115/160] node: use simple lock
---
node/node.go | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/node/node.go b/node/node.go
index f93f179af805..419d9ad5bca7 100644
--- a/node/node.go
+++ b/node/node.go
@@ -51,7 +51,7 @@ type Node struct {
stop chan struct{} // Channel to wait for termination notifications
server *p2p.Server // Currently running P2P networking layer
- lock sync.RWMutex
+ lock sync.Mutex
runstate int
lifecycles []Lifecycle // All registered backends, services, and auxiliary services that have a lifecycle
httpServers serverMap // serverMap stores information about the node's rpc, ws, and graphQL http servers.
@@ -549,8 +549,8 @@ func (n *Node) Attach() (*rpc.Client, error) {
// RPCHandler returns the in-process RPC request handler.
func (n *Node) RPCHandler() (*rpc.Server, error) {
- n.lock.RLock()
- defer n.lock.RUnlock()
+ n.lock.Lock()
+ defer n.lock.Unlock()
if n.runstate == stoppedState {
return nil, ErrNodeStopped
From b8d75870b1644fb52f6df8584a17f780f017095e Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Tue, 21 Jul 2020 17:02:24 +0200
Subject: [PATCH 116/160] node: more cosmetic fixes
---
node/node.go | 53 ++++++++++++++++++++++++++--------------------------
1 file changed, 27 insertions(+), 26 deletions(-)
diff --git a/node/node.go b/node/node.go
index 419d9ad5bca7..a658bc4feb4d 100644
--- a/node/node.go
+++ b/node/node.go
@@ -42,14 +42,14 @@ import (
// Node is a container on which services can be registered.
type Node struct {
- eventmux *event.TypeMux // Event multiplexer used between the services of a stack
- config *Config
- accman *accounts.Manager
- log log.Logger
- ephemeralKeystore string // if non-empty, the key directory that will be removed by Stop
- instanceDirLock fileutil.Releaser // prevents concurrent use of instance directory
- stop chan struct{} // Channel to wait for termination notifications
- server *p2p.Server // Currently running P2P networking layer
+ eventmux *event.TypeMux // Event multiplexer used between the services of a stack
+ config *Config
+ accman *accounts.Manager
+ log log.Logger
+ ephemKeystore string // if non-empty, the key directory that will be removed by Stop
+ dirLock fileutil.Releaser // prevents concurrent use of instance directory
+ stop chan struct{} // Channel to wait for termination notifications
+ server *p2p.Server // Currently running P2P networking layer
lock sync.Mutex
runstate int
@@ -96,11 +96,9 @@ func New(conf *Config) (*Node, error) {
conf.Logger = log.New()
}
node := &Node{
- config: conf,
- httpServers: make(serverMap),
- ipc: &httpServer{
- endpoint: conf.IPCEndpoint(),
- },
+ config: conf,
+ httpServers: make(serverMap),
+ ipc: &httpServer{endpoint: conf.IPCEndpoint()},
inprocHandler: rpc.NewServer(),
eventmux: new(event.TypeMux),
log: conf.Logger,
@@ -119,7 +117,7 @@ func New(conf *Config) (*Node, error) {
return nil, err
}
node.accman = am
- node.ephemeralKeystore = ephemeralKeystore
+ node.ephemKeystore = ephemeralKeystore
// Initialize the p2p server. This creates the node key and discovery databases.
node.server.Config.PrivateKey = node.config.NodeKey()
@@ -196,8 +194,8 @@ func (n *Node) Close() error {
if err := n.accman.Close(); err != nil {
errs = append(errs, err)
}
- if n.ephemeralKeystore != "" {
- if err := os.RemoveAll(n.ephemeralKeystore); err != nil {
+ if n.ephemKeystore != "" {
+ if err := os.RemoveAll(n.ephemKeystore); err != nil {
errs = append(errs, err)
}
}
@@ -385,17 +383,17 @@ func (n *Node) openDataDir() error {
if err != nil {
return convertFileLockError(err)
}
- n.instanceDirLock = release
+ n.dirLock = release
return nil
}
func (n *Node) closeDataDir() {
// Release instance directory lock.
- if n.instanceDirLock != nil {
- if err := n.instanceDirLock.Release(); err != nil {
+ if n.dirLock != nil {
+ if err := n.dirLock.Release(); err != nil {
n.log.Error("Can't release datadir lock", "err", err)
}
- n.instanceDirLock = nil
+ n.dirLock = nil
}
}
@@ -537,7 +535,7 @@ func (n *Node) stopServices() error {
return nil
}
-// Wait blocks until the node is stopped.
+// Wait blocks until the node is closed.
func (n *Node) Wait() {
<-n.stop
}
@@ -613,7 +611,8 @@ func (n *Node) EventMux() *event.TypeMux {
// previous can be found) from within the node's instance directory. If the node is
// ephemeral, a memory database is returned.
func (n *Node) OpenDatabase(name string, cache, handles int, namespace string) (ethdb.Database, error) {
- // TODO: track databases so they can be closed later.
+ n.lock.Lock()
+ defer n.lock.Unlock()
if n.runstate == stoppedState {
return nil, ErrNodeStopped
@@ -621,7 +620,7 @@ func (n *Node) OpenDatabase(name string, cache, handles int, namespace string) (
if n.config.DataDir == "" {
return rawdb.NewMemoryDatabase(), nil
}
- return rawdb.NewLevelDBDatabase(n.config.ResolvePath(name), cache, handles, namespace)
+ return rawdb.NewLevelDBDatabase(n.ResolvePath(name), cache, handles, namespace)
}
// OpenDatabaseWithFreezer opens an existing database with the given name (or
@@ -630,19 +629,21 @@ func (n *Node) OpenDatabase(name string, cache, handles int, namespace string) (
// database to immutable append-only files. If the node is an ephemeral one, a
// memory database is returned.
func (n *Node) OpenDatabaseWithFreezer(name string, cache, handles int, freezer, namespace string) (ethdb.Database, error) {
+ n.lock.Lock()
+ defer n.lock.Unlock()
+
if n.runstate == stoppedState {
return nil, ErrNodeStopped
}
if n.config.DataDir == "" {
return rawdb.NewMemoryDatabase(), nil
}
- root := n.config.ResolvePath(name)
-
+ root := n.ResolvePath(name)
switch {
case freezer == "":
freezer = filepath.Join(root, "ancient")
case !filepath.IsAbs(freezer):
- freezer = n.config.ResolvePath(freezer)
+ freezer = n.ResolvePath(freezer)
}
return rawdb.NewLevelDBDatabaseWithFreezer(root, cache, handles, freezer, namespace)
}
From b6c60cf25856e8b729a0a007bb2a196694040b8b Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Tue, 21 Jul 2020 17:35:56 +0200
Subject: [PATCH 117/160] node: track open databases
---
node/node.go | 39 ++++++++++++++++++++++++++++++---------
1 file changed, 30 insertions(+), 9 deletions(-)
diff --git a/node/node.go b/node/node.go
index a658bc4feb4d..885a3106b280 100644
--- a/node/node.go
+++ b/node/node.go
@@ -42,7 +42,7 @@ import (
// Node is a container on which services can be registered.
type Node struct {
- eventmux *event.TypeMux // Event multiplexer used between the services of a stack
+ eventmux *event.TypeMux
config *Config
accman *accounts.Manager
log log.Logger
@@ -53,11 +53,12 @@ type Node struct {
lock sync.Mutex
runstate int
- lifecycles []Lifecycle // All registered backends, services, and auxiliary services that have a lifecycle
- httpServers serverMap // serverMap stores information about the node's rpc, ws, and graphQL http servers.
- inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
- rpcAPIs []rpc.API // List of APIs currently provided by the node
- ipc *httpServer // Stores information about the ipc http server
+ lifecycles []Lifecycle // All registered backends, services, and auxiliary services that have a lifecycle
+ httpServers serverMap // serverMap stores information about the node's rpc, ws, and graphQL http servers.
+ inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
+ rpcAPIs []rpc.API // List of APIs currently provided by the node
+ ipc *httpServer // Stores information about the ipc http server
+ databases []ethdb.Database // all opened databases
}
const (
@@ -190,7 +191,6 @@ func (n *Node) Close() error {
}
// Release resources acquired by New().
- n.closeDataDir()
if err := n.accman.Close(); err != nil {
errs = append(errs, err)
}
@@ -199,6 +199,8 @@ func (n *Node) Close() error {
errs = append(errs, err)
}
}
+ errs = append(errs, n.closeDatabases()...)
+ n.closeDataDir()
n.runstate = stoppedState
// Unblock n.Wait.
@@ -620,7 +622,9 @@ func (n *Node) OpenDatabase(name string, cache, handles int, namespace string) (
if n.config.DataDir == "" {
return rawdb.NewMemoryDatabase(), nil
}
- return rawdb.NewLevelDBDatabase(n.ResolvePath(name), cache, handles, namespace)
+ db, err := rawdb.NewLevelDBDatabase(n.ResolvePath(name), cache, handles, namespace)
+ n.addDatabase(db)
+ return db, err
}
// OpenDatabaseWithFreezer opens an existing database with the given name (or
@@ -645,7 +649,24 @@ func (n *Node) OpenDatabaseWithFreezer(name string, cache, handles int, freezer,
case !filepath.IsAbs(freezer):
freezer = n.ResolvePath(freezer)
}
- return rawdb.NewLevelDBDatabaseWithFreezer(root, cache, handles, freezer, namespace)
+ db, err := rawdb.NewLevelDBDatabaseWithFreezer(root, cache, handles, freezer, namespace)
+ n.addDatabase(db)
+ return db, err
+}
+
+func (n *Node) addDatabase(db ethdb.Database) {
+ if db != nil {
+ n.databases = append(n.databases, db)
+ }
+}
+
+func (n *Node) closeDatabases() (errors []error) {
+ for _, db := range n.databases {
+ if err := db.Close(); err != nil {
+ errors = append(errors, err)
+ }
+ }
+ return errors
}
// ResolvePath returns the absolute path of a resource in the instance directory.
From 4ae4172d6591a56c25f3e4366206dfa740e5a997 Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Tue, 21 Jul 2020 17:40:40 +0200
Subject: [PATCH 118/160] core/rawdb: make Freezer.Close idempotent
---
core/rawdb/freezer.go | 18 +++++++++++-------
1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/core/rawdb/freezer.go b/core/rawdb/freezer.go
index c5bb7cf1f443..621d35d3f420 100644
--- a/core/rawdb/freezer.go
+++ b/core/rawdb/freezer.go
@@ -22,6 +22,7 @@ import (
"math"
"os"
"path/filepath"
+ "sync"
"sync/atomic"
"time"
@@ -74,6 +75,7 @@ type freezer struct {
tables map[string]*freezerTable // Data tables for storing everything
instanceLock fileutil.Releaser // File-system lock to prevent double opens
quit chan struct{}
+ closeOnce sync.Once
}
// newFreezer creates a chain freezer that moves ancient chain data into
@@ -128,16 +130,18 @@ func newFreezer(datadir string, namespace string) (*freezer, error) {
// Close terminates the chain freezer, unmapping all the data files.
func (f *freezer) Close() error {
- f.quit <- struct{}{}
var errs []error
- for _, table := range f.tables {
- if err := table.Close(); err != nil {
+ f.closeOnce.Do(func() {
+ f.quit <- struct{}{}
+ for _, table := range f.tables {
+ if err := table.Close(); err != nil {
+ errs = append(errs, err)
+ }
+ }
+ if err := f.instanceLock.Release(); err != nil {
errs = append(errs, err)
}
- }
- if err := f.instanceLock.Release(); err != nil {
- errs = append(errs, err)
- }
+ })
if errs != nil {
return fmt.Errorf("%v", errs)
}
From 8400a5da0bb9f2f7ba34b02bc6ea25edd3be3f3d Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Wed, 22 Jul 2020 00:01:35 +0200
Subject: [PATCH 119/160] node: avoid auto-closing DB if service closes it
first
---
node/node.go | 77 ++++++++++++++++++++++++++++++++++++----------------
1 file changed, 54 insertions(+), 23 deletions(-)
diff --git a/node/node.go b/node/node.go
index 885a3106b280..ce73e348b907 100644
--- a/node/node.go
+++ b/node/node.go
@@ -53,12 +53,14 @@ type Node struct {
lock sync.Mutex
runstate int
- lifecycles []Lifecycle // All registered backends, services, and auxiliary services that have a lifecycle
- httpServers serverMap // serverMap stores information about the node's rpc, ws, and graphQL http servers.
- inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
- rpcAPIs []rpc.API // List of APIs currently provided by the node
- ipc *httpServer // Stores information about the ipc http server
- databases []ethdb.Database // all opened databases
+ lifecycles []Lifecycle // All registered backends, services, and auxiliary services that have a lifecycle
+ httpServers serverMap // serverMap stores information about the node's rpc, ws, and graphQL http servers.
+ inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
+ rpcAPIs []rpc.API // List of APIs currently provided by the node
+ ipc *httpServer // Stores information about the ipc http server
+
+ dbLock sync.Mutex
+ databases map[*closeTrackingDB]struct{} // all opened databases
}
const (
@@ -105,6 +107,7 @@ func New(conf *Config) (*Node, error) {
log: conf.Logger,
stop: make(chan struct{}),
server: &p2p.Server{Config: conf.P2P},
+ databases: make(map[*closeTrackingDB]struct{}),
}
// Acquire the instance directory lock.
@@ -623,7 +626,9 @@ func (n *Node) OpenDatabase(name string, cache, handles int, namespace string) (
return rawdb.NewMemoryDatabase(), nil
}
db, err := rawdb.NewLevelDBDatabase(n.ResolvePath(name), cache, handles, namespace)
- n.addDatabase(db)
+ if err == nil {
+ db = n.wrapDatabase(db)
+ }
return db, err
}
@@ -650,23 +655,10 @@ func (n *Node) OpenDatabaseWithFreezer(name string, cache, handles int, freezer,
freezer = n.ResolvePath(freezer)
}
db, err := rawdb.NewLevelDBDatabaseWithFreezer(root, cache, handles, freezer, namespace)
- n.addDatabase(db)
- return db, err
-}
-
-func (n *Node) addDatabase(db ethdb.Database) {
- if db != nil {
- n.databases = append(n.databases, db)
- }
-}
-
-func (n *Node) closeDatabases() (errors []error) {
- for _, db := range n.databases {
- if err := db.Close(); err != nil {
- errors = append(errors, err)
- }
+ if err == nil {
+ db = n.wrapDatabase(db)
}
- return errors
+ return db, err
}
// ResolvePath returns the absolute path of a resource in the instance directory.
@@ -699,6 +691,45 @@ func (n *Node) apis() []rpc.API {
}
}
+// closeTrackingDB wraps the Close method of a database. When the database is closed by the
+// service, the wrapper removes it from the node's database map. This ensures that Node
+// won't auto-close the database if it is closed by the service that opened it.
+type closeTrackingDB struct {
+ ethdb.Database
+ n *Node
+}
+
+func (db *closeTrackingDB) Close() error {
+ db.n.dbLock.Lock()
+ delete(db.n.databases, db)
+ db.n.dbLock.Unlock()
+ return db.Database.Close()
+}
+
+// wrapDatabase ensures the database will be auto-closed when Node is closed.
+func (n *Node) wrapDatabase(db ethdb.Database) ethdb.Database {
+ n.dbLock.Lock()
+ defer n.dbLock.Unlock()
+
+ wrapper := &closeTrackingDB{db, n}
+ n.databases[wrapper] = struct{}{}
+ return wrapper
+}
+
+// closeDatabases closes all open databases.
+func (n *Node) closeDatabases() (errors []error) {
+ n.dbLock.Lock()
+ defer n.dbLock.Unlock()
+
+ for db := range n.databases {
+ delete(n.databases, db)
+ if err := db.Database.Close(); err != nil {
+ errors = append(errors, err)
+ }
+ }
+ return errors
+}
+
// RegisterApisFromWhitelist checks the given modules' availability, generates a whitelist based on the allowed modules,
// and then registers all of the APIs exposed by the services.
func RegisterApisFromWhitelist(apis []rpc.API, modules []string, srv *rpc.Server, exposeAll bool) error {
From fa88f302bfd8b71fd8b73190b4238d7ff580bd81 Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Wed, 22 Jul 2020 00:36:41 +0200
Subject: [PATCH 120/160] p2p/simulations/adapters: delete snapshotService
---
p2p/simulations/adapters/exec.go | 39 +++++++-------------------------
1 file changed, 8 insertions(+), 31 deletions(-)
diff --git a/p2p/simulations/adapters/exec.go b/p2p/simulations/adapters/exec.go
index ccb0d82e7d3d..7ef908814d79 100644
--- a/p2p/simulations/adapters/exec.go
+++ b/p2p/simulations/adapters/exec.go
@@ -434,8 +434,8 @@ func startExecNodeStack() (*node.Node, error) {
return nil, fmt.Errorf("error creating node stack: %v", err)
}
- // register the services, collecting them into a map so we can wrap
- // them in a snapshot service
+ // Register the services, collecting them into a map so they can
+ // be accessed by the snapshot API.
services := make(map[string]node.Lifecycle, len(serviceNames))
for _, name := range serviceNames {
lifecycleFunc, exists := lifecycleConstructorFuncs[name]
@@ -457,10 +457,13 @@ func startExecNodeStack() (*node.Node, error) {
stack.RegisterLifecycle(service)
}
- // register the snapshot service
- stack.RegisterLifecycle(&snapshotService{services})
+ // Add the snapshot API.
+ stack.RegisterAPIs([]rpc.API{{
+ Namespace: "simulation",
+ Version: "1.0",
+ Service: SnapshotAPI{services},
+ }})
- // start the stack
if err = stack.Start(); err != nil {
err = fmt.Errorf("error starting stack: %v", err)
}
@@ -479,32 +482,6 @@ type nodeStartupJSON struct {
NodeInfo *p2p.NodeInfo
}
-// snapshotService is a node.Service which wraps a list of services and
-// exposes an API to generate a snapshot of those services
-type snapshotService struct {
- services map[string]node.Lifecycle
-}
-
-func (s *snapshotService) APIs() []rpc.API {
- return []rpc.API{{
- Namespace: "simulation",
- Version: "1.0",
- Service: SnapshotAPI{s.services},
- }}
-}
-
-func (s *snapshotService) Protocols() []p2p.Protocol {
- return nil
-}
-
-func (s *snapshotService) Start() error {
- return nil
-}
-
-func (s *snapshotService) Stop() error {
- return nil
-}
-
// SnapshotAPI provides an RPC method to create snapshots of services
type SnapshotAPI struct {
services map[string]node.Lifecycle
From 4da9ef7393bfb2c7a0e4463ffa822979cbc60742 Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Wed, 22 Jul 2020 00:38:43 +0200
Subject: [PATCH 121/160] p2p: delete Server.Running
---
p2p/server.go | 5 -----
1 file changed, 5 deletions(-)
diff --git a/p2p/server.go b/p2p/server.go
index 58a41729861e..1fe5f3978923 100644
--- a/p2p/server.go
+++ b/p2p/server.go
@@ -1119,8 +1119,3 @@ func (srv *Server) PeersInfo() []*PeerInfo {
}
return infos
}
-
-// Running returns whether the server is running.
-func (srv *Server) Running() bool {
- return srv.running
-}
From e1f4668e37f85da9925dd0624cc15c10a1460cef Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Wed, 22 Jul 2020 10:11:49 +0200
Subject: [PATCH 122/160] cmd/geth, cmd/utils: gofmt -w -s
---
cmd/geth/main.go | 2 +-
cmd/utils/flags.go | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index da0b00c74464..ccc6358996b6 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -36,8 +36,8 @@ import (
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/internal/debug"
- "github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/internal/ethapi"
+ "github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/node"
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index 6af946dffe8a..a2e5244dc4fd 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -48,8 +48,8 @@ import (
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/ethstats"
"github.com/ethereum/go-ethereum/graphql"
- "github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/internal/ethapi"
+ "github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/les"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
From a30d4015ba1008de63b0b1a8b74ef692a8f21b4e Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Wed, 22 Jul 2020 12:00:01 +0200
Subject: [PATCH 123/160] p2p/simulations/examples: remove unused APIs callback
---
p2p/simulations/examples/ping-pong.go | 6 ------
1 file changed, 6 deletions(-)
diff --git a/p2p/simulations/examples/ping-pong.go b/p2p/simulations/examples/ping-pong.go
index 13b6873bfea3..0cddd9b505f3 100644
--- a/p2p/simulations/examples/ping-pong.go
+++ b/p2p/simulations/examples/ping-pong.go
@@ -31,7 +31,6 @@ import (
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/simulations"
"github.com/ethereum/go-ethereum/p2p/simulations/adapters"
- "github.com/ethereum/go-ethereum/rpc"
)
var adapterType = flag.String("adapter", "sim", `node adapter to use (one of "sim", "exec" or "docker")`)
@@ -49,7 +48,6 @@ func main() {
"ping-pong": func(ctx *adapters.ServiceContext, stack *node.Node) (node.Lifecycle, error) {
pps := newPingPongService(ctx.Config.ID)
stack.RegisterProtocols(pps.Protocols())
- stack.RegisterAPIs(pps.APIs())
return pps, nil
},
}
@@ -113,10 +111,6 @@ func (p *pingPongService) Protocols() []p2p.Protocol {
}}
}
-func (p *pingPongService) APIs() []rpc.API {
- return nil
-}
-
func (p *pingPongService) Start() error {
p.log.Info("ping-pong service starting")
return nil
From 5a3cf7a3ebcb1f53a616d2751f2edbd7d85ab80a Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Wed, 22 Jul 2020 12:08:47 +0200
Subject: [PATCH 124/160] p2p/testing: delete unused package
pkg.go.dev lists zero imports from public Go code.
---
p2p/testing/peerpool.go | 67 --------
p2p/testing/protocolsession.go | 283 --------------------------------
p2p/testing/protocoltester.go | 284 ---------------------------------
3 files changed, 634 deletions(-)
delete mode 100644 p2p/testing/peerpool.go
delete mode 100644 p2p/testing/protocolsession.go
delete mode 100644 p2p/testing/protocoltester.go
diff --git a/p2p/testing/peerpool.go b/p2p/testing/peerpool.go
deleted file mode 100644
index 91b9704c79f4..000000000000
--- a/p2p/testing/peerpool.go
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2018 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package testing
-
-import (
- "fmt"
- "sync"
-
- "github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/p2p/enode"
-)
-
-type TestPeer interface {
- ID() enode.ID
- Drop()
-}
-
-// TestPeerPool is an example peerPool to demonstrate registration of peer connections
-type TestPeerPool struct {
- lock sync.Mutex
- peers map[enode.ID]TestPeer
-}
-
-func NewTestPeerPool() *TestPeerPool {
- return &TestPeerPool{peers: make(map[enode.ID]TestPeer)}
-}
-
-func (p *TestPeerPool) Add(peer TestPeer) {
- p.lock.Lock()
- defer p.lock.Unlock()
- log.Trace(fmt.Sprintf("pp add peer %v", peer.ID()))
- p.peers[peer.ID()] = peer
-
-}
-
-func (p *TestPeerPool) Remove(peer TestPeer) {
- p.lock.Lock()
- defer p.lock.Unlock()
- delete(p.peers, peer.ID())
-}
-
-func (p *TestPeerPool) Has(id enode.ID) bool {
- p.lock.Lock()
- defer p.lock.Unlock()
- _, ok := p.peers[id]
- return ok
-}
-
-func (p *TestPeerPool) Get(id enode.ID) TestPeer {
- p.lock.Lock()
- defer p.lock.Unlock()
- return p.peers[id]
-}
diff --git a/p2p/testing/protocolsession.go b/p2p/testing/protocolsession.go
deleted file mode 100644
index 58dac93c36c9..000000000000
--- a/p2p/testing/protocolsession.go
+++ /dev/null
@@ -1,283 +0,0 @@
-// Copyright 2018 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package testing
-
-import (
- "errors"
- "fmt"
- "sync"
- "time"
-
- "github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/p2p"
- "github.com/ethereum/go-ethereum/p2p/enode"
- "github.com/ethereum/go-ethereum/p2p/simulations/adapters"
-)
-
-var errTimedOut = errors.New("timed out")
-
-// ProtocolSession is a quasi simulation of a pivot node running
-// a service and a number of dummy peers that can send (trigger) or
-// receive (expect) messages
-type ProtocolSession struct {
- Server *p2p.Server
- Nodes []*enode.Node
- adapter *adapters.SimAdapter
- events chan *p2p.PeerEvent
-}
-
-// Exchange is the basic units of protocol tests
-// the triggers and expects in the arrays are run immediately and asynchronously
-// thus one cannot have multiple expects for the SAME peer with DIFFERENT message types
-// because it's unpredictable which expect will receive which message
-// (with expect #1 and #2, messages might be sent #2 and #1, and both expects will complain about wrong message code)
-// an exchange is defined on a session
-type Exchange struct {
- Label string
- Triggers []Trigger
- Expects []Expect
- Timeout time.Duration
-}
-
-// Trigger is part of the exchange, incoming message for the pivot node
-// sent by a peer
-type Trigger struct {
- Msg interface{} // type of message to be sent
- Code uint64 // code of message is given
- Peer enode.ID // the peer to send the message to
- Timeout time.Duration // timeout duration for the sending
-}
-
-// Expect is part of an exchange, outgoing message from the pivot node
-// received by a peer
-type Expect struct {
- Msg interface{} // type of message to expect
- Code uint64 // code of message is now given
- Peer enode.ID // the peer that expects the message
- Timeout time.Duration // timeout duration for receiving
-}
-
-// Disconnect represents a disconnect event, used and checked by TestDisconnected
-type Disconnect struct {
- Peer enode.ID // discconnected peer
- Error error // disconnect reason
-}
-
-// trigger sends messages from peers
-func (s *ProtocolSession) trigger(trig Trigger) error {
- simNode, ok := s.adapter.GetNode(trig.Peer)
- if !ok {
- return fmt.Errorf("trigger: peer %v does not exist (1- %v)", trig.Peer, len(s.Nodes))
- }
- mockNode, ok := simNode.Services()[0].(*mockNode)
- if !ok {
- return fmt.Errorf("trigger: peer %v is not a mock", trig.Peer)
- }
-
- errc := make(chan error)
-
- go func() {
- log.Trace(fmt.Sprintf("trigger %v (%v)....", trig.Msg, trig.Code))
- errc <- mockNode.Trigger(&trig)
- log.Trace(fmt.Sprintf("triggered %v (%v)", trig.Msg, trig.Code))
- }()
-
- t := trig.Timeout
- if t == time.Duration(0) {
- t = 1000 * time.Millisecond
- }
- select {
- case err := <-errc:
- return err
- case <-time.After(t):
- return fmt.Errorf("timout expecting %v to send to peer %v", trig.Msg, trig.Peer)
- }
-}
-
-// expect checks an expectation of a message sent out by the pivot node
-func (s *ProtocolSession) expect(exps []Expect) error {
- // construct a map of expectations for each node
- peerExpects := make(map[enode.ID][]Expect)
- for _, exp := range exps {
- if exp.Msg == nil {
- return errors.New("no message to expect")
- }
- peerExpects[exp.Peer] = append(peerExpects[exp.Peer], exp)
- }
-
- // construct a map of mockNodes for each node
- mockNodes := make(map[enode.ID]*mockNode)
- for nodeID := range peerExpects {
- simNode, ok := s.adapter.GetNode(nodeID)
- if !ok {
- return fmt.Errorf("trigger: peer %v does not exist (1- %v)", nodeID, len(s.Nodes))
- }
- mockNode, ok := simNode.Services()[0].(*mockNode)
- if !ok {
- return fmt.Errorf("trigger: peer %v is not a mock", nodeID)
- }
- mockNodes[nodeID] = mockNode
- }
-
- // done chanell cancels all created goroutines when function returns
- done := make(chan struct{})
- defer close(done)
- // errc catches the first error from
- errc := make(chan error)
-
- wg := &sync.WaitGroup{}
- wg.Add(len(mockNodes))
- for nodeID, mockNode := range mockNodes {
- nodeID := nodeID
- mockNode := mockNode
- go func() {
- defer wg.Done()
-
- // Sum all Expect timeouts to give the maximum
- // time for all expectations to finish.
- // mockNode.Expect checks all received messages against
- // a list of expected messages and timeout for each
- // of them can not be checked separately.
- var t time.Duration
- for _, exp := range peerExpects[nodeID] {
- if exp.Timeout == time.Duration(0) {
- t += 2000 * time.Millisecond
- } else {
- t += exp.Timeout
- }
- }
- alarm := time.NewTimer(t)
- defer alarm.Stop()
-
- // expectErrc is used to check if error returned
- // from mockNode.Expect is not nil and to send it to
- // errc only in that case.
- // done channel will be closed when function
- expectErrc := make(chan error)
- go func() {
- select {
- case expectErrc <- mockNode.Expect(peerExpects[nodeID]...):
- case <-done:
- case <-alarm.C:
- }
- }()
-
- select {
- case err := <-expectErrc:
- if err != nil {
- select {
- case errc <- err:
- case <-done:
- case <-alarm.C:
- errc <- errTimedOut
- }
- }
- case <-done:
- case <-alarm.C:
- errc <- errTimedOut
- }
-
- }()
- }
-
- go func() {
- wg.Wait()
- // close errc when all goroutines finish to return nill err from errc
- close(errc)
- }()
-
- return <-errc
-}
-
-// TestExchanges tests a series of exchanges against the session
-func (s *ProtocolSession) TestExchanges(exchanges ...Exchange) error {
- for i, e := range exchanges {
- if err := s.testExchange(e); err != nil {
- return fmt.Errorf("exchange #%d %q: %v", i, e.Label, err)
- }
- log.Trace(fmt.Sprintf("exchange #%d %q: run successfully", i, e.Label))
- }
- return nil
-}
-
-// testExchange tests a single Exchange.
-// Default timeout value is 2 seconds.
-func (s *ProtocolSession) testExchange(e Exchange) error {
- errc := make(chan error)
- done := make(chan struct{})
- defer close(done)
-
- go func() {
- for _, trig := range e.Triggers {
- err := s.trigger(trig)
- if err != nil {
- errc <- err
- return
- }
- }
-
- select {
- case errc <- s.expect(e.Expects):
- case <-done:
- }
- }()
-
- // time out globally or finish when all expectations satisfied
- t := e.Timeout
- if t == 0 {
- t = 2000 * time.Millisecond
- }
- alarm := time.NewTimer(t)
- defer alarm.Stop()
- select {
- case err := <-errc:
- return err
- case <-alarm.C:
- return errTimedOut
- }
-}
-
-// TestDisconnected tests the disconnections given as arguments
-// the disconnect structs describe what disconnect error is expected on which peer
-func (s *ProtocolSession) TestDisconnected(disconnects ...*Disconnect) error {
- expects := make(map[enode.ID]error)
- for _, disconnect := range disconnects {
- expects[disconnect.Peer] = disconnect.Error
- }
-
- timeout := time.After(time.Second)
- for len(expects) > 0 {
- select {
- case event := <-s.events:
- if event.Type != p2p.PeerEventTypeDrop {
- continue
- }
- expectErr, ok := expects[event.Peer]
- if !ok {
- continue
- }
-
- if !(expectErr == nil && event.Error == "" || expectErr != nil && expectErr.Error() == event.Error) {
- return fmt.Errorf("unexpected error on peer %v. expected '%v', got '%v'", event.Peer, expectErr, event.Error)
- }
- delete(expects, event.Peer)
- case <-timeout:
- return fmt.Errorf("timed out waiting for peers to disconnect")
- }
- }
- return nil
-}
diff --git a/p2p/testing/protocoltester.go b/p2p/testing/protocoltester.go
deleted file mode 100644
index 9dd53e71226a..000000000000
--- a/p2p/testing/protocoltester.go
+++ /dev/null
@@ -1,284 +0,0 @@
-// Copyright 2018 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-/*
-the p2p/testing package provides a unit test scheme to check simple
-protocol message exchanges with one pivot node and a number of dummy peers
-The pivot test node runs a node.Service, the dummy peers run a mock node
-that can be used to send and receive messages
-*/
-
-package testing
-
-import (
- "bytes"
- "crypto/ecdsa"
- "fmt"
- "io"
- "io/ioutil"
- "strings"
- "sync"
-
- "github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/node"
- "github.com/ethereum/go-ethereum/p2p"
- "github.com/ethereum/go-ethereum/p2p/enode"
- "github.com/ethereum/go-ethereum/p2p/simulations"
- "github.com/ethereum/go-ethereum/p2p/simulations/adapters"
- "github.com/ethereum/go-ethereum/rlp"
- "github.com/ethereum/go-ethereum/rpc"
-)
-
-// ProtocolTester is the tester environment used for unit testing protocol
-// message exchanges. It uses p2p/simulations framework
-type ProtocolTester struct {
- *ProtocolSession
- network *simulations.Network
-}
-
-// NewProtocolTester constructs a new ProtocolTester
-// it takes as argument the pivot node id, the number of dummy peers and the
-// protocol run function called on a peer connection by the p2p server
-func NewProtocolTester(prvkey *ecdsa.PrivateKey, nodeCount int, run func(*p2p.Peer, p2p.MsgReadWriter) error) *ProtocolTester {
- services := adapters.LifecycleConstructors{
- "test": func(ctx *adapters.ServiceContext, stack *node.Node) (node.Lifecycle, error) {
- return &testNode{run}, nil
- },
- "mock": func(ctx *adapters.ServiceContext, stack *node.Node) (node.Lifecycle, error) {
- return newMockNode(), nil
- },
- }
- adapter := adapters.NewSimAdapter(services)
- net := simulations.NewNetwork(adapter, &simulations.NetworkConfig{})
- nodeConfig := &adapters.NodeConfig{
- PrivateKey: prvkey,
- EnableMsgEvents: true,
- Lifecycles: []string{"test"},
- }
- if _, err := net.NewNodeWithConfig(nodeConfig); err != nil {
- panic(err.Error())
- }
- if err := net.Start(nodeConfig.ID); err != nil {
- panic(err.Error())
- }
-
- node := net.GetNode(nodeConfig.ID).Node.(*adapters.SimNode)
- peers := make([]*adapters.NodeConfig, nodeCount)
- nodes := make([]*enode.Node, nodeCount)
- for i := 0; i < nodeCount; i++ {
- peers[i] = adapters.RandomNodeConfig()
- peers[i].Lifecycles = []string{"mock"}
- if _, err := net.NewNodeWithConfig(peers[i]); err != nil {
- panic(fmt.Sprintf("error initializing peer %v: %v", peers[i].ID, err))
- }
- if err := net.Start(peers[i].ID); err != nil {
- panic(fmt.Sprintf("error starting peer %v: %v", peers[i].ID, err))
- }
- nodes[i] = peers[i].Node()
- }
- events := make(chan *p2p.PeerEvent, 1000)
- node.SubscribeEvents(events)
- ps := &ProtocolSession{
- Server: node.Server(),
- Nodes: nodes,
- adapter: adapter,
- events: events,
- }
- self := &ProtocolTester{
- ProtocolSession: ps,
- network: net,
- }
-
- self.Connect(nodeConfig.ID, peers...)
-
- return self
-}
-
-// Stop stops the p2p server
-func (t *ProtocolTester) Stop() {
- t.Server.Stop()
- t.network.Shutdown()
-}
-
-// Connect brings up the remote peer node and connects it using the
-// p2p/simulations network connection with the in memory network adapter
-func (t *ProtocolTester) Connect(selfID enode.ID, peers ...*adapters.NodeConfig) {
- for _, peer := range peers {
- log.Trace(fmt.Sprintf("connect to %v", peer.ID))
- if err := t.network.Connect(selfID, peer.ID); err != nil {
- panic(fmt.Sprintf("error connecting to peer %v: %v", peer.ID, err))
- }
- }
-
-}
-
-// testNode wraps a protocol run function and implements the node.Service
-// interface
-type testNode struct {
- run func(*p2p.Peer, p2p.MsgReadWriter) error
-}
-
-func (t *testNode) Protocols() []p2p.Protocol {
- return []p2p.Protocol{{
- Length: 100,
- Run: t.run,
- }}
-}
-
-func (t *testNode) APIs() []rpc.API {
- return nil
-}
-
-func (t *testNode) Start() error {
- return nil
-}
-
-func (t *testNode) Stop() error {
- return nil
-}
-
-// mockNode is a testNode which doesn't actually run a protocol, instead
-// exposing channels so that tests can manually trigger and expect certain
-// messages
-type mockNode struct {
- testNode
-
- trigger chan *Trigger
- expect chan []Expect
- err chan error
- stop chan struct{}
- stopOnce sync.Once
-}
-
-func newMockNode() *mockNode {
- mock := &mockNode{
- trigger: make(chan *Trigger),
- expect: make(chan []Expect),
- err: make(chan error),
- stop: make(chan struct{}),
- }
- mock.testNode.run = mock.Run
- return mock
-}
-
-// Run is a protocol run function which just loops waiting for tests to
-// instruct it to either trigger or expect a message from the peer
-func (m *mockNode) Run(peer *p2p.Peer, rw p2p.MsgReadWriter) error {
- for {
- select {
- case trig := <-m.trigger:
- wmsg := Wrap(trig.Msg)
- m.err <- p2p.Send(rw, trig.Code, wmsg)
- case exps := <-m.expect:
- m.err <- expectMsgs(rw, exps)
- case <-m.stop:
- return nil
- }
- }
-}
-
-func (m *mockNode) Trigger(trig *Trigger) error {
- m.trigger <- trig
- return <-m.err
-}
-
-func (m *mockNode) Expect(exp ...Expect) error {
- m.expect <- exp
- return <-m.err
-}
-
-func (m *mockNode) Stop() error {
- m.stopOnce.Do(func() { close(m.stop) })
- return nil
-}
-
-func expectMsgs(rw p2p.MsgReadWriter, exps []Expect) error {
- matched := make([]bool, len(exps))
- for {
- msg, err := rw.ReadMsg()
- if err != nil {
- if err == io.EOF {
- break
- }
- return err
- }
- actualContent, err := ioutil.ReadAll(msg.Payload)
- if err != nil {
- return err
- }
- var found bool
- for i, exp := range exps {
- if exp.Code == msg.Code && bytes.Equal(actualContent, mustEncodeMsg(Wrap(exp.Msg))) {
- if matched[i] {
- return fmt.Errorf("message #%d received two times", i)
- }
- matched[i] = true
- found = true
- break
- }
- }
- if !found {
- expected := make([]string, 0)
- for i, exp := range exps {
- if matched[i] {
- continue
- }
- expected = append(expected, fmt.Sprintf("code %d payload %x", exp.Code, mustEncodeMsg(Wrap(exp.Msg))))
- }
- return fmt.Errorf("unexpected message code %d payload %x, expected %s", msg.Code, actualContent, strings.Join(expected, " or "))
- }
- done := true
- for _, m := range matched {
- if !m {
- done = false
- break
- }
- }
- if done {
- return nil
- }
- }
- for i, m := range matched {
- if !m {
- return fmt.Errorf("expected message #%d not received", i)
- }
- }
- return nil
-}
-
-// mustEncodeMsg uses rlp to encode a message.
-// In case of error it panics.
-func mustEncodeMsg(msg interface{}) []byte {
- contentEnc, err := rlp.EncodeToBytes(msg)
- if err != nil {
- panic("content encode error: " + err.Error())
- }
- return contentEnc
-}
-
-type WrappedMsg struct {
- Context []byte
- Size uint32
- Payload []byte
-}
-
-func Wrap(msg interface{}) interface{} {
- data, _ := rlp.EncodeToBytes(msg)
- return &WrappedMsg{
- Size: uint32(len(data)),
- Payload: data,
- }
-}
From e6cd0e3e696a1e1c70bbec853128e96874e35a01 Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Wed, 22 Jul 2020 12:16:05 +0200
Subject: [PATCH 125/160] node: unexport RegisterHTTPServer
---
node/api.go | 4 ++--
node/node.go | 10 +++++-----
node/node_test.go | 4 ++--
3 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/node/api.go b/node/api.go
index 810697fafb35..0c81bf4827b9 100644
--- a/node/api.go
+++ b/node/api.go
@@ -208,7 +208,7 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
return false, err
}
// register the HTTP server
- api.node.RegisterHTTPServer(endpoint, httpServer)
+ api.node.registerHTTPServer(endpoint, httpServer)
// start the HTTP server
httpServer.Start()
api.node.log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%v/", httpServer.Listener.Addr()),
@@ -297,7 +297,7 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
return false, err
}
// register the HTTP server
- api.node.RegisterHTTPServer(endpoint, wsServer)
+ api.node.registerHTTPServer(endpoint, wsServer)
// start the HTTP server
if err := wsServer.Start(); err != nil {
return false, err
diff --git a/node/node.go b/node/node.go
index ce73e348b907..93b949acaa5b 100644
--- a/node/node.go
+++ b/node/node.go
@@ -247,11 +247,6 @@ func (n *Node) RegisterAPIs(apis []rpc.API) {
n.rpcAPIs = append(n.rpcAPIs, apis...)
}
-// RegisterHTTPServer registers the given HTTP server on the node.
-func (n *Node) RegisterHTTPServer(endpoint string, server *httpServer) {
- n.httpServers[endpoint] = server
-}
-
// RegisterPath mounts the given handler on the given path on the canonical HTTP server.
func (n *Node) RegisterPath(path string, handler http.Handler) string {
if n.runstate != initializingState {
@@ -267,6 +262,11 @@ func (n *Node) RegisterPath(path string, handler http.Handler) string {
return ""
}
+// registerHTTPServer registers the given HTTP server on the node.
+func (n *Node) registerHTTPServer(endpoint string, server *httpServer) {
+ n.httpServers[endpoint] = server
+}
+
// existingHTTPServer checks if an HTTP server is already configured on the given endpoint.
func (n *Node) existingHTTPServer(endpoint string) *httpServer {
if server, exists := n.httpServers[endpoint]; exists {
diff --git a/node/node_test.go b/node/node_test.go
index f18df593f91e..a360c5cdfd07 100644
--- a/node/node_test.go
+++ b/node/node_test.go
@@ -378,14 +378,14 @@ func TestRegisterHTTPServer(t *testing.T) {
port: 0001,
}
endpoint1 := fmt.Sprintf("%s:%d", srv1.host, srv1.port)
- stack.RegisterHTTPServer(endpoint1, srv1)
+ stack.registerHTTPServer(endpoint1, srv1)
srv2 := &httpServer{
host: "test2",
port: 0002,
}
endpoint2 := fmt.Sprintf("%s:%d", srv2.host, srv2.port)
- stack.RegisterHTTPServer(endpoint2, srv2)
+ stack.registerHTTPServer(endpoint2, srv2)
noop := &httpServer{
host: "test",
From aba06679a4b88a5cda4a7580bd7e0ba876cbbd99 Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Wed, 22 Jul 2020 12:21:26 +0200
Subject: [PATCH 126/160] node: clean up instrumented service tests
---
node/node_test.go | 72 +++++++++++++++++-----------------------------
node/utils_test.go | 8 ------
2 files changed, 27 insertions(+), 53 deletions(-)
diff --git a/node/node_test.go b/node/node_test.go
index a360c5cdfd07..4d04fd7ceaff 100644
--- a/node/node_test.go
+++ b/node/node_test.go
@@ -182,23 +182,17 @@ func TestLifecycleLifeCycle(t *testing.T) {
// Create a batch of instrumented services
lifecycles := map[string]Lifecycle{
- "A": &InstrumentedServiceA{
- InstrumentedService{
- startHook: func() { started["A"] = true },
- stopHook: func() { stopped["A"] = true },
- },
+ "A": &InstrumentedService{
+ startHook: func() { started["A"] = true },
+ stopHook: func() { stopped["A"] = true },
},
- "B": &InstrumentedServiceB{
- InstrumentedService{
- startHook: func() { started["B"] = true },
- stopHook: func() { stopped["B"] = true },
- },
+ "B": &InstrumentedService{
+ startHook: func() { started["B"] = true },
+ stopHook: func() { stopped["B"] = true },
},
- "C": &InstrumentedServiceC{
- InstrumentedService{
- startHook: func() { started["C"] = true },
- stopHook: func() { stopped["C"] = true },
- },
+ "C": &InstrumentedService{
+ startHook: func() { started["C"] = true },
+ stopHook: func() { stopped["C"] = true },
},
}
// register lifecycles on node
@@ -242,23 +236,17 @@ func TestLifecycleStartupError(t *testing.T) {
// Create a batch of instrumented services
lifecycles := map[string]Lifecycle{
- "A": &InstrumentedServiceA{
- InstrumentedService{
- startHook: func() { started["A"] = true },
- stopHook: func() { stopped["A"] = true },
- },
+ "A": &InstrumentedService{
+ startHook: func() { started["A"] = true },
+ stopHook: func() { stopped["A"] = true },
},
- "B": &InstrumentedServiceB{
- InstrumentedService{
- startHook: func() { started["B"] = true },
- stopHook: func() { stopped["B"] = true },
- },
+ "B": &InstrumentedService{
+ startHook: func() { started["B"] = true },
+ stopHook: func() { stopped["B"] = true },
},
- "C": &InstrumentedServiceC{
- InstrumentedService{
- startHook: func() { started["C"] = true },
- stopHook: func() { stopped["C"] = true },
- },
+ "C": &InstrumentedService{
+ startHook: func() { started["C"] = true },
+ stopHook: func() { stopped["C"] = true },
},
}
// register lifecycles on node
@@ -298,23 +286,17 @@ func TestLifecycleTerminationGuarantee(t *testing.T) {
// Create a batch of instrumented services
lifecycles := map[string]Lifecycle{
- "A": &InstrumentedServiceA{
- InstrumentedService{
- startHook: func() { started["A"] = true },
- stopHook: func() { stopped["A"] = true },
- },
+ "A": &InstrumentedService{
+ startHook: func() { started["A"] = true },
+ stopHook: func() { stopped["A"] = true },
},
- "B": &InstrumentedServiceB{
- InstrumentedService{
- startHook: func() { started["B"] = true },
- stopHook: func() { stopped["B"] = true },
- },
+ "B": &InstrumentedService{
+ startHook: func() { started["B"] = true },
+ stopHook: func() { stopped["B"] = true },
},
- "C": &InstrumentedServiceC{
- InstrumentedService{
- startHook: func() { started["C"] = true },
- stopHook: func() { stopped["C"] = true },
- },
+ "C": &InstrumentedService{
+ startHook: func() { started["C"] = true },
+ stopHook: func() { stopped["C"] = true },
},
}
// register lifecycles on node
diff --git a/node/utils_test.go b/node/utils_test.go
index 481edd6d4822..44c83e22da75 100644
--- a/node/utils_test.go
+++ b/node/utils_test.go
@@ -51,14 +51,6 @@ type InstrumentedService struct {
protocols []p2p.Protocol
}
-type InstrumentedServiceA struct{ InstrumentedService }
-type InstrumentedServiceB struct{ InstrumentedService }
-type InstrumentedServiceC struct{ InstrumentedService }
-
-func NewInstrumentedService() (*InstrumentedService, error) {
- return new(InstrumentedService), nil
-}
-
func (s *InstrumentedService) Start() error {
if s.startHook != nil {
s.startHook()
From a23b6506640ab5c8cc0098849a177673272c9df2 Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Wed, 22 Jul 2020 12:36:03 +0200
Subject: [PATCH 127/160] node: add test for database auto-closing
---
node/node.go | 32 +++++++++++++++++++-----------
node/node_test.go | 50 +++++++++++++++++++++++++++++++----------------
2 files changed, 54 insertions(+), 28 deletions(-)
diff --git a/node/node.go b/node/node.go
index 93b949acaa5b..a53eadc4fd05 100644
--- a/node/node.go
+++ b/node/node.go
@@ -622,10 +622,15 @@ func (n *Node) OpenDatabase(name string, cache, handles int, namespace string) (
if n.runstate == stoppedState {
return nil, ErrNodeStopped
}
+
+ var db ethdb.Database
+ var err error
if n.config.DataDir == "" {
- return rawdb.NewMemoryDatabase(), nil
+ db = rawdb.NewMemoryDatabase()
+ } else {
+ db, err = rawdb.NewLevelDBDatabase(n.ResolvePath(name), cache, handles, namespace)
}
- db, err := rawdb.NewLevelDBDatabase(n.ResolvePath(name), cache, handles, namespace)
+
if err == nil {
db = n.wrapDatabase(db)
}
@@ -644,17 +649,22 @@ func (n *Node) OpenDatabaseWithFreezer(name string, cache, handles int, freezer,
if n.runstate == stoppedState {
return nil, ErrNodeStopped
}
+
+ var db ethdb.Database
+ var err error
if n.config.DataDir == "" {
- return rawdb.NewMemoryDatabase(), nil
- }
- root := n.ResolvePath(name)
- switch {
- case freezer == "":
- freezer = filepath.Join(root, "ancient")
- case !filepath.IsAbs(freezer):
- freezer = n.ResolvePath(freezer)
+ db = rawdb.NewMemoryDatabase()
+ } else {
+ root := n.ResolvePath(name)
+ switch {
+ case freezer == "":
+ freezer = filepath.Join(root, "ancient")
+ case !filepath.IsAbs(freezer):
+ freezer = n.ResolvePath(freezer)
+ }
+ db, err = rawdb.NewLevelDBDatabaseWithFreezer(root, cache, handles, freezer, namespace)
}
- db, err := rawdb.NewLevelDBDatabaseWithFreezer(root, cache, handles, freezer, namespace)
+
if err == nil {
db = n.wrapDatabase(db)
}
diff --git a/node/node_test.go b/node/node_test.go
index 4d04fd7ceaff..9c421be9435a 100644
--- a/node/node_test.go
+++ b/node/node_test.go
@@ -151,30 +151,28 @@ func TestRegisterProtocols(t *testing.T) {
}
}
-func containsProtocol(stackProtocols []p2p.Protocol, protocol p2p.Protocol) bool {
- for _, a := range stackProtocols {
- if reflect.DeepEqual(a, protocol) {
- return true
- }
+// This test checks that open databases are closed with node.
+func TestCloseNodeClosesDB(t *testing.T) {
+ stack, _ := New(testNodeConfig())
+ defer stack.Close()
+
+ db, err := stack.OpenDatabase("mydb", 0, 0, "")
+ if err != nil {
+ t.Fatal("can't open DB:", err)
+ }
+ if err = db.Put([]byte{}, []byte{}); err != nil {
+ t.Fatal("can't put on open DB:", err)
}
- return false
-}
-func containsAPI(stackAPIs []rpc.API, api rpc.API) bool {
- for _, a := range stackAPIs {
- if reflect.DeepEqual(a, api) {
- return true
- }
+ stack.Close()
+ if err = db.Put([]byte{}, []byte{}); err == nil {
+ t.Fatal("put succeeded after node is closed")
}
- return false
}
// Tests that registered Lifecycles get started and stopped correctly.
func TestLifecycleLifeCycle(t *testing.T) {
- stack, err := New(testNodeConfig())
- if err != nil {
- t.Fatalf("failed to create protocol stack: %v", err)
- }
+ stack, _ := New(testNodeConfig())
defer stack.Close()
started := make(map[string]bool)
@@ -547,3 +545,21 @@ func doHTTPRequest(t *testing.T, req *http.Request) *http.Response {
}
return resp
}
+
+func containsProtocol(stackProtocols []p2p.Protocol, protocol p2p.Protocol) bool {
+ for _, a := range stackProtocols {
+ if reflect.DeepEqual(a, protocol) {
+ return true
+ }
+ }
+ return false
+}
+
+func containsAPI(stackAPIs []rpc.API, api rpc.API) bool {
+ for _, a := range stackAPIs {
+ if reflect.DeepEqual(a, api) {
+ return true
+ }
+ }
+ return false
+}
From 0a5312afb1dbec3df94bfe1af4bfd9b73adccb61 Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Wed, 22 Jul 2020 18:18:15 +0200
Subject: [PATCH 128/160] node: WIP TestNodeOpenDatabaseFromLifecycle
This is a lot more complicated than I thought...
---
node/node.go | 108 ++++++++++++++++++++++++++++++++--------------
node/node_test.go | 30 +++++++++++--
2 files changed, 102 insertions(+), 36 deletions(-)
diff --git a/node/node.go b/node/node.go
index a53eadc4fd05..a490698079bb 100644
--- a/node/node.go
+++ b/node/node.go
@@ -65,8 +65,10 @@ type Node struct {
const (
initializingState = iota
+ startingState
+ closedWhileStartingState
runningState
- stoppedState
+ closedState
)
// New creates a new P2P node, ready for protocol registration.
@@ -180,20 +182,45 @@ func New(conf *Config) (*Node, error) {
// Node constructor New.
func (n *Node) Close() error {
n.lock.Lock()
- defer n.lock.Unlock()
- var errs []error
switch n.runstate {
- case stoppedState:
- return ErrNodeStopped
+ case initializingState:
+ // The node was never started.
+ defer n.lock.Unlock()
+ return n.doClose(nil)
+ case startingState:
+ // The node is currently starting lifecycles. Signal that
+ // Close was called through runstate to make Start stop
+ // everything when it re-acquires the lock.
+ n.runstate = closedWhileStartingState
+ n.lock.Unlock()
+ n.Wait()
+ return nil
+ case closedWhileStartingState:
+ // This branch handles double-close during startup.
+ n.lock.Unlock()
+ n.Wait()
+ return nil
case runningState:
// The node was started, release resources acquired by Start().
+ defer n.lock.Unlock()
+ var errs []error
if err := n.stopServices(); err != nil {
errs = append(errs, err)
}
+ return n.doClose(errs)
+ case closedState:
+ // Shutdown is already over.
+ n.lock.Unlock()
+ return ErrNodeStopped
+ default:
+ defer n.lock.Unlock()
+ panic(fmt.Sprintf("BUG: node is in unexpected state %d", n.runstate))
}
+}
- // Release resources acquired by New().
+// doClose releases resources acquired by New() and collects shutdown errors.
+func (n *Node) doClose(errs []error) error {
if err := n.accman.Close(); err != nil {
errs = append(errs, err)
}
@@ -204,7 +231,7 @@ func (n *Node) Close() error {
}
errs = append(errs, n.closeDatabases()...)
n.closeDataDir()
- n.runstate = stoppedState
+ n.runstate = closedState
// Unblock n.Wait.
close(n.stop)
@@ -305,46 +332,62 @@ func (n *Node) createHTTPServer(h *httpServer, exposeAll bool) error {
}
// Start starts all registered lifecycles, RPC services and p2p networking.
+// Node can only be started once.
func (n *Node) Start() error {
n.lock.Lock()
defer n.lock.Unlock()
- // Node can only be started when it
switch n.runstate {
- case runningState:
+ case runningState, startingState:
return ErrNodeRunning
- case stoppedState:
+ case closedState, closedWhileStartingState:
return ErrNodeStopped
}
-
- // Start the p2p node
- if err := n.server.Start(); err != nil {
- return convertFileLockError(err)
+ if n.runstate != initializingState {
+ panic(fmt.Sprintf("BUG: node is in unexpected state %d", n.runstate))
}
- n.log.Info("Starting peer-to-peer node", "instance", n.server.Name)
-
- // Configure the RPC interfaces
- if err := n.configureRPC(); err != nil {
- n.httpServers.Stop()
- n.server.Stop()
- n.runstate = stoppedState
+ if err := n.startNetworking(); err != nil {
+ n.runstate = closedState
return err
}
+ n.runstate = startingState
- // Start all registered lifecycles
+ // Start all registered lifecycles. The node lock mustn't
+ // be held here because the Start methods of lifecycle objects
+ // might want to access resources on the node.
+ n.lock.Unlock()
var started []Lifecycle
+ var startErr error
for _, lifecycle := range n.lifecycles {
- if err := lifecycle.Start(); err != nil {
- stopLifecycles(started)
- n.server.Stop()
- n.runstate = stoppedState
- return err
+ if startErr = lifecycle.Start(); startErr != nil {
+ break
}
started = append(started, lifecycle)
}
+ n.lock.Lock()
- n.runstate = runningState
- return nil
+ // Check if any lifecycle failed to start or the node was closed while starting.
+ if startErr != nil || n.runstate == closedWhileStartingState {
+ stopLifecycles(started)
+ n.doClose(nil)
+ } else {
+ n.runstate = runningState
+ }
+ return startErr
+}
+
+// startNetworking starts all network endpoints.
+func (n *Node) startNetworking() error {
+ n.log.Info("Starting peer-to-peer node", "instance", n.server.Name)
+ if err := n.server.Start(); err != nil {
+ return convertFileLockError(err)
+ }
+ err := n.configureRPC()
+ if err != nil {
+ n.httpServers.Stop()
+ n.server.Stop()
+ }
+ return err
}
// containsLifecycle checks if 'lfs' contains 'l'.
@@ -495,7 +538,6 @@ func (n *Node) stopIPC() {
if n.ipc.Listener != nil {
n.ipc.Listener.Close()
n.ipc.Listener = nil
-
n.log.Info("IPC endpoint closed", "url", n.ipc.endpoint)
}
if n.ipc.Srv != nil {
@@ -555,7 +597,7 @@ func (n *Node) RPCHandler() (*rpc.Server, error) {
n.lock.Lock()
defer n.lock.Unlock()
- if n.runstate == stoppedState {
+ if n.runstate == closedState {
return nil, ErrNodeStopped
}
return n.inprocHandler, nil
@@ -619,7 +661,7 @@ func (n *Node) OpenDatabase(name string, cache, handles int, namespace string) (
n.lock.Lock()
defer n.lock.Unlock()
- if n.runstate == stoppedState {
+ if n.runstate == closedState {
return nil, ErrNodeStopped
}
@@ -646,7 +688,7 @@ func (n *Node) OpenDatabaseWithFreezer(name string, cache, handles int, freezer,
n.lock.Lock()
defer n.lock.Unlock()
- if n.runstate == stoppedState {
+ if n.runstate == closedState {
return nil, ErrNodeStopped
}
diff --git a/node/node_test.go b/node/node_test.go
index 9c421be9435a..e57952105d32 100644
--- a/node/node_test.go
+++ b/node/node_test.go
@@ -28,6 +28,7 @@ import (
"testing"
"github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/rpc"
@@ -152,7 +153,7 @@ func TestRegisterProtocols(t *testing.T) {
}
// This test checks that open databases are closed with node.
-func TestCloseNodeClosesDB(t *testing.T) {
+func TestNodeCloseClosesDB(t *testing.T) {
stack, _ := New(testNodeConfig())
defer stack.Close()
@@ -161,15 +162,38 @@ func TestCloseNodeClosesDB(t *testing.T) {
t.Fatal("can't open DB:", err)
}
if err = db.Put([]byte{}, []byte{}); err != nil {
- t.Fatal("can't put on open DB:", err)
+ t.Fatal("can't Put on open DB:", err)
}
stack.Close()
if err = db.Put([]byte{}, []byte{}); err == nil {
- t.Fatal("put succeeded after node is closed")
+ t.Fatal("Put succeeded after node is closed")
}
}
+// This test checks that OpenDatabase can be used from within a Lifecycle Start method.
+func TestNodeOpenDatabaseFromLifecycle(t *testing.T) {
+ stack, _ := New(testNodeConfig())
+ defer stack.Close()
+
+ var db ethdb.Database
+ var err error
+ stack.RegisterLifecycle(&InstrumentedService{
+ startHook: func() {
+ db, err = stack.OpenDatabase("mydb", 0, 0, "")
+ if err != nil {
+ t.Fatal("can't open DB:", err)
+ }
+ },
+ stopHook: func() {
+ db.Close()
+ },
+ })
+
+ stack.Start()
+ stack.Close()
+}
+
// Tests that registered Lifecycles get started and stopped correctly.
func TestLifecycleLifeCycle(t *testing.T) {
stack, _ := New(testNodeConfig())
From 39dbf650ca1661aa9ae6a873ec0888a052e30df1 Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Wed, 22 Jul 2020 18:29:21 +0200
Subject: [PATCH 129/160] node: move Start up
---
node/node.go | 90 ++++++++++++++++++++++++++--------------------------
1 file changed, 45 insertions(+), 45 deletions(-)
diff --git a/node/node.go b/node/node.go
index a490698079bb..222e68ffd32d 100644
--- a/node/node.go
+++ b/node/node.go
@@ -178,6 +178,51 @@ func New(conf *Config) (*Node, error) {
return node, nil
}
+// Start starts all registered lifecycles, RPC services and p2p networking.
+// Node can only be started once.
+func (n *Node) Start() error {
+ n.lock.Lock()
+ defer n.lock.Unlock()
+
+ switch n.runstate {
+ case runningState, startingState:
+ return ErrNodeRunning
+ case closedState, closedWhileStartingState:
+ return ErrNodeStopped
+ }
+ if n.runstate != initializingState {
+ panic(fmt.Sprintf("BUG: node is in unexpected state %d", n.runstate))
+ }
+ if err := n.startNetworking(); err != nil {
+ n.doClose(nil)
+ return err
+ }
+ n.runstate = startingState
+
+ // Start all registered lifecycles. The node lock mustn't
+ // be held here because the Start methods of lifecycle objects
+ // might want to access resources on the node.
+ n.lock.Unlock()
+ var started []Lifecycle
+ var startErr error
+ for _, lifecycle := range n.lifecycles {
+ if startErr = lifecycle.Start(); startErr != nil {
+ break
+ }
+ started = append(started, lifecycle)
+ }
+ n.lock.Lock()
+
+ // Check if any lifecycle failed to start or the node was closed while starting.
+ if startErr != nil || n.runstate == closedWhileStartingState {
+ stopLifecycles(started)
+ n.doClose(nil)
+ } else {
+ n.runstate = runningState
+ }
+ return startErr
+}
+
// Close stops the Node and releases resources acquired in
// Node constructor New.
func (n *Node) Close() error {
@@ -331,51 +376,6 @@ func (n *Node) createHTTPServer(h *httpServer, exposeAll bool) error {
return nil
}
-// Start starts all registered lifecycles, RPC services and p2p networking.
-// Node can only be started once.
-func (n *Node) Start() error {
- n.lock.Lock()
- defer n.lock.Unlock()
-
- switch n.runstate {
- case runningState, startingState:
- return ErrNodeRunning
- case closedState, closedWhileStartingState:
- return ErrNodeStopped
- }
- if n.runstate != initializingState {
- panic(fmt.Sprintf("BUG: node is in unexpected state %d", n.runstate))
- }
- if err := n.startNetworking(); err != nil {
- n.runstate = closedState
- return err
- }
- n.runstate = startingState
-
- // Start all registered lifecycles. The node lock mustn't
- // be held here because the Start methods of lifecycle objects
- // might want to access resources on the node.
- n.lock.Unlock()
- var started []Lifecycle
- var startErr error
- for _, lifecycle := range n.lifecycles {
- if startErr = lifecycle.Start(); startErr != nil {
- break
- }
- started = append(started, lifecycle)
- }
- n.lock.Lock()
-
- // Check if any lifecycle failed to start or the node was closed while starting.
- if startErr != nil || n.runstate == closedWhileStartingState {
- stopLifecycles(started)
- n.doClose(nil)
- } else {
- n.runstate = runningState
- }
- return startErr
-}
-
// startNetworking starts all network endpoints.
func (n *Node) startNetworking() error {
n.log.Info("Starting peer-to-peer node", "instance", n.server.Name)
From 6a16cbef94367a45889a94cadaf34857700c02ec Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Wed, 22 Jul 2020 23:09:40 +0200
Subject: [PATCH 130/160] node: simplify Start/Stop concurrency handling
---
node/node.go | 285 ++++++++++++++++++++++------------------------
node/node_test.go | 21 +++-
2 files changed, 157 insertions(+), 149 deletions(-)
diff --git a/node/node.go b/node/node.go
index 222e68ffd32d..62c4f62674ff 100644
--- a/node/node.go
+++ b/node/node.go
@@ -50,27 +50,33 @@ type Node struct {
dirLock fileutil.Releaser // prevents concurrent use of instance directory
stop chan struct{} // Channel to wait for termination notifications
server *p2p.Server // Currently running P2P networking layer
+ startStopLock sync.Mutex // Start/Stop are protected by an additional lock
+ stateFlag int32 // Tracks state of node lifecycle
lock sync.Mutex
- runstate int
lifecycles []Lifecycle // All registered backends, services, and auxiliary services that have a lifecycle
httpServers serverMap // serverMap stores information about the node's rpc, ws, and graphQL http servers.
inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
rpcAPIs []rpc.API // List of APIs currently provided by the node
ipc *httpServer // Stores information about the ipc http server
- dbLock sync.Mutex
- databases map[*closeTrackingDB]struct{} // all opened databases
+ databases map[*closeTrackingDB]struct{} // All open databases
}
const (
initializingState = iota
- startingState
- closedWhileStartingState
runningState
closedState
)
+func (n *Node) state() int32 {
+ return atomic.LoadInt32(&n.stateFlag)
+}
+
+func (n *Node) setState(state int32) {
+ atomic.StoreInt32(&n.stateFlag, state)
+}
+
// New creates a new P2P node, ready for protocol registration.
func New(conf *Config) (*Node, error) {
// Copy config and resolve the datadir so future changes to the current
@@ -84,6 +90,9 @@ func New(conf *Config) (*Node, error) {
}
conf.DataDir = absdatadir
}
+ if conf.Logger == nil {
+ conf.Logger = log.New()
+ }
// Ensure that the instance name doesn't cause weird conflicts with
// other files in the data directory.
@@ -97,9 +106,6 @@ func New(conf *Config) (*Node, error) {
return nil, errors.New(`Config.Name cannot end in ".ipc"`)
}
- if conf.Logger == nil {
- conf.Logger = log.New()
- }
node := &Node{
config: conf,
httpServers: make(serverMap),
@@ -112,6 +118,9 @@ func New(conf *Config) (*Node, error) {
databases: make(map[*closeTrackingDB]struct{}),
}
+ // Register built-in APIs.
+ node.rpcAPIs = append(node.rpcAPIs, node.apis()...)
+
// Acquire the instance directory lock.
if err := node.openDataDir(); err != nil {
return nil, err
@@ -181,91 +190,72 @@ func New(conf *Config) (*Node, error) {
// Start starts all registered lifecycles, RPC services and p2p networking.
// Node can only be started once.
func (n *Node) Start() error {
- n.lock.Lock()
- defer n.lock.Unlock()
+ n.startStopLock.Lock()
+ defer n.startStopLock.Unlock()
- switch n.runstate {
- case runningState, startingState:
+ switch n.state() {
+ case runningState:
return ErrNodeRunning
- case closedState, closedWhileStartingState:
+ case closedState:
return ErrNodeStopped
}
- if n.runstate != initializingState {
- panic(fmt.Sprintf("BUG: node is in unexpected state %d", n.runstate))
- }
- if err := n.startNetworking(); err != nil {
+ n.setState(runningState)
+
+ n.lock.Lock()
+ err := n.startNetworking()
+ lifecycles := make([]Lifecycle, len(n.lifecycles))
+ copy(lifecycles, n.lifecycles)
+ n.lock.Unlock()
+
+ // Check if networking startup failed.
+ if err != nil {
n.doClose(nil)
return err
}
- n.runstate = startingState
-
- // Start all registered lifecycles. The node lock mustn't
- // be held here because the Start methods of lifecycle objects
- // might want to access resources on the node.
- n.lock.Unlock()
+ // Start all registered lifecycles.
var started []Lifecycle
- var startErr error
- for _, lifecycle := range n.lifecycles {
- if startErr = lifecycle.Start(); startErr != nil {
+ for _, lifecycle := range lifecycles {
+ if err = lifecycle.Start(); err != nil {
break
}
started = append(started, lifecycle)
}
- n.lock.Lock()
-
- // Check if any lifecycle failed to start or the node was closed while starting.
- if startErr != nil || n.runstate == closedWhileStartingState {
- stopLifecycles(started)
+ // Check if any lifecycle failed to start.
+ if err != nil {
+ n.stopServices(started)
n.doClose(nil)
- } else {
- n.runstate = runningState
}
- return startErr
+ return err
}
// Close stops the Node and releases resources acquired in
// Node constructor New.
func (n *Node) Close() error {
- n.lock.Lock()
+ n.startStopLock.Lock()
+ defer n.startStopLock.Unlock()
- switch n.runstate {
+ switch state := n.state(); state {
case initializingState:
// The node was never started.
- defer n.lock.Unlock()
return n.doClose(nil)
- case startingState:
- // The node is currently starting lifecycles. Signal that
- // Close was called through runstate to make Start stop
- // everything when it re-acquires the lock.
- n.runstate = closedWhileStartingState
- n.lock.Unlock()
- n.Wait()
- return nil
- case closedWhileStartingState:
- // This branch handles double-close during startup.
- n.lock.Unlock()
- n.Wait()
- return nil
case runningState:
// The node was started, release resources acquired by Start().
- defer n.lock.Unlock()
var errs []error
- if err := n.stopServices(); err != nil {
+ if err := n.stopServices(n.lifecycles); err != nil {
errs = append(errs, err)
}
return n.doClose(errs)
case closedState:
- // Shutdown is already over.
- n.lock.Unlock()
return ErrNodeStopped
default:
- defer n.lock.Unlock()
- panic(fmt.Sprintf("BUG: node is in unexpected state %d", n.runstate))
+ panic(fmt.Sprintf("node is in unknown state %d", state))
}
}
-// doClose releases resources acquired by New() and collects shutdown errors.
+// doClose releases resources acquired by New(), collecting errors.
func (n *Node) doClose(errs []error) error {
+ n.setState(closedState)
+
if err := n.accman.Close(); err != nil {
errs = append(errs, err)
}
@@ -274,9 +264,15 @@ func (n *Node) doClose(errs []error) error {
errs = append(errs, err)
}
}
+
+ // Close databases. This needs the lock because it needs to
+ // synchronize with OpenDatabase*.
+ n.lock.Lock()
errs = append(errs, n.closeDatabases()...)
+ n.lock.Unlock()
+
+ // Release instance directory lock.
n.closeDataDir()
- n.runstate = closedState
// Unblock n.Wait.
close(n.stop)
@@ -292,48 +288,6 @@ func (n *Node) doClose(errs []error) error {
}
}
-// RegisterLifecycle registers the given Lifecycle on the node.
-func (n *Node) RegisterLifecycle(lifecycle Lifecycle) {
- if n.runstate != initializingState {
- panic("can't register lifecycle on running/stopped node")
- }
- if containsLifecycle(n.lifecycles, lifecycle) {
- panic(fmt.Sprintf("attempt to register lifecycle %T more than once", lifecycle))
- }
- n.lifecycles = append(n.lifecycles, lifecycle)
-}
-
-// RegisterProtocols adds backend's protocols to the node's p2p server.
-func (n *Node) RegisterProtocols(protocols []p2p.Protocol) {
- if n.runstate != initializingState {
- panic("can't register protocols on running/stopped node")
- }
- n.server.Protocols = append(n.server.Protocols, protocols...)
-}
-
-// RegisterAPIs registers the APIs a service provides on the node.
-func (n *Node) RegisterAPIs(apis []rpc.API) {
- if n.runstate != initializingState {
- panic("can't register APIs on running/stopped node")
- }
- n.rpcAPIs = append(n.rpcAPIs, apis...)
-}
-
-// RegisterPath mounts the given handler on the given path on the canonical HTTP server.
-func (n *Node) RegisterPath(path string, handler http.Handler) string {
- if n.runstate != initializingState {
- panic("can't register HTTP handler on running/stopped node")
- }
- for _, server := range n.httpServers {
- if atomic.LoadInt32(&server.RPCAllowed) == 1 {
- server.srvMux.Handle(path, handler)
- return server.endpoint
- }
- }
- n.log.Warn(fmt.Sprintf("HTTP server not configured on node, path %s cannot be enabled", path))
- return ""
-}
-
// registerHTTPServer registers the given HTTP server on the node.
func (n *Node) registerHTTPServer(endpoint string, server *httpServer) {
n.httpServers[endpoint] = server
@@ -400,20 +354,27 @@ func containsLifecycle(lfs []Lifecycle, l Lifecycle) bool {
return false
}
-// stopLifecycles stops the given lifecycles in reverse order.
-func stopLifecycles(lfs []Lifecycle) map[reflect.Type]error {
- errors := make(map[reflect.Type]error)
- for i := len(lfs) - 1; i >= 0; i-- {
- if err := lfs[i].Stop(); err != nil {
- errors[reflect.TypeOf(lfs[i])] = err
+// stopServices terminates running services, RPC and p2p networking.
+// It is the inverse of Start.
+func (n *Node) stopServices(running []Lifecycle) error {
+ n.stopIPC()
+ n.rpcAPIs = nil
+
+ // Stop running lifecycles in reverse order.
+ failure := &StopError{Services: make(map[reflect.Type]error)}
+ for i := len(running) - 1; i >= 0; i-- {
+ if err := running[i].Stop(); err != nil {
+ failure.Services[reflect.TypeOf(running[i])] = err
}
}
- return errors
-}
-// Config returns the configuration of node.
-func (n *Node) Config() *Config {
- return n.config
+ // Stop p2p networking.
+ n.server.Stop()
+
+ if len(failure.Services) > 0 {
+ return failure
+ }
+ return nil
}
func (n *Node) openDataDir() error {
@@ -449,8 +410,6 @@ func (n *Node) closeDataDir() {
// startup. It's not meant to be called at any time afterwards as it makes certain
// assumptions about the state of the node.
func (n *Node) configureRPC() error {
- n.RegisterAPIs(n.apis())
-
// Start the various API endpoints, terminating all in case of errors
if err := n.startInProc(); err != nil {
return err
@@ -459,25 +418,22 @@ func (n *Node) configureRPC() error {
n.stopInProc()
return err
}
- // configure HTTPServers
+
+ // Configure HTTP servers.
for _, server := range n.httpServers {
- // configure the handlers
handler := n.createHandler(server)
if handler != nil {
server.srvMux.Handle("/", handler)
}
- // create the HTTP server
if err := n.createHTTPServer(server, false); err != nil {
return err
}
}
- // only register http server as a lifecycle if it has not already been registered
+ // Register HTTP server as a lifecycle if it has not already been registered.
if !containsLifecycle(n.lifecycles, &n.httpServers) {
- n.RegisterLifecycle(&n.httpServers)
+ n.lifecycles = append(n.lifecycles, &n.httpServers)
}
-
- // All API endpoints started successfully
return nil
}
@@ -562,29 +518,63 @@ func (n *Node) stopServer(server *httpServer) {
delete(n.httpServers, server.endpoint)
}
-// stopServices terminates running services, RPC and p2p networking.
-// It is the inverse of Start.
-func (n *Node) stopServices() error {
- if n.runstate != runningState {
- panic("call to stopServices on node that isn't running")
+// Wait blocks until the node is closed.
+func (n *Node) Wait() {
+ <-n.stop
+}
+
+// RegisterLifecycle registers the given Lifecycle on the node.
+func (n *Node) RegisterLifecycle(lifecycle Lifecycle) {
+ n.lock.Lock()
+ defer n.lock.Unlock()
+
+ if n.state() != initializingState {
+ panic("can't register lifecycle on running/stopped node")
+ }
+ if containsLifecycle(n.lifecycles, lifecycle) {
+ panic(fmt.Sprintf("attempt to register lifecycle %T more than once", lifecycle))
}
+ n.lifecycles = append(n.lifecycles, lifecycle)
+}
- // Terminate the API, services and the p2p server.
- n.stopIPC()
- n.rpcAPIs = nil
- failure := new(StopError)
- failure.Services = stopLifecycles(n.lifecycles)
- n.server.Stop()
+// RegisterProtocols adds backend's protocols to the node's p2p server.
+func (n *Node) RegisterProtocols(protocols []p2p.Protocol) {
+ n.lock.Lock()
+ defer n.lock.Unlock()
- if len(failure.Services) > 0 {
- return failure
+ if n.state() != initializingState {
+ panic("can't register protocols on running/stopped node")
}
- return nil
+ n.server.Protocols = append(n.server.Protocols, protocols...)
}
-// Wait blocks until the node is closed.
-func (n *Node) Wait() {
- <-n.stop
+// RegisterAPIs registers the APIs a service provides on the node.
+func (n *Node) RegisterAPIs(apis []rpc.API) {
+ n.lock.Lock()
+ defer n.lock.Unlock()
+
+ if n.state() != initializingState {
+ panic("can't register APIs on running/stopped node")
+ }
+ n.rpcAPIs = append(n.rpcAPIs, apis...)
+}
+
+// RegisterPath mounts the given handler on the given path on the canonical HTTP server.
+func (n *Node) RegisterPath(path string, handler http.Handler) string {
+ n.lock.Lock()
+ defer n.lock.Unlock()
+
+ if n.state() != initializingState {
+ panic("can't register HTTP handler on running/stopped node")
+ }
+ for _, server := range n.httpServers {
+ if atomic.LoadInt32(&server.RPCAllowed) == 1 {
+ server.srvMux.Handle(path, handler)
+ return server.endpoint
+ }
+ }
+ n.log.Warn(fmt.Sprintf("HTTP server not configured on node, path %s cannot be enabled", path))
+ return ""
}
// Attach creates an RPC client attached to an in-process API handler.
@@ -597,12 +587,17 @@ func (n *Node) RPCHandler() (*rpc.Server, error) {
n.lock.Lock()
defer n.lock.Unlock()
- if n.runstate == closedState {
+ if n.state() == closedState {
return nil, ErrNodeStopped
}
return n.inprocHandler, nil
}
+// Config returns the configuration of node.
+func (n *Node) Config() *Config {
+ return n.config
+}
+
// Server retrieves the currently running P2P network layer. This method is meant
// only to inspect fields of the currently running server. Callers should not
// start or stop the returned server.
@@ -661,7 +656,7 @@ func (n *Node) OpenDatabase(name string, cache, handles int, namespace string) (
n.lock.Lock()
defer n.lock.Unlock()
- if n.runstate == closedState {
+ if n.state() == closedState {
return nil, ErrNodeStopped
}
@@ -688,7 +683,7 @@ func (n *Node) OpenDatabaseWithFreezer(name string, cache, handles int, freezer,
n.lock.Lock()
defer n.lock.Unlock()
- if n.runstate == closedState {
+ if n.state() == closedState {
return nil, ErrNodeStopped
}
@@ -752,17 +747,14 @@ type closeTrackingDB struct {
}
func (db *closeTrackingDB) Close() error {
- db.n.dbLock.Lock()
+ db.n.lock.Lock()
delete(db.n.databases, db)
- db.n.dbLock.Unlock()
+ db.n.lock.Unlock()
return db.Database.Close()
}
// wrapDatabase ensures the database will be auto-closed when Node is closed.
func (n *Node) wrapDatabase(db ethdb.Database) ethdb.Database {
- n.dbLock.Lock()
- defer n.dbLock.Unlock()
-
wrapper := &closeTrackingDB{db, n}
n.databases[wrapper] = struct{}{}
return wrapper
@@ -770,9 +762,6 @@ func (n *Node) wrapDatabase(db ethdb.Database) ethdb.Database {
// closeDatabases closes all open databases.
func (n *Node) closeDatabases() (errors []error) {
- n.dbLock.Lock()
- defer n.dbLock.Unlock()
-
for db := range n.databases {
delete(n.databases, db)
if err := db.Database.Close(); err != nil {
diff --git a/node/node_test.go b/node/node_test.go
index e57952105d32..f8df4b518b57 100644
--- a/node/node_test.go
+++ b/node/node_test.go
@@ -172,7 +172,7 @@ func TestNodeCloseClosesDB(t *testing.T) {
}
// This test checks that OpenDatabase can be used from within a Lifecycle Start method.
-func TestNodeOpenDatabaseFromLifecycle(t *testing.T) {
+func TestNodeOpenDatabaseFromLifecycleStart(t *testing.T) {
stack, _ := New(testNodeConfig())
defer stack.Close()
@@ -194,6 +194,25 @@ func TestNodeOpenDatabaseFromLifecycle(t *testing.T) {
stack.Close()
}
+// This test checks that OpenDatabase can be used from within a Lifecycle Stop method.
+func TestNodeOpenDatabaseFromLifecycleStop(t *testing.T) {
+ stack, _ := New(testNodeConfig())
+ defer stack.Close()
+
+ stack.RegisterLifecycle(&InstrumentedService{
+ stopHook: func() {
+ db, err := stack.OpenDatabase("mydb", 0, 0, "")
+ if err != nil {
+ t.Fatal("can't open DB:", err)
+ }
+ db.Close()
+ },
+ })
+
+ stack.Start()
+ stack.Close()
+}
+
// Tests that registered Lifecycles get started and stopped correctly.
func TestLifecycleLifeCycle(t *testing.T) {
stack, _ := New(testNodeConfig())
From cc9fdddc14e5f5e88a768b291cb2ecf5476f8ab6 Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Wed, 22 Jul 2020 23:14:44 +0200
Subject: [PATCH 131/160] node: unexport built-in API handler objects
---
node/api.go | 83 +++++++++++++++++++++++++++++-----------------------
node/node.go | 26 ----------------
2 files changed, 46 insertions(+), 63 deletions(-)
diff --git a/node/api.go b/node/api.go
index 0c81bf4827b9..39ba48b2a1ee 100644
--- a/node/api.go
+++ b/node/api.go
@@ -24,26 +24,46 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/internal/debug"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/rpc"
)
-// PrivateAdminAPI is the collection of administrative API methods exposed only
-// over a secure RPC channel.
-type PrivateAdminAPI struct {
- node *Node // Node interfaced by this API
+// apis returns the collection of built-in RPC APIs.
+func (n *Node) apis() []rpc.API {
+ return []rpc.API{
+ {
+ Namespace: "admin",
+ Version: "1.0",
+ Service: &privateAdminAPI{n},
+ }, {
+ Namespace: "admin",
+ Version: "1.0",
+ Service: &publicAdminAPI{n},
+ Public: true,
+ }, {
+ Namespace: "debug",
+ Version: "1.0",
+ Service: debug.Handler,
+ }, {
+ Namespace: "web3",
+ Version: "1.0",
+ Service: &publicWeb3API{n},
+ Public: true,
+ },
+ }
}
-// NewPrivateAdminAPI creates a new API definition for the private admin methods
-// of the node itself.
-func NewPrivateAdminAPI(node *Node) *PrivateAdminAPI {
- return &PrivateAdminAPI{node: node}
+// privateAdminAPI is the collection of administrative API methods exposed only
+// over a secure RPC channel.
+type privateAdminAPI struct {
+ node *Node // Node interfaced by this API
}
// AddPeer requests connecting to a remote node, and also maintaining the new
// connection at all times, even reconnecting if it is lost.
-func (api *PrivateAdminAPI) AddPeer(url string) (bool, error) {
+func (api *privateAdminAPI) AddPeer(url string) (bool, error) {
// Make sure the server is running, fail otherwise
server := api.node.Server()
if server == nil {
@@ -59,7 +79,7 @@ func (api *PrivateAdminAPI) AddPeer(url string) (bool, error) {
}
// RemovePeer disconnects from a remote node if the connection exists
-func (api *PrivateAdminAPI) RemovePeer(url string) (bool, error) {
+func (api *privateAdminAPI) RemovePeer(url string) (bool, error) {
// Make sure the server is running, fail otherwise
server := api.node.Server()
if server == nil {
@@ -75,7 +95,7 @@ func (api *PrivateAdminAPI) RemovePeer(url string) (bool, error) {
}
// AddTrustedPeer allows a remote node to always connect, even if slots are full
-func (api *PrivateAdminAPI) AddTrustedPeer(url string) (bool, error) {
+func (api *privateAdminAPI) AddTrustedPeer(url string) (bool, error) {
// Make sure the server is running, fail otherwise
server := api.node.Server()
if server == nil {
@@ -91,7 +111,7 @@ func (api *PrivateAdminAPI) AddTrustedPeer(url string) (bool, error) {
// RemoveTrustedPeer removes a remote node from the trusted peer set, but it
// does not disconnect it automatically.
-func (api *PrivateAdminAPI) RemoveTrustedPeer(url string) (bool, error) {
+func (api *privateAdminAPI) RemoveTrustedPeer(url string) (bool, error) {
// Make sure the server is running, fail otherwise
server := api.node.Server()
if server == nil {
@@ -107,7 +127,7 @@ func (api *PrivateAdminAPI) RemoveTrustedPeer(url string) (bool, error) {
// PeerEvents creates an RPC subscription which receives peer events from the
// node's p2p.Server
-func (api *PrivateAdminAPI) PeerEvents(ctx context.Context) (*rpc.Subscription, error) {
+func (api *privateAdminAPI) PeerEvents(ctx context.Context) (*rpc.Subscription, error) {
// Make sure the server is running, fail otherwise
server := api.node.Server()
if server == nil {
@@ -144,7 +164,7 @@ func (api *PrivateAdminAPI) PeerEvents(ctx context.Context) (*rpc.Subscription,
}
// StartRPC starts the HTTP RPC API server.
-func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis *string, vhosts *string) (bool, error) {
+func (api *privateAdminAPI) StartRPC(host *string, port *int, cors *string, apis *string, vhosts *string) (bool, error) {
api.node.lock.Lock()
defer api.node.lock.Unlock()
@@ -218,7 +238,7 @@ func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
}
// StopRPC terminates an already running HTTP RPC API endpoint.
-func (api *PrivateAdminAPI) StopRPC() (bool, error) {
+func (api *privateAdminAPI) StopRPC() (bool, error) {
api.node.lock.Lock()
defer api.node.lock.Unlock()
@@ -232,7 +252,7 @@ func (api *PrivateAdminAPI) StopRPC() (bool, error) {
}
// StartWS starts the websocket RPC API server.
-func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *string, apis *string) (bool, error) {
+func (api *privateAdminAPI) StartWS(host *string, port *int, allowedOrigins *string, apis *string) (bool, error) {
api.node.lock.Lock()
defer api.node.lock.Unlock()
@@ -307,7 +327,7 @@ func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
}
// StopWS terminates an already running websocket RPC API endpoint.
-func (api *PrivateAdminAPI) StopWS() (bool, error) {
+func (api *privateAdminAPI) StopWS() (bool, error) {
api.node.lock.Lock()
defer api.node.lock.Unlock()
@@ -323,21 +343,15 @@ func (api *PrivateAdminAPI) StopWS() (bool, error) {
return false, fmt.Errorf("WebSocket RPC not running")
}
-// PublicAdminAPI is the collection of administrative API methods exposed over
+// publicAdminAPI is the collection of administrative API methods exposed over
// both secure and unsecure RPC channels.
-type PublicAdminAPI struct {
+type publicAdminAPI struct {
node *Node // Node interfaced by this API
}
-// NewPublicAdminAPI creates a new API definition for the public admin methods
-// of the node itself.
-func NewPublicAdminAPI(node *Node) *PublicAdminAPI {
- return &PublicAdminAPI{node: node}
-}
-
// Peers retrieves all the information we know about each individual peer at the
// protocol granularity.
-func (api *PublicAdminAPI) Peers() ([]*p2p.PeerInfo, error) {
+func (api *publicAdminAPI) Peers() ([]*p2p.PeerInfo, error) {
server := api.node.Server()
if server == nil {
return nil, ErrNodeStopped
@@ -347,7 +361,7 @@ func (api *PublicAdminAPI) Peers() ([]*p2p.PeerInfo, error) {
// NodeInfo retrieves all the information we know about the host node at the
// protocol granularity.
-func (api *PublicAdminAPI) NodeInfo() (*p2p.NodeInfo, error) {
+func (api *publicAdminAPI) NodeInfo() (*p2p.NodeInfo, error) {
server := api.node.Server()
if server == nil {
return nil, ErrNodeStopped
@@ -356,27 +370,22 @@ func (api *PublicAdminAPI) NodeInfo() (*p2p.NodeInfo, error) {
}
// Datadir retrieves the current data directory the node is using.
-func (api *PublicAdminAPI) Datadir() string {
+func (api *publicAdminAPI) Datadir() string {
return api.node.DataDir()
}
-// PublicWeb3API offers helper utils
-type PublicWeb3API struct {
+// publicWeb3API offers helper utils
+type publicWeb3API struct {
stack *Node
}
-// NewPublicWeb3API creates a new Web3Service instance
-func NewPublicWeb3API(stack *Node) *PublicWeb3API {
- return &PublicWeb3API{stack}
-}
-
// ClientVersion returns the node name
-func (s *PublicWeb3API) ClientVersion() string {
+func (s *publicWeb3API) ClientVersion() string {
return s.stack.Server().Name
}
// Sha3 applies the ethereum sha3 implementation on the input.
// It assumes the input is hex encoded.
-func (s *PublicWeb3API) Sha3(input hexutil.Bytes) hexutil.Bytes {
+func (s *publicWeb3API) Sha3(input hexutil.Bytes) hexutil.Bytes {
return crypto.Keccak256(input)
}
diff --git a/node/node.go b/node/node.go
index 62c4f62674ff..c252f1e39cc7 100644
--- a/node/node.go
+++ b/node/node.go
@@ -33,7 +33,6 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
- "github.com/ethereum/go-ethereum/internal/debug"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/rpc"
@@ -713,31 +712,6 @@ func (n *Node) ResolvePath(x string) string {
return n.config.ResolvePath(x)
}
-// apis returns the collection of RPC descriptors this node offers.
-func (n *Node) apis() []rpc.API {
- return []rpc.API{
- {
- Namespace: "admin",
- Version: "1.0",
- Service: NewPrivateAdminAPI(n),
- }, {
- Namespace: "admin",
- Version: "1.0",
- Service: NewPublicAdminAPI(n),
- Public: true,
- }, {
- Namespace: "debug",
- Version: "1.0",
- Service: debug.Handler,
- }, {
- Namespace: "web3",
- Version: "1.0",
- Service: NewPublicWeb3API(n),
- Public: true,
- },
- }
-}
-
// closeTrackingDB wraps the Close method of a database. When the database is closed by the
// service, the wrapper removes it from the node's database map. This ensures that Node
// won't auto-close the database if it is closed by the service that opened it.
From 390e8a3df822122d9cfac4321db144b345050ab6 Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Wed, 22 Jul 2020 23:15:06 +0200
Subject: [PATCH 132/160] node: move RegisterApisFromWhitelist
---
node/node.go | 22 ----------------------
node/rpcstack.go | 22 ++++++++++++++++++++++
2 files changed, 22 insertions(+), 22 deletions(-)
diff --git a/node/node.go b/node/node.go
index c252f1e39cc7..ad5927a0ee63 100644
--- a/node/node.go
+++ b/node/node.go
@@ -744,25 +744,3 @@ func (n *Node) closeDatabases() (errors []error) {
}
return errors
}
-
-// RegisterApisFromWhitelist checks the given modules' availability, generates a whitelist based on the allowed modules,
-// and then registers all of the APIs exposed by the services.
-func RegisterApisFromWhitelist(apis []rpc.API, modules []string, srv *rpc.Server, exposeAll bool) error {
- if bad, available := checkModuleAvailability(modules, apis); len(bad) > 0 {
- log.Error("Unavailable modules in HTTP API list", "unavailable", bad, "available", available)
- }
- // Generate the whitelist based on the allowed modules
- whitelist := make(map[string]bool)
- for _, module := range modules {
- whitelist[module] = true
- }
- // Register all the APIs exposed by the services
- for _, api := range apis {
- if exposeAll || whitelist[api.Namespace] || (len(whitelist) == 0 && api.Public) {
- if err := srv.RegisterName(api.Namespace, api.Service); err != nil {
- return err
- }
- }
- }
- return nil
-}
diff --git a/node/rpcstack.go b/node/rpcstack.go
index 43716a4dbd66..aad54fa1945f 100644
--- a/node/rpcstack.go
+++ b/node/rpcstack.go
@@ -33,6 +33,28 @@ import (
"github.com/rs/cors"
)
+// RegisterApisFromWhitelist checks the given modules' availability, generates a whitelist based on the allowed modules,
+// and then registers all of the APIs exposed by the services.
+func RegisterApisFromWhitelist(apis []rpc.API, modules []string, srv *rpc.Server, exposeAll bool) error {
+ if bad, available := checkModuleAvailability(modules, apis); len(bad) > 0 {
+ log.Error("Unavailable modules in HTTP API list", "unavailable", bad, "available", available)
+ }
+ // Generate the whitelist based on the allowed modules
+ whitelist := make(map[string]bool)
+ for _, module := range modules {
+ whitelist[module] = true
+ }
+ // Register all the APIs exposed by the services
+ for _, api := range apis {
+ if exposeAll || whitelist[api.Namespace] || (len(whitelist) == 0 && api.Public) {
+ if err := srv.RegisterName(api.Namespace, api.Service); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
type serverMap map[string]*httpServer // Stores information about all http servers (if any) by their endpoint, including http, ws, and graphql
type httpServer struct {
From 908268d51e600ed732d03db0d1b5bf25004bd414 Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Wed, 22 Jul 2020 23:33:19 +0200
Subject: [PATCH 133/160] miner: fix test scripts
---
miner/stress_clique.go | 37 ++++++++++++++++++-------------------
miner/stress_ethash.go | 42 ++++++++++++++++++++----------------------
2 files changed, 38 insertions(+), 41 deletions(-)
diff --git a/miner/stress_clique.go b/miner/stress_clique.go
index d09538050164..dbb285e068b3 100644
--- a/miner/stress_clique.go
+++ b/miner/stress_clique.go
@@ -22,6 +22,7 @@ package main
import (
"bytes"
"crypto/ecdsa"
+ "fmt"
"io/ioutil"
"math/big"
"math/rand"
@@ -35,8 +36,9 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth"
- "github.com/ethereum/go-ethereum/internal/ethapi"
+ "github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/log"
+ "github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/enode"
@@ -62,38 +64,38 @@ func main() {
var (
nodes []struct {
node *node.Node
- backend ethapi.Backend
+ backend *eth.Ethereum
}
enodes []*enode.Node
)
for _, sealer := range sealers {
// Start the node and wait until it's up
- node, ethBackend, err := makeSealer(genesis)
+ stack, ethBackend, err := makeSealer(genesis)
if err != nil {
panic(err)
}
- defer node.Close()
+ defer stack.Close()
- for node.Server().NodeInfo().Ports.Listener == 0 {
+ for stack.Server().NodeInfo().Ports.Listener == 0 {
time.Sleep(250 * time.Millisecond)
}
// Connect the node to al the previous ones
for _, n := range enodes {
- node.Server().AddPeer(n)
+ stack.Server().AddPeer(n)
}
// Start tracking the node and it's enode
nodes = append(nodes, struct {
node *node.Node
- backend ethapi.Backend
+ backend *eth.Ethereum
}{
- node,
+ stack,
ethBackend,
})
- enodes = append(enodes, node.Server().Self())
+ enodes = append(enodes, stack.Server().Self())
// Inject the signer key and start sealing with it
- store := node.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
+ store := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
signer, err := store.ImportECDSA(sealer, "")
if err != nil {
panic(err)
@@ -178,7 +180,7 @@ func makeGenesis(faucets []*ecdsa.PrivateKey, sealers []*ecdsa.PrivateKey) *core
return genesis
}
-func makeSealer(genesis *core.Genesis) (*node.Node, ethapi.Backend, error) {
+func makeSealer(genesis *core.Genesis) (*node.Node, *eth.Ethereum, error) {
// Define the basic configurations for the Ethereum node
datadir, _ := ioutil.TempDir("", "")
@@ -196,10 +198,10 @@ func makeSealer(genesis *core.Genesis) (*node.Node, ethapi.Backend, error) {
// Start the node and configure a full Ethereum node on it
stack, err := node.New(config)
if err != nil {
- return nil, err
+ return nil, nil, err
}
// Create and register the backend
- ethBackend, err := eth.New(ctx, ð.Config{
+ ethBackend, err := eth.New(stack, ð.Config{
Genesis: genesis,
NetworkId: genesis.Config.ChainID.Uint64(),
SyncMode: downloader.FullSync,
@@ -215,12 +217,9 @@ func makeSealer(genesis *core.Genesis) (*node.Node, ethapi.Backend, error) {
},
})
if err != nil {
- return nil, err
+ return nil, nil, err
}
- stack.RegisterAPIs(ethBackend.APIs())
- stack.RegisterProtocols(ethBackend.Protocols())
- stack.RegisterLifecycle(ethBackend)
- // Start the node and return if successful
- return stack, ethBackend, stack.Start()
+ err = stack.Start()
+ return stack, ethBackend, err
}
diff --git a/miner/stress_ethash.go b/miner/stress_ethash.go
index 4e0a75174d3f..b6e3899a2335 100644
--- a/miner/stress_ethash.go
+++ b/miner/stress_ethash.go
@@ -21,6 +21,7 @@ package main
import (
"crypto/ecdsa"
+ "fmt"
"io/ioutil"
"math/big"
"math/rand"
@@ -61,39 +62,39 @@ func main() {
genesis := makeGenesis(faucets)
var (
- nodes []struct{
- node *node.Node
- backend ethapi.Backend
+ nodes []struct {
+ node *node.Node
+ backend *eth.Ethereum
}
enodes []*enode.Node
)
for i := 0; i < 4; i++ {
// Start the node and wait until it's up
- node, ethBackend, err := makeMiner(genesis)
+ stack, ethBackend, err := makeMiner(genesis)
if err != nil {
panic(err)
}
- defer node.Close()
+ defer stack.Close()
- for node.Server().NodeInfo().Ports.Listener == 0 {
+ for stack.Server().NodeInfo().Ports.Listener == 0 {
time.Sleep(250 * time.Millisecond)
}
// Connect the node to al the previous ones
for _, n := range enodes {
- node.Server().AddPeer(n)
+ stack.Server().AddPeer(n)
}
// Start tracking the node and it's enode
- nodes = append(nodes, struct{
- node *node.Node
- backend ethapi.Backend
+ nodes = append(nodes, struct {
+ node *node.Node
+ backend *eth.Ethereum
}{
- node,
+ stack,
ethBackend,
})
- enodes = append(enodes, node.Server().Self())
+ enodes = append(enodes, stack.Server().Self())
// Inject the signer key and start sealing with it
- store := node.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
+ store := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
if _, err := store.NewAccount(""); err != nil {
panic(err)
}
@@ -154,7 +155,7 @@ func makeGenesis(faucets []*ecdsa.PrivateKey) *core.Genesis {
return genesis
}
-func makeMiner(genesis *core.Genesis) (*node.Node, ethapi.Backend, error) {
+func makeMiner(genesis *core.Genesis) (*node.Node, *eth.Ethereum, error) {
// Define the basic configurations for the Ethereum node
datadir, _ := ioutil.TempDir("", "")
@@ -173,9 +174,9 @@ func makeMiner(genesis *core.Genesis) (*node.Node, ethapi.Backend, error) {
// Create the node and configure a full Ethereum node on it
stack, err := node.New(config)
if err != nil {
- return nil, err
+ return nil, nil, err
}
- ethBackend, err := eth.New(ctx, ð.Config{
+ ethBackend, err := eth.New(stack, ð.Config{
Genesis: genesis,
NetworkId: genesis.Config.ChainID.Uint64(),
SyncMode: downloader.FullSync,
@@ -192,12 +193,9 @@ func makeMiner(genesis *core.Genesis) (*node.Node, ethapi.Backend, error) {
},
})
if err != nil {
- return nil, err
+ return nil, nil, err
}
- stack.RegisterAPIs(ethBackend.APIs())
- stack.RegisterProtocols(ethBackend.Protocols())
- stack.RegisterLifecycle(ethBackend)
- // Start the node and return if successful
- return stack, ethBackend, stack.Start()
+ err = stack.Start()
+ return stack, ethBackend, err
}
From 891b286abfea85bb7767dc1b097c555d29ff8393 Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Wed, 22 Jul 2020 23:41:50 +0200
Subject: [PATCH 134/160] miner: simplify test scripts
---
miner/stress_clique.go | 24 +++++++-----------------
miner/stress_ethash.go | 26 +++++++++-----------------
2 files changed, 16 insertions(+), 34 deletions(-)
diff --git a/miner/stress_clique.go b/miner/stress_clique.go
index dbb285e068b3..a4bbb9d22112 100644
--- a/miner/stress_clique.go
+++ b/miner/stress_clique.go
@@ -62,10 +62,7 @@ func main() {
genesis := makeGenesis(faucets, sealers)
var (
- nodes []struct {
- node *node.Node
- backend *eth.Ethereum
- }
+ nodes []*eth.Ethereum
enodes []*enode.Node
)
@@ -85,13 +82,7 @@ func main() {
stack.Server().AddPeer(n)
}
// Start tracking the node and it's enode
- nodes = append(nodes, struct {
- node *node.Node
- backend *eth.Ethereum
- }{
- stack,
- ethBackend,
- })
+ nodes = append(nodes, ethBackend)
enodes = append(enodes, stack.Server().Self())
// Inject the signer key and start sealing with it
@@ -104,11 +95,11 @@ func main() {
panic(err)
}
}
- // Iterate over all the nodes and start signing with them
- time.Sleep(3 * time.Second)
+ // Iterate over all the nodes and start signing on them
+ time.Sleep(3 * time.Second)
for _, node := range nodes {
- if err := node.backend.StartMining(1); err != nil {
+ if err := node.StartMining(1); err != nil {
panic(err)
}
}
@@ -117,10 +108,9 @@ func main() {
// Start injecting transactions from the faucet like crazy
nonces := make([]uint64, len(faucets))
for {
+ // Pick a random signer node
index := rand.Intn(len(faucets))
-
- // Fetch the accessor for the relevant signer
- backend := nodes[index%len(nodes)].backend
+ backend := nodes[index%len(nodes)]
// Create a self transaction and inject into the pool
tx, err := types.SignTx(types.NewTransaction(nonces[index], crypto.PubkeyToAddress(faucets[index].PublicKey), new(big.Int), 21000, big.NewInt(100000000000), nil), types.HomesteadSigner{}, faucets[index])
diff --git a/miner/stress_ethash.go b/miner/stress_ethash.go
index b6e3899a2335..1f4492a05d9f 100644
--- a/miner/stress_ethash.go
+++ b/miner/stress_ethash.go
@@ -62,10 +62,7 @@ func main() {
genesis := makeGenesis(faucets)
var (
- nodes []struct {
- node *node.Node
- backend *eth.Ethereum
- }
+ nodes []*eth.Ethereum
enodes []*enode.Node
)
for i := 0; i < 4; i++ {
@@ -83,14 +80,8 @@ func main() {
for _, n := range enodes {
stack.Server().AddPeer(n)
}
- // Start tracking the node and it's enode
- nodes = append(nodes, struct {
- node *node.Node
- backend *eth.Ethereum
- }{
- stack,
- ethBackend,
- })
+ // Start tracking the node and its enode
+ nodes = append(nodes, ethBackend)
enodes = append(enodes, stack.Server().Self())
// Inject the signer key and start sealing with it
@@ -99,11 +90,11 @@ func main() {
panic(err)
}
}
- // Iterate over all the nodes and start signing with them
- time.Sleep(3 * time.Second)
+ // Iterate over all the nodes and start mining
+ time.Sleep(3 * time.Second)
for _, node := range nodes {
- if err := node.backend.StartMining(1); err != nil {
+ if err := node.StartMining(1); err != nil {
panic(err)
}
}
@@ -112,9 +103,10 @@ func main() {
// Start injecting transactions from the faucets like crazy
nonces := make([]uint64, len(faucets))
for {
+ // Pick a random mining node
index := rand.Intn(len(faucets))
- // Fetch the accessor for the relevant signer
- backend := nodes[index%len(nodes)].backend
+ backend := nodes[index%len(nodes)]
+
// Create a self transaction and inject into the pool
tx, err := types.SignTx(types.NewTransaction(nonces[index], crypto.PubkeyToAddress(faucets[index].PublicKey), new(big.Int), 21000, big.NewInt(100000000000+rand.Int63n(65536)), nil), types.HomesteadSigner{}, faucets[index])
if err != nil {
From c70d5e64303dcf960037b2f5701ce1f2d9c56c6f Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Wed, 22 Jul 2020 23:46:39 +0200
Subject: [PATCH 135/160] miner: simplify test scripts even more
---
miner/stress_clique.go | 13 ++++---------
miner/stress_ethash.go | 11 +++--------
2 files changed, 7 insertions(+), 17 deletions(-)
diff --git a/miner/stress_clique.go b/miner/stress_clique.go
index a4bbb9d22112..21538aaaed71 100644
--- a/miner/stress_clique.go
+++ b/miner/stress_clique.go
@@ -22,7 +22,6 @@ package main
import (
"bytes"
"crypto/ecdsa"
- "fmt"
"io/ioutil"
"math/big"
"math/rand"
@@ -77,11 +76,11 @@ func main() {
for stack.Server().NodeInfo().Ports.Listener == 0 {
time.Sleep(250 * time.Millisecond)
}
- // Connect the node to al the previous ones
+ // Connect the node to all the previous ones
for _, n := range enodes {
stack.Server().AddPeer(n)
}
- // Start tracking the node and it's enode
+ // Start tracking the node and its enode
nodes = append(nodes, ethBackend)
enodes = append(enodes, stack.Server().Self())
@@ -117,17 +116,13 @@ func main() {
if err != nil {
panic(err)
}
- txpool := backend.TxPool()
- if txpool == nil {
- panic(fmt.Errorf("Ethereum service not running"))
- }
- if err := txpool.AddLocal(tx); err != nil {
+ if err := backend.TxPool().AddLocal(tx); err != nil {
panic(err)
}
nonces[index]++
// Wait if we're too saturated
- if pend, _ := txpool.Stats(); pend > 2048 {
+ if pend, _ := backend.TxPool().Stats(); pend > 2048 {
time.Sleep(100 * time.Millisecond)
}
}
diff --git a/miner/stress_ethash.go b/miner/stress_ethash.go
index 1f4492a05d9f..5a7e7685a62b 100644
--- a/miner/stress_ethash.go
+++ b/miner/stress_ethash.go
@@ -21,7 +21,6 @@ package main
import (
"crypto/ecdsa"
- "fmt"
"io/ioutil"
"math/big"
"math/rand"
@@ -76,7 +75,7 @@ func main() {
for stack.Server().NodeInfo().Ports.Listener == 0 {
time.Sleep(250 * time.Millisecond)
}
- // Connect the node to al the previous ones
+ // Connect the node to all the previous ones
for _, n := range enodes {
stack.Server().AddPeer(n)
}
@@ -112,17 +111,13 @@ func main() {
if err != nil {
panic(err)
}
- txpool := backend.TxPool()
- if txpool == nil {
- panic(fmt.Errorf("Ethereum service not running"))
- }
- if err := txpool.AddLocal(tx); err != nil {
+ if err := backend.TxPool().AddLocal(tx); err != nil {
panic(err)
}
nonces[index]++
// Wait if we're too saturated
- if pend, _ := txpool.Stats(); pend > 2048 {
+ if pend, _ := backend.TxPool().Stats(); pend > 2048 {
time.Sleep(100 * time.Millisecond)
}
}
From 45f162cf5e1c2c0f6e525da9b19ecf5cbd605608 Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Thu, 23 Jul 2020 10:52:54 +0200
Subject: [PATCH 136/160] node: remove atomic operations on n.state
---
node/node.go | 53 +++++++++++++++++++++++-----------------------------
1 file changed, 23 insertions(+), 30 deletions(-)
diff --git a/node/node.go b/node/node.go
index ad5927a0ee63..e9758338f7eb 100644
--- a/node/node.go
+++ b/node/node.go
@@ -50,7 +50,7 @@ type Node struct {
stop chan struct{} // Channel to wait for termination notifications
server *p2p.Server // Currently running P2P networking layer
startStopLock sync.Mutex // Start/Stop are protected by an additional lock
- stateFlag int32 // Tracks state of node lifecycle
+ state int // Tracks state of node lifecycle
lock sync.Mutex
lifecycles []Lifecycle // All registered backends, services, and auxiliary services that have a lifecycle
@@ -68,14 +68,6 @@ const (
closedState
)
-func (n *Node) state() int32 {
- return atomic.LoadInt32(&n.stateFlag)
-}
-
-func (n *Node) setState(state int32) {
- atomic.StoreInt32(&n.stateFlag, state)
-}
-
// New creates a new P2P node, ready for protocol registration.
func New(conf *Config) (*Node, error) {
// Copy config and resolve the datadir so future changes to the current
@@ -192,15 +184,16 @@ func (n *Node) Start() error {
n.startStopLock.Lock()
defer n.startStopLock.Unlock()
- switch n.state() {
+ n.lock.Lock()
+ switch n.state {
case runningState:
+ n.lock.Unlock()
return ErrNodeRunning
case closedState:
+ n.lock.Unlock()
return ErrNodeStopped
}
- n.setState(runningState)
-
- n.lock.Lock()
+ n.state = runningState
err := n.startNetworking()
lifecycles := make([]Lifecycle, len(n.lifecycles))
copy(lifecycles, n.lifecycles)
@@ -233,7 +226,10 @@ func (n *Node) Close() error {
n.startStopLock.Lock()
defer n.startStopLock.Unlock()
- switch state := n.state(); state {
+ n.lock.Lock()
+ state := n.state
+ n.lock.Unlock()
+ switch state {
case initializingState:
// The node was never started.
return n.doClose(nil)
@@ -253,7 +249,12 @@ func (n *Node) Close() error {
// doClose releases resources acquired by New(), collecting errors.
func (n *Node) doClose(errs []error) error {
- n.setState(closedState)
+ // Close databases. This needs the lock because it needs to
+ // synchronize with OpenDatabase*.
+ n.lock.Lock()
+ n.state = closedState
+ errs = append(errs, n.closeDatabases()...)
+ n.lock.Unlock()
if err := n.accman.Close(); err != nil {
errs = append(errs, err)
@@ -264,12 +265,6 @@ func (n *Node) doClose(errs []error) error {
}
}
- // Close databases. This needs the lock because it needs to
- // synchronize with OpenDatabase*.
- n.lock.Lock()
- errs = append(errs, n.closeDatabases()...)
- n.lock.Unlock()
-
// Release instance directory lock.
n.closeDataDir()
@@ -527,7 +522,7 @@ func (n *Node) RegisterLifecycle(lifecycle Lifecycle) {
n.lock.Lock()
defer n.lock.Unlock()
- if n.state() != initializingState {
+ if n.state != initializingState {
panic("can't register lifecycle on running/stopped node")
}
if containsLifecycle(n.lifecycles, lifecycle) {
@@ -541,7 +536,7 @@ func (n *Node) RegisterProtocols(protocols []p2p.Protocol) {
n.lock.Lock()
defer n.lock.Unlock()
- if n.state() != initializingState {
+ if n.state != initializingState {
panic("can't register protocols on running/stopped node")
}
n.server.Protocols = append(n.server.Protocols, protocols...)
@@ -552,7 +547,7 @@ func (n *Node) RegisterAPIs(apis []rpc.API) {
n.lock.Lock()
defer n.lock.Unlock()
- if n.state() != initializingState {
+ if n.state != initializingState {
panic("can't register APIs on running/stopped node")
}
n.rpcAPIs = append(n.rpcAPIs, apis...)
@@ -563,7 +558,7 @@ func (n *Node) RegisterPath(path string, handler http.Handler) string {
n.lock.Lock()
defer n.lock.Unlock()
- if n.state() != initializingState {
+ if n.state != initializingState {
panic("can't register HTTP handler on running/stopped node")
}
for _, server := range n.httpServers {
@@ -586,7 +581,7 @@ func (n *Node) RPCHandler() (*rpc.Server, error) {
n.lock.Lock()
defer n.lock.Unlock()
- if n.state() == closedState {
+ if n.state == closedState {
return nil, ErrNodeStopped
}
return n.inprocHandler, nil
@@ -654,8 +649,7 @@ func (n *Node) EventMux() *event.TypeMux {
func (n *Node) OpenDatabase(name string, cache, handles int, namespace string) (ethdb.Database, error) {
n.lock.Lock()
defer n.lock.Unlock()
-
- if n.state() == closedState {
+ if n.state == closedState {
return nil, ErrNodeStopped
}
@@ -681,8 +675,7 @@ func (n *Node) OpenDatabase(name string, cache, handles int, namespace string) (
func (n *Node) OpenDatabaseWithFreezer(name string, cache, handles int, freezer, namespace string) (ethdb.Database, error) {
n.lock.Lock()
defer n.lock.Unlock()
-
- if n.state() == closedState {
+ if n.state == closedState {
return nil, ErrNodeStopped
}
From 4a6faffd35655f0d1c668473a8462b37a0c5792f Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Fri, 24 Jul 2020 15:00:40 +0200
Subject: [PATCH 137/160] node: WIP rewrite HTTP server setup
The HTTP server code was very subtle and I couldn't really figure out if
it's correct or not. This change rewrites it with the intention of
simplifying the logic in node.go and reducing duplication in api.go.
---
node/api.go | 161 ++++++++----------------
node/node.go | 255 +++++++++++---------------------------
node/node_test.go | 168 +++++++++++++------------
node/rpcstack.go | 279 ++++++++++++++++++++++++++++++++++--------
node/rpcstack_test.go | 109 ++++++++++-------
5 files changed, 493 insertions(+), 479 deletions(-)
diff --git a/node/api.go b/node/api.go
index 39ba48b2a1ee..a8b700df481a 100644
--- a/node/api.go
+++ b/node/api.go
@@ -20,7 +20,6 @@ import (
"context"
"fmt"
"strings"
- "sync/atomic"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
@@ -168,7 +167,7 @@ func (api *privateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
api.node.lock.Lock()
defer api.node.lock.Unlock()
- // set host, port, and endpoint
+ // Determine host and port.
if host == nil {
h := DefaultHTTPHost
if api.node.config.HTTPHost != "" {
@@ -179,76 +178,48 @@ func (api *privateAdminAPI) StartRPC(host *string, port *int, cors *string, apis
if port == nil {
port = &api.node.config.HTTPPort
}
- endpoint := fmt.Sprintf("%s:%d", *host, *port)
- // check if HTTP server already exists
- if server, exists := api.node.httpServers[endpoint]; exists {
- if atomic.LoadInt32(&server.RPCAllowed) == 1 {
- return false, fmt.Errorf("HTTP RPC already running on %v", server.Listener.Addr())
- }
- }
- allowedOrigins := api.node.config.HTTPCors
+ // Determine config.
+ config := httpConfig{
+ CorsAllowedOrigins: api.node.config.HTTPCors,
+ Vhosts: api.node.config.HTTPVirtualHosts,
+ Modules: api.node.config.HTTPModules,
+ }
if cors != nil {
- allowedOrigins = nil
+ config.CorsAllowedOrigins = nil
for _, origin := range strings.Split(*cors, ",") {
- allowedOrigins = append(allowedOrigins, strings.TrimSpace(origin))
+ config.CorsAllowedOrigins = append(config.CorsAllowedOrigins, strings.TrimSpace(origin))
}
}
-
- allowedVHosts := api.node.config.HTTPVirtualHosts
if vhosts != nil {
- allowedVHosts = nil
+ config.Vhosts = nil
for _, vhost := range strings.Split(*host, ",") {
- allowedVHosts = append(allowedVHosts, strings.TrimSpace(vhost))
+ config.Vhosts = append(config.Vhosts, strings.TrimSpace(vhost))
}
}
-
- modules := api.node.config.HTTPModules
if apis != nil {
- modules = nil
+ config.Modules = nil
for _, m := range strings.Split(*apis, ",") {
- modules = append(modules, strings.TrimSpace(m))
+ config.Modules = append(config.Modules, strings.TrimSpace(m))
}
}
- // configure http server
- httpServer := &httpServer{
- host: *host,
- port: *port,
- endpoint: endpoint,
- Srv: rpc.NewServer(),
- CorsAllowedOrigins: allowedOrigins,
- Vhosts: allowedVHosts,
- Whitelist: modules,
+
+ if err := api.node.http.setListenAddr(*host, *port); err != nil {
+ return false, err
+ }
+ if err := api.node.http.enableRPC(api.node.rpcAPIs, config); err != nil {
+ return false, err
}
- // create handler
- handler := NewHTTPHandlerStack(httpServer.Srv, httpServer.CorsAllowedOrigins, httpServer.Vhosts)
- httpServer.srvMux.Handle("/", handler)
- // create HTTP server
- if err := api.node.createHTTPServer(httpServer, false); err != nil {
+ if err := api.node.http.start(); err != nil {
return false, err
}
- // register the HTTP server
- api.node.registerHTTPServer(endpoint, httpServer)
- // start the HTTP server
- httpServer.Start()
- api.node.log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%v/", httpServer.Listener.Addr()),
- "cors", strings.Join(httpServer.CorsAllowedOrigins, ","),
- "vhosts", strings.Join(httpServer.Vhosts, ","))
return true, nil
}
-// StopRPC terminates an already running HTTP RPC API endpoint.
+// StopRPC shuts down the HTTP server.
func (api *privateAdminAPI) StopRPC() (bool, error) {
- api.node.lock.Lock()
- defer api.node.lock.Unlock()
-
- for _, httpServer := range api.node.httpServers {
- if atomic.LoadInt32(&httpServer.RPCAllowed) == 1 {
- api.node.stopServer(httpServer)
- return true, nil
- }
- }
- return false, fmt.Errorf("HTTP RPC not running")
+ api.node.http.stop()
+ return true, nil
}
// StartWS starts the websocket RPC API server.
@@ -256,13 +227,7 @@ func (api *privateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
api.node.lock.Lock()
defer api.node.lock.Unlock()
- // check if an existing WS server already exists
- for _, server := range api.node.httpServers {
- if atomic.LoadInt32(&server.WSAllowed) == 1 {
- return false, fmt.Errorf("WebSocket RPC already running on %v", server.Listener.Addr())
- }
- }
- // set host, port and endpoint
+ // Determine host and port.
if host == nil {
h := DefaultWSHost
if api.node.config.WSHost != "" {
@@ -273,74 +238,48 @@ func (api *privateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
if port == nil {
port = &api.node.config.WSPort
}
- endpoint := fmt.Sprintf("%s:%d", *host, *port)
- origins := api.node.config.WSOrigins
- if allowedOrigins != nil {
- origins = nil
- for _, origin := range strings.Split(*allowedOrigins, ",") {
- origins = append(origins, strings.TrimSpace(origin))
- }
+ // Determine config.
+ config := wsConfig{
+ Modules: api.node.config.WSModules,
+ Origins: api.node.config.WSOrigins,
+ // ExposeAll: api.node.config.WSExposeAll,
}
- // check if an HTTP server exists on the given endpoint, and if so, enable websocket on that HTTP server
- existingServer := api.node.existingHTTPServer(endpoint)
- if existingServer != nil {
- atomic.StoreInt32(&existingServer.WSAllowed, 1)
- existingServer.WsOrigins = origins
-
- api.node.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", existingServer.Listener.Addr()))
- return true, nil
- }
-
- modules := api.node.config.WSModules
if apis != nil {
- modules = nil
+ config.Modules = nil
for _, m := range strings.Split(*apis, ",") {
- modules = append(modules, strings.TrimSpace(m))
+ config.Modules = append(config.Modules, strings.TrimSpace(m))
}
}
- // configure http server
- wsServer := &httpServer{
- Srv: rpc.NewServer(),
- endpoint: endpoint,
- host: *host,
- port: *port,
- Whitelist: modules,
- WsOrigins: origins,
- WSAllowed: 1,
+ if allowedOrigins != nil {
+ config.Origins = nil
+ for _, origin := range strings.Split(*allowedOrigins, ",") {
+ config.Origins = append(config.Origins, strings.TrimSpace(origin))
+ }
}
- // create handler
- handler := wsServer.Srv.WebsocketHandler(wsServer.WsOrigins)
- wsServer.srvMux.Handle("/", handler)
- // create the HTTP server
- if err := api.node.createHTTPServer(wsServer, api.node.config.WSExposeAll); err != nil {
+
+ // Enable WebSocket on the server.
+ server := api.node.wsServerForPort(*port)
+ if err := server.setListenAddr(*host, *port); err != nil {
return false, err
}
- // register the HTTP server
- api.node.registerHTTPServer(endpoint, wsServer)
- // start the HTTP server
- if err := wsServer.Start(); err != nil {
+ if err := server.enableWS(api.node.rpcAPIs, config); err != nil {
return false, err
}
- api.node.log.Info("WebSocket endpoint opened", "url", fmt.Sprintf("ws://%v", wsServer.Listener.Addr()))
+ if err := server.start(); err != nil {
+ return false, err
+ }
+ api.node.log.Info("WebSocket endpoint opened", "url", api.node.WSEndpoint())
return true, nil
}
-// StopWS terminates an already running websocket RPC API endpoint.
+// StopWS terminates all WebSocket servers.
func (api *privateAdminAPI) StopWS() (bool, error) {
- api.node.lock.Lock()
- defer api.node.lock.Unlock()
-
- for _, httpServer := range api.node.httpServers {
- if atomic.SwapInt32(&httpServer.WSAllowed, 0) == 1 {
- // if RPC is not enabled on the WS http server, shut it down
- if atomic.LoadInt32(&httpServer.RPCAllowed) == 0 {
- api.node.stopServer(httpServer)
- }
- return true, nil
- }
+ if api.node.http.wsAllowed() {
+ api.node.http.disableWS()
}
- return false, fmt.Errorf("WebSocket RPC not running")
+ api.node.ws.stop()
+ return true, nil
}
// publicAdminAPI is the collection of administrative API methods exposed over
diff --git a/node/node.go b/node/node.go
index e9758338f7eb..d907d77d9eee 100644
--- a/node/node.go
+++ b/node/node.go
@@ -17,17 +17,14 @@
package node
import (
- "context"
"errors"
"fmt"
- "net"
"net/http"
"os"
"path/filepath"
"reflect"
"strings"
"sync"
- "sync/atomic"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/core/rawdb"
@@ -54,10 +51,11 @@ type Node struct {
lock sync.Mutex
lifecycles []Lifecycle // All registered backends, services, and auxiliary services that have a lifecycle
- httpServers serverMap // serverMap stores information about the node's rpc, ws, and graphQL http servers.
- inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
rpcAPIs []rpc.API // List of APIs currently provided by the node
- ipc *httpServer // Stores information about the ipc http server
+ http *httpServer //
+ ws *httpServer //
+ ipc *ipcServer // Stores information about the ipc http server
+ inprocHandler *rpc.Server // In-process RPC request handler to process the API requests
databases map[*closeTrackingDB]struct{} // All open databases
}
@@ -99,8 +97,6 @@ func New(conf *Config) (*Node, error) {
node := &Node{
config: conf,
- httpServers: make(serverMap),
- ipc: &httpServer{endpoint: conf.IPCEndpoint()},
inprocHandler: rpc.NewServer(),
eventmux: new(event.TypeMux),
log: conf.Logger,
@@ -139,41 +135,10 @@ func New(conf *Config) (*Node, error) {
node.server.Config.NodeDatabase = node.config.NodeDB()
}
- // Configure HTTP servers.
- if conf.HTTPHost != "" {
- httpServ := &httpServer{
- CorsAllowedOrigins: conf.HTTPCors,
- Vhosts: conf.HTTPVirtualHosts,
- Whitelist: conf.HTTPModules,
- Timeouts: conf.HTTPTimeouts,
- Srv: rpc.NewServer(),
- endpoint: conf.HTTPEndpoint(),
- host: conf.HTTPHost,
- port: conf.HTTPPort,
- RPCAllowed: 1,
- }
- // Enable WebSocket on HTTP port if enabled.
- if conf.WSHost != "" && conf.WSPort == conf.HTTPPort {
- httpServ.WSAllowed = 1
- httpServ.WsOrigins = conf.WSOrigins
- httpServ.Whitelist = append(httpServ.Whitelist, conf.WSModules...)
-
- node.httpServers[conf.HTTPEndpoint()] = httpServ
- return node, nil
- }
- node.httpServers[conf.HTTPEndpoint()] = httpServ
- }
- if conf.WSHost != "" {
- node.httpServers[conf.WSEndpoint()] = &httpServer{
- WsOrigins: conf.WSOrigins,
- Whitelist: conf.WSModules,
- Srv: rpc.NewServer(),
- endpoint: conf.WSEndpoint(),
- host: conf.WSHost,
- port: conf.WSPort,
- WSAllowed: 1,
- }
- }
+ // Configure RPC servers.
+ node.http = newHTTPServer(node.log, conf.HTTPTimeouts)
+ node.ws = newHTTPServer(node.log, rpc.DefaultHTTPTimeouts)
+ node.ipc = newIPCServer(node.log, conf.IPCEndpoint())
return node, nil
}
@@ -282,57 +247,15 @@ func (n *Node) doClose(errs []error) error {
}
}
-// registerHTTPServer registers the given HTTP server on the node.
-func (n *Node) registerHTTPServer(endpoint string, server *httpServer) {
- n.httpServers[endpoint] = server
-}
-
-// existingHTTPServer checks if an HTTP server is already configured on the given endpoint.
-func (n *Node) existingHTTPServer(endpoint string) *httpServer {
- if server, exists := n.httpServers[endpoint]; exists {
- return server
- }
- return nil
-}
-
-// createHTTPServer creates an http.Server and adds it to the given httpServer.
-func (n *Node) createHTTPServer(h *httpServer, exposeAll bool) error {
- // register apis and create handler stack
- err := RegisterApisFromWhitelist(n.rpcAPIs, h.Whitelist, h.Srv, exposeAll)
- if err != nil {
- return err
- }
-
- // start the HTTP listener
- listener, err := net.Listen("tcp", h.endpoint)
- if err != nil {
- return err
- }
- // create the HTTP server
- httpSrv := &http.Server{Handler: &h.srvMux}
- // check timeouts if they exist
- if h.Timeouts != (rpc.HTTPTimeouts{}) {
- CheckTimeouts(&h.Timeouts)
- httpSrv.ReadTimeout = h.Timeouts.ReadTimeout
- httpSrv.WriteTimeout = h.Timeouts.WriteTimeout
- httpSrv.IdleTimeout = h.Timeouts.IdleTimeout
- }
- // add listener and http.Server to httpServer
- h.Listener = listener
- h.Server = httpSrv
-
- return nil
-}
-
// startNetworking starts all network endpoints.
func (n *Node) startNetworking() error {
n.log.Info("Starting peer-to-peer node", "instance", n.server.Name)
if err := n.server.Start(); err != nil {
return convertFileLockError(err)
}
- err := n.configureRPC()
+ err := n.startRPC()
if err != nil {
- n.httpServers.Stop()
+ n.stopRPC()
n.server.Stop()
}
return err
@@ -351,8 +274,7 @@ func containsLifecycle(lfs []Lifecycle, l Lifecycle) bool {
// stopServices terminates running services, RPC and p2p networking.
// It is the inverse of Start.
func (n *Node) stopServices(running []Lifecycle) error {
- n.stopIPC()
- n.rpcAPIs = nil
+ n.stopRPC()
// Stop running lifecycles in reverse order.
failure := &StopError{Services: make(map[reflect.Type]error)}
@@ -403,54 +325,66 @@ func (n *Node) closeDataDir() {
// configureRPC is a helper method to configure all the various RPC endpoints during node
// startup. It's not meant to be called at any time afterwards as it makes certain
// assumptions about the state of the node.
-func (n *Node) configureRPC() error {
- // Start the various API endpoints, terminating all in case of errors
+func (n *Node) startRPC() error {
if err := n.startInProc(); err != nil {
return err
}
- if err := n.startIPC(); err != nil {
- n.stopInProc()
- return err
+
+ // Configure IPC.
+ if n.ipc.endpoint != "" {
+ if err := n.ipc.start(); err != nil {
+ return err
+ }
+ }
+
+ // Configure HTTP.
+ if n.config.HTTPHost != "" {
+ config := httpConfig{
+ CorsAllowedOrigins: n.config.HTTPCors,
+ Vhosts: n.config.HTTPVirtualHosts,
+ Modules: n.config.HTTPModules,
+ }
+ if err := n.http.setListenAddr(n.config.HTTPHost, n.config.HTTPPort); err != nil {
+ return err
+ }
+ if err := n.http.enableRPC(n.rpcAPIs, config); err != nil {
+ return err
+ }
}
- // Configure HTTP servers.
- for _, server := range n.httpServers {
- handler := n.createHandler(server)
- if handler != nil {
- server.srvMux.Handle("/", handler)
+ // Configure WebSocket.
+ if n.config.WSHost != "" {
+ server := n.wsServerForPort(n.config.WSPort)
+ config := wsConfig{
+ Modules: n.config.WSModules,
+ Origins: n.config.WSOrigins,
}
- if err := n.createHTTPServer(server, false); err != nil {
+ if err := server.setListenAddr(n.config.WSHost, n.config.WSPort); err != nil {
+ return err
+ }
+ if err := server.enableWS(n.rpcAPIs, config); err != nil {
return err
}
}
- // Register HTTP server as a lifecycle if it has not already been registered.
- if !containsLifecycle(n.lifecycles, &n.httpServers) {
- n.lifecycles = append(n.lifecycles, &n.httpServers)
+ if err := n.http.start(); err != nil {
+ return err
}
- return nil
+ return n.ws.start()
}
-// createHandler creates the http.Handler for the given httpServer.
-func (n *Node) createHandler(server *httpServer) http.Handler {
- var handler http.Handler
- if atomic.LoadInt32(&server.RPCAllowed) == 1 {
- handler = NewHTTPHandlerStack(server.Srv, server.CorsAllowedOrigins, server.Vhosts)
- // wrap ws handler just in case ws is enabled through the console after start-up
- wsHandler := server.Srv.WebsocketHandler(server.WsOrigins)
- handler = server.NewWebsocketUpgradeHandler(handler, wsHandler)
-
- n.log.Info("HTTP configured on endpoint ", "endpoint", fmt.Sprintf("http://%s/", server.endpoint))
- if atomic.LoadInt32(&server.WSAllowed) == 1 {
- n.log.Info("Websocket configured on endpoint ", "endpoint", fmt.Sprintf("ws://%s/", server.endpoint))
- }
- }
- if (atomic.LoadInt32(&server.WSAllowed) == 1) && handler == nil {
- handler = server.Srv.WebsocketHandler(server.WsOrigins)
- n.log.Info("Websocket configured on endpoint ", "endpoint", fmt.Sprintf("ws://%s/", server.endpoint))
+func (n *Node) wsServerForPort(port int) *httpServer {
+ if n.config.HTTPHost == "" || n.http.port == port {
+ return n.http
}
+ return n.ws
+}
- return handler
+func (n *Node) stopRPC() {
+ n.http.stop()
+ n.ws.stop()
+ n.ipc.stop()
+ n.stopInProc()
}
// startInProc registers all RPC APIs on the inproc server.
@@ -468,50 +402,6 @@ func (n *Node) stopInProc() {
n.inprocHandler.Stop()
}
-// startIPC initializes and starts the IPC RPC endpoint.
-func (n *Node) startIPC() error {
- if n.ipc.endpoint == "" {
- return nil // IPC disabled.
- }
- listener, handler, err := rpc.StartIPCEndpoint(n.ipc.endpoint, n.rpcAPIs)
- if err != nil {
- return err
- }
- n.ipc.Listener = listener
- n.ipc.handler = handler
- n.log.Info("IPC endpoint opened", "url", n.ipc.endpoint)
- return nil
-}
-
-// stopIPC terminates the IPC RPC endpoint.
-func (n *Node) stopIPC() {
- if n.ipc.Listener != nil {
- n.ipc.Listener.Close()
- n.ipc.Listener = nil
- n.log.Info("IPC endpoint closed", "url", n.ipc.endpoint)
- }
- if n.ipc.Srv != nil {
- n.ipc.Srv.Stop()
- n.ipc.Srv = nil
- }
-}
-
-// stopServers terminates the given HTTP servers' endpoints
-func (n *Node) stopServer(server *httpServer) {
- if server.Server != nil {
- url := fmt.Sprintf("http://%v/", server.Listener.Addr())
- // Don't bother imposing a timeout here.
- server.Server.Shutdown(context.Background())
- n.log.Info("HTTP Endpoint closed", "url", url)
- }
- if server.Srv != nil {
- server.Srv.Stop()
- server.Srv = nil
- }
- // remove stopped http server from node's http servers
- delete(n.httpServers, server.endpoint)
-}
-
// Wait blocks until the node is closed.
func (n *Node) Wait() {
<-n.stop
@@ -561,14 +451,8 @@ func (n *Node) RegisterPath(path string, handler http.Handler) string {
if n.state != initializingState {
panic("can't register HTTP handler on running/stopped node")
}
- for _, server := range n.httpServers {
- if atomic.LoadInt32(&server.RPCAllowed) == 1 {
- server.srvMux.Handle(path, handler)
- return server.endpoint
- }
- }
- n.log.Warn(fmt.Sprintf("HTTP server not configured on node, path %s cannot be enabled", path))
- return ""
+ n.http.mux.Handle(path, handler)
+ return n.http.endpoint
}
// Attach creates an RPC client attached to an in-process API handler.
@@ -596,6 +480,9 @@ func (n *Node) Config() *Config {
// only to inspect fields of the currently running server. Callers should not
// start or stop the returned server.
func (n *Node) Server() *p2p.Server {
+ n.lock.Lock()
+ defer n.lock.Unlock()
+
return n.server
}
@@ -620,21 +507,17 @@ func (n *Node) IPCEndpoint() string {
return n.ipc.endpoint
}
+// HTTPEndpoint returns the URL of the HTTP server.
+func (n *Node) HTTPEndpoint() string {
+ return "http://" + n.http.listenAddr()
+}
+
// WSEndpoint retrieves the current WS endpoint used by the protocol stack.
func (n *Node) WSEndpoint() string {
- n.lock.Lock()
- defer n.lock.Unlock()
-
- for _, httpServer := range n.httpServers {
- if atomic.LoadInt32(&httpServer.WSAllowed) == 1 {
- if httpServer.Listener != nil {
- return httpServer.Listener.Addr().String()
- }
- return httpServer.endpoint
- }
+ if n.http.wsAllowed() {
+ return "ws://" + n.http.listenAddr()
}
-
- return n.config.WSEndpoint()
+ return "ws://" + n.ws.listenAddr()
}
// EventMux retrieves the event multiplexer used by all the network services in
diff --git a/node/node_test.go b/node/node_test.go
index f8df4b518b57..f5d25360c23e 100644
--- a/node/node_test.go
+++ b/node/node_test.go
@@ -18,13 +18,11 @@ package node
import (
"errors"
- "fmt"
"io"
"io/ioutil"
"net/http"
"os"
"reflect"
- "sync/atomic"
"testing"
"github.com/ethereum/go-ethereum/crypto"
@@ -388,44 +386,44 @@ func TestLifecycleTerminationGuarantee(t *testing.T) {
stack.server.PrivateKey = testNodeKey
}
-// Tests whether a given httpServer can be registered on the node
-func TestRegisterHTTPServer(t *testing.T) {
- stack, err := New(testNodeConfig())
- if err != nil {
- t.Fatalf("failed to create protocol stack: %v", err)
- }
- defer stack.Close()
-
- srv1 := &httpServer{
- host: "test1",
- port: 0001,
- }
- endpoint1 := fmt.Sprintf("%s:%d", srv1.host, srv1.port)
- stack.registerHTTPServer(endpoint1, srv1)
-
- srv2 := &httpServer{
- host: "test2",
- port: 0002,
- }
- endpoint2 := fmt.Sprintf("%s:%d", srv2.host, srv2.port)
- stack.registerHTTPServer(endpoint2, srv2)
-
- noop := &httpServer{
- host: "test",
- port: 0000,
- }
- endpointNoop := fmt.Sprintf("%s:%d", noop.host, noop.port)
-
- if srv1 != stack.existingHTTPServer(endpoint1) {
- t.Fatalf("server %v was not properly registered on the given endpoint %s", srv1, endpoint1)
- }
- if srv2 != stack.existingHTTPServer(endpoint2) {
- t.Fatalf("server %v was not properly registered on the given endpoint %s", srv2, endpoint2)
- }
- if noop == stack.existingHTTPServer(endpointNoop) {
- t.Fatalf("server %v was incorrectly registered on the given endpoint %s", noop, endpointNoop)
- }
-}
+// // Tests whether a given httpServer can be registered on the node
+// func TestRegisterHTTPServer(t *testing.T) {
+// stack, err := New(testNodeConfig())
+// if err != nil {
+// t.Fatalf("failed to create protocol stack: %v", err)
+// }
+// defer stack.Close()
+//
+// srv1 := &httpServer{
+// host: "test1",
+// port: 0001,
+// }
+// endpoint1 := fmt.Sprintf("%s:%d", srv1.host, srv1.port)
+// stack.registerHTTPServer(endpoint1, srv1)
+//
+// srv2 := &httpServer{
+// host: "test2",
+// port: 0002,
+// }
+// endpoint2 := fmt.Sprintf("%s:%d", srv2.host, srv2.port)
+// stack.registerHTTPServer(endpoint2, srv2)
+//
+// noop := &httpServer{
+// host: "test",
+// port: 0000,
+// }
+// endpointNoop := fmt.Sprintf("%s:%d", noop.host, noop.port)
+//
+// if srv1 != stack.existingHTTPServer(endpoint1) {
+// t.Fatalf("server %v was not properly registered on the given endpoint %s", srv1, endpoint1)
+// }
+// if srv2 != stack.existingHTTPServer(endpoint2) {
+// t.Fatalf("server %v was not properly registered on the given endpoint %s", srv2, endpoint2)
+// }
+// if noop == stack.existingHTTPServer(endpointNoop) {
+// t.Fatalf("server %v was incorrectly registered on the given endpoint %s", noop, endpointNoop)
+// }
+// }
// Tests whether a handler can be successfully mounted on the canonical HTTP server
// on the given path
@@ -476,51 +474,51 @@ func TestRegisterPath_Unsuccessful(t *testing.T) {
assert.Equal(t, "", endpoint)
}
-// Tests whether a node can successfully create and register HTTP server
-// lifecycles on the node.
-func TestHTTPServerCreateAndStop(t *testing.T) {
- // test on same ports
- node1 := startHTTP(t, 7453, 7453)
- if len(node1.httpServers) != 1 {
- t.Fatalf("node has more than 1 http server")
- }
- // check to make sure http servers are registered
- if !containsLifecycle(node1.lifecycles, &node1.httpServers) {
- t.Fatal("HTTP servers not registered as lifecycles on the node")
- }
- // check to make sure http servers are configured properly
- for _, server := range node1.httpServers {
- if atomic.LoadInt32(&server.WSAllowed) == 0 && atomic.LoadInt32(&server.RPCAllowed) == 0 {
- t.Fatalf("node's http server is not configured to handle both rpc and ws")
- }
- node1.stopServer(server)
- if node1.existingHTTPServer(server.endpoint) != nil {
- t.Fatalf("failed to remove server %v from node after stopping it", server)
- }
- }
- node1.Close()
-
- // test on separate ports
- node2 := startHTTP(t, 7453, 9393)
- if len(node2.httpServers) != 2 {
- t.Fatalf("amount of http servers on the node is not equal to 2")
- }
- // check to make sure http servers are registered
- if !containsLifecycle(node2.lifecycles, &node2.httpServers) {
- t.Fatal("HTTP servers not registered as lifecycles on the node")
- }
- // check that neither http server has both ws and rpc enabled
- for _, server := range node2.httpServers {
- if atomic.LoadInt32(&server.WSAllowed) == 1 && atomic.LoadInt32(&server.RPCAllowed) == 1 {
- t.Fatalf("both rpc and ws allowed on a single http server")
- }
- node2.stopServer(server)
- if node2.existingHTTPServer(server.endpoint) != nil {
- t.Fatalf("failed to remove server %v from node after stopping it", server)
- }
- }
- node2.Close()
-}
+// // Tests whether a node can successfully create and register HTTP server
+// // lifecycles on the node.
+// func TestHTTPServerCreateAndStop(t *testing.T) {
+// // test on same ports
+// node1 := startHTTP(t, 7453, 7453)
+// if len(node1.httpServers) != 1 {
+// t.Fatalf("node has more than 1 http server")
+// }
+// // check to make sure http servers are registered
+// if !containsLifecycle(node1.lifecycles, &node1.httpServers) {
+// t.Fatal("HTTP servers not registered as lifecycles on the node")
+// }
+// // check to make sure http servers are configured properly
+// for _, server := range node1.httpServers {
+// if atomic.LoadInt32(&server.WSAllowed) == 0 && atomic.LoadInt32(&server.RPCAllowed) == 0 {
+// t.Fatalf("node's http server is not configured to handle both rpc and ws")
+// }
+// node1.stopServer(server)
+// if node1.existingHTTPServer(server.endpoint) != nil {
+// t.Fatalf("failed to remove server %v from node after stopping it", server)
+// }
+// }
+// node1.Close()
+//
+// // test on separate ports
+// node2 := startHTTP(t, 7453, 9393)
+// if len(node2.httpServers) != 2 {
+// t.Fatalf("amount of http servers on the node is not equal to 2")
+// }
+// // check to make sure http servers are registered
+// if !containsLifecycle(node2.lifecycles, &node2.httpServers) {
+// t.Fatal("HTTP servers not registered as lifecycles on the node")
+// }
+// // check that neither http server has both ws and rpc enabled
+// for _, server := range node2.httpServers {
+// if atomic.LoadInt32(&server.WSAllowed) == 1 && atomic.LoadInt32(&server.RPCAllowed) == 1 {
+// t.Fatalf("both rpc and ws allowed on a single http server")
+// }
+// node2.stopServer(server)
+// if node2.existingHTTPServer(server.endpoint) != nil {
+// t.Fatalf("failed to remove server %v from node after stopping it", server)
+// }
+// }
+// node2.Close()
+// }
// Tests whether websocket requests can be handled on the same port as a regular http server.
func TestWebsocketHTTPOnSamePort_WebsocketRequest(t *testing.T) {
diff --git a/node/rpcstack.go b/node/rpcstack.go
index aad54fa1945f..d1541cd98650 100644
--- a/node/rpcstack.go
+++ b/node/rpcstack.go
@@ -55,73 +55,221 @@ func RegisterApisFromWhitelist(apis []rpc.API, modules []string, srv *rpc.Server
return nil
}
-type serverMap map[string]*httpServer // Stores information about all http servers (if any) by their endpoint, including http, ws, and graphql
+// httpConfig is the JSON-RPC/HTTP configuration.
+type httpConfig struct {
+ Modules []string
+ CorsAllowedOrigins []string
+ Vhosts []string
+}
+
+// wsConfig is the JSON-RPC/Websocket configuration
+type wsConfig struct {
+ Origins []string
+ Modules []string
+}
type httpServer struct {
- srvMux http.ServeMux
+ log log.Logger
+ timeouts rpc.HTTPTimeouts
+ mux http.ServeMux // registered handlers go here
- handler http.Handler
- Srv *rpc.Server
- Server *http.Server
+ mu sync.Mutex
+ server *http.Server
+ listener net.Listener // non-nil when server is running
- Listener net.Listener
+ httpConfig httpConfig
+ httpRPC *rpc.Server
+ httpHandler http.Handler
+
+ wsConfig wsConfig
+ wsRPC *rpc.Server
+ wsHandler http.Handler
endpoint string
host string
port int
+ config httpConfig
- Whitelist []string
-
- CorsAllowedOrigins []string
- Vhosts []string
- WsOrigins []string
- Timeouts rpc.HTTPTimeouts
+ // atomic flags for the handler
+ rpcAllowedFlag int32
+ wsAllowedFlag int32
+}
- RPCAllowed int32
- WSAllowed int32
+func newHTTPServer(log log.Logger, timeouts rpc.HTTPTimeouts) *httpServer {
+ return &httpServer{log: log, timeouts: timeouts}
}
-func (sm serverMap) Start() error {
- for _, server := range sm {
- if err := server.Start(); err != nil {
- return sm.Stop()
- }
+// setListenAddr configures the listening address of the server.
+// The address can only be set while the server isn't running.
+func (h *httpServer) setListenAddr(host string, port int) error {
+ h.mu.Lock()
+ defer h.mu.Unlock()
+
+ if h.listener != nil && (host != h.host || port != h.port) {
+ return fmt.Errorf("HTTP server already running on %s", h.endpoint)
}
+
+ h.host, h.port = host, port
+ h.endpoint = fmt.Sprintf("%s:%d", host, port)
return nil
}
-func (sm serverMap) Stop() error {
- for _, server := range sm {
- if err := server.Stop(); err != nil {
- return err
- }
+// listenAddr returns the listening address of the server.
+func (h *httpServer) listenAddr() string {
+ h.mu.Lock()
+ defer h.mu.Unlock()
+
+ if h.listener != nil {
+ return h.listener.Addr().String()
}
+ return h.endpoint
+}
+
+// enableRPC turns on JSON-RPC over HTTP on the server.
+func (h *httpServer) enableRPC(apis []rpc.API, config httpConfig) error {
+ h.mu.Lock()
+ defer h.mu.Unlock()
+
+ if h.httpRPC != nil {
+ return fmt.Errorf("JSON-RPC over HTTP is already enabled")
+ }
+
+ // Create RPC server.
+ srv := rpc.NewServer()
+ if err := RegisterApisFromWhitelist(apis, h.httpConfig.Modules, srv, false); err != nil {
+ return err
+ }
+ // Create handler.
+ h.httpRPC = srv
+ h.httpHandler = NewHTTPHandlerStack(h.httpRPC, config.CorsAllowedOrigins, config.Vhosts)
+ atomic.StoreInt32(&h.rpcAllowedFlag, 1)
return nil
}
-// Start starts the httpServer's http.Server
-func (h *httpServer) Start() error {
- go h.Server.Serve(h.Listener)
- log.Info("HTTP endpoint successfully opened", "url", fmt.Sprintf("http://%v/", h.Listener.Addr()))
+// enableWS turns on JSON-RPC over WebSocket on the server.
+func (h *httpServer) enableWS(apis []rpc.API, config wsConfig) error {
+ h.mu.Lock()
+ defer h.mu.Unlock()
+
+ if h.wsRPC != nil {
+ return fmt.Errorf("JSON-RPC over WebSocket is already enabled")
+ }
+
+ // Create RPC server.
+ srv := rpc.NewServer()
+ if err := RegisterApisFromWhitelist(apis, h.wsConfig.Modules, srv, false); err != nil {
+ return err
+ }
+ // Create handler.
+ h.wsRPC = rpc.NewServer()
+ h.wsHandler = h.wsRPC.WebsocketHandler(config.Origins)
+ atomic.StoreInt32(&h.wsAllowedFlag, 1)
return nil
}
-// Stop shuts down the httpServer's http.Server
-func (h *httpServer) Stop() error {
- if h.Server != nil {
- url := fmt.Sprintf("http://%v/", h.Listener.Addr())
- // Don't bother imposing a timeout here.
- h.Server.Shutdown(context.Background())
- log.Info("HTTP Endpoint closed", "url", url)
+// disableWS disables JSON-RPC over WebSocket.
+func (h *httpServer) disableWS() {
+ h.mu.Lock()
+ defer h.mu.Unlock()
+
+ atomic.StoreInt32(&h.wsAllowedFlag, 0)
+ h.wsRPC.Stop()
+ h.wsRPC = nil
+}
+
+// start starts the HTTP server if it is enabled and not already running.
+func (h *httpServer) start() error {
+ h.mu.Lock()
+ defer h.mu.Unlock()
+
+ if h.endpoint == "" || h.listener != nil {
+ return nil // already running or not configured
}
- if h.Srv != nil {
- h.Srv.Stop()
- h.Srv = nil
+
+ // Initialize the server.
+ h.server = &http.Server{Handler: h}
+ if h.timeouts != (rpc.HTTPTimeouts{}) {
+ CheckTimeouts(&h.timeouts)
+ h.server.ReadTimeout = h.timeouts.ReadTimeout
+ h.server.WriteTimeout = h.timeouts.WriteTimeout
+ h.server.IdleTimeout = h.timeouts.IdleTimeout
}
+ // Start the server.
+ listener, err := net.Listen("tcp", h.endpoint)
+ if err != nil {
+ return err
+ }
+ h.listener = listener
+ go h.server.Serve(listener)
+ h.log.Info("HTTP endpoint opened",
+ "url", fmt.Sprintf("http://%v/", listener.Addr()),
+ "cors", strings.Join(h.config.CorsAllowedOrigins, ","),
+ "vhosts", strings.Join(h.config.Vhosts, ","),
+ )
return nil
}
+// stop shuts down the HTTP server.
+func (h *httpServer) stop() error {
+ h.mu.Lock()
+ defer h.mu.Unlock()
+ if h.listener == nil {
+ return nil // not running
+ }
+
+ // Shut down the server.
+ if h.httpRPC != nil {
+ h.httpRPC.Stop()
+ }
+ if h.wsRPC != nil {
+ h.wsRPC.Stop()
+ }
+ h.server.Shutdown(context.Background())
+ h.listener.Close()
+ h.log.Info("HTTP endpoint closed", "url", h.endpoint)
+
+ // Clear out everything to allow re-configuring it later.
+ h.host, h.port, h.endpoint = "", 0, ""
+ h.server, h.listener = nil, nil
+ h.httpRPC, h.httpHandler, h.wsRPC, h.wsHandler = nil, nil, nil, nil
+ atomic.StoreInt32(&h.rpcAllowedFlag, 0)
+ atomic.StoreInt32(&h.wsAllowedFlag, 0)
+ return nil
+}
+
+// rpcAllowed returns true when JSON-RPC over HTTP is enabled.
+func (h *httpServer) rpcAllowed() bool {
+ return atomic.LoadInt32(&h.rpcAllowedFlag) == 1
+}
+
+// wsAllowed returns true when JSON-RPC over WebSocket is enabled.
+func (h *httpServer) wsAllowed() bool {
+ return atomic.LoadInt32(&h.wsAllowedFlag) == 1
+}
+
+func (h *httpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ if h.wsAllowed() && isWebsocket(r) {
+ h.wsHandler.ServeHTTP(w, r)
+ return
+ }
+ if r.RequestURI == "/" {
+ if h.rpcAllowed() {
+ h.httpHandler.ServeHTTP(w, r)
+ } else {
+ w.WriteHeader(404)
+ }
+ } else {
+ h.mux.ServeHTTP(w, r)
+ }
+}
+
+// isWebsocket checks the header of an http request for a websocket upgrade request.
+func isWebsocket(r *http.Request) bool {
+ return strings.ToLower(r.Header.Get("Upgrade")) == "websocket" &&
+ strings.ToLower(r.Header.Get("Connection")) == "upgrade"
+}
+
// NewHTTPHandlerStack returns wrapped http-related handlers
func NewHTTPHandlerStack(srv http.Handler, cors []string, vhosts []string) http.Handler {
// Wrap the CORS-handler within a host-handler
@@ -231,22 +379,47 @@ func newGzipHandler(next http.Handler) http.Handler {
})
}
-// NewWebsocketUpgradeHandler returns a websocket handler that serves an incoming request only if it contains an upgrade
-// request to the websocket protocol. If not, serves the the request with the http handler.
-func (hs *httpServer) NewWebsocketUpgradeHandler(h http.Handler, ws http.Handler) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- if atomic.LoadInt32(&hs.WSAllowed) == 1 && isWebsocket(r) {
- ws.ServeHTTP(w, r)
- log.Debug("serving websocket request")
- return
- }
+type ipcServer struct {
+ log log.Logger
+ endpoint string
- h.ServeHTTP(w, r)
- })
+ mu sync.Mutex
+ listener net.Listener
+ srv *rpc.Server
+ apis []rpc.API
}
-// isWebsocket checks the header of an http request for a websocket upgrade request.
-func isWebsocket(r *http.Request) bool {
- return strings.ToLower(r.Header.Get("Upgrade")) == "websocket" &&
- strings.ToLower(r.Header.Get("Connection")) == "upgrade"
+func newIPCServer(log log.Logger, endpoint string) *ipcServer {
+ return &ipcServer{log: log, endpoint: endpoint}
+}
+
+// Start starts the httpServer's http.Server
+func (is *ipcServer) start() error {
+ is.mu.Lock()
+ defer is.mu.Unlock()
+
+ if is.listener != nil {
+ return nil // already running
+ }
+ listener, srv, err := rpc.StartIPCEndpoint(is.endpoint, is.apis)
+ if err != nil {
+ return err
+ }
+ is.log.Info("IPC endpoint opened", "url", is.endpoint)
+ is.listener, is.srv = listener, srv
+ return nil
+}
+
+func (is *ipcServer) stop() error {
+ is.mu.Lock()
+ defer is.mu.Unlock()
+
+ if is.listener == nil {
+ return nil // not running
+ }
+ err := is.listener.Close()
+ is.srv.Stop()
+ is.listener, is.srv = nil, nil
+ is.log.Info("IPC endpoint closed", "url", is.endpoint)
+ return err
}
diff --git a/node/rpcstack_test.go b/node/rpcstack_test.go
index c00c4d665896..cd2dbf63b5f9 100644
--- a/node/rpcstack_test.go
+++ b/node/rpcstack_test.go
@@ -2,68 +2,89 @@ package node
import (
"fmt"
- "net/http"
- "net/http/httptest"
- "sync/atomic"
+ "strings"
"testing"
+ "github.com/ethereum/go-ethereum/internal/testlog"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc"
- "github.com/stretchr/testify/assert"
)
-func TestNewWebsocketUpgradeHandler_websocket(t *testing.T) {
- h := &httpServer{
- Srv: rpc.NewServer(),
- WSAllowed: 1,
- }
- handler := h.NewWebsocketUpgradeHandler(nil, h.Srv.WebsocketHandler([]string{}))
- ts := httptest.NewServer(handler)
- defer ts.Close()
-
- responses := make(chan *http.Response)
- go func(responses chan *http.Response) {
- client := &http.Client{}
-
- req, _ := http.NewRequest(http.MethodGet, ts.URL, nil)
- req.Header.Set("Connection", "upgrade")
- req.Header.Set("Upgrade", "websocket")
- req.Header.Set("Sec-WebSocket-Version", "13")
- req.Header.Set("Sec-Websocket-Key", "SGVsbG8sIHdvcmxkIQ==")
-
- resp, err := client.Do(req)
- if err != nil {
- t.Fatalf("could not issue a GET request to the test http server %v", err)
- }
- responses <- resp
- }(responses)
-
- response := <-responses
- assert.Equal(t, "websocket", response.Header.Get("Upgrade"))
-}
+// func TestNewWebsocketUpgradeHandler_websocket(t *testing.T) {
+// h := &httpServer{
+// Srv: rpc.NewServer(),
+// WSAllowed: 1,
+// }
+// handler := h.NewWebsocketUpgradeHandler(nil, h.Srv.WebsocketHandler([]string{}))
+// ts := httptest.NewServer(handler)
+// defer ts.Close()
+//
+// responses := make(chan *http.Response)
+// go func(responses chan *http.Response) {
+// client := &http.Client{}
+//
+// req, _ := http.NewRequest(http.MethodGet, ts.URL, nil)
+// req.Header.Set("Connection", "upgrade")
+// req.Header.Set("Upgrade", "websocket")
+// req.Header.Set("Sec-WebSocket-Version", "13")
+// req.Header.Set("Sec-Websocket-Key", "SGVsbG8sIHdvcmxkIQ==")
+//
+// resp, err := client.Do(req)
+// if err != nil {
+// t.Fatalf("could not issue a GET request to the test http server %v", err)
+// }
+// responses <- resp
+// }(responses)
+//
+// response := <-responses
+// assert.Equal(t, "websocket", response.Header.Get("Upgrade"))
+// }
// Tests that a ws handler can be added to and enabled on an existing HTTPServer
func TestWSAllowed(t *testing.T) {
stack, err := New(&Config{
- HTTPHost: DefaultHTTPHost,
- HTTPPort: 9393,
- WSHost: DefaultHTTPHost,
- WSPort: 9393,
+ HTTPHost: "127.0.0.1",
+ HTTPPort: 0,
+ WSHost: "127.0.0.1",
+ WSPort: 0,
+ Logger: testlog.Logger(t, log.LvlDebug),
})
if err != nil {
t.Fatalf("could not create node: %v", err)
}
defer stack.Close()
+
// start node
err = stack.Start()
if err != nil {
t.Fatalf("could not start node: %v", err)
}
- // check that server was configured on the given endpoint
- server := stack.existingHTTPServer(fmt.Sprintf("%s:%d", DefaultHTTPHost, 9393))
- if server == nil {
- t.Fatalf("server was not started on the given endpoint: %v", err)
+
+ // check that HTTP works on the endpoint.
+ url := stack.HTTPEndpoint()
+ if err := checkModules(url, stack.Config().WSModules); err != nil {
+ t.Fatal(err)
+ }
+
+ // check that WS works on the same endpoint.
+ wsURL := strings.Replace(url, "http://", "ws://", 1)
+ if err := checkModules(wsURL, stack.Config().WSModules); err != nil {
+ t.Fatal(err)
+ }
+}
+
+func checkModules(url string, want []string) error {
+ c, err := rpc.Dial(url)
+ if err != nil {
+ return fmt.Errorf("can't create RPC client: %v", err)
}
- // assert that both RPC and WS are allowed on the HTTP Server
- assert.Equal(t, atomic.LoadInt32(&server.RPCAllowed), int32(1))
- assert.Equal(t, atomic.LoadInt32(&server.WSAllowed), int32(1))
+ defer c.Close()
+
+ _, err = c.SupportedModules()
+ if err != nil {
+ return fmt.Errorf("can't get modules: %v", err)
+ }
+
+ // TODO: check module list
+ return nil
}
From a1a44545810d9a46b3e7f968fc019f73e2c715b4 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Mon, 27 Jul 2020 15:36:10 +0200
Subject: [PATCH 138/160] descriptive logging
---
go.mod | 23 +++---
go.sum | 184 ++++++++++++++++++++++++++++++++++++++++++---
graphql/service.go | 13 +---
node/node.go | 5 +-
node/node_test.go | 6 +-
node/rpcstack.go | 29 ++++++-
6 files changed, 218 insertions(+), 42 deletions(-)
diff --git a/go.mod b/go.mod
index eaff1e2ac5e6..9d418a2d58f9 100644
--- a/go.mod
+++ b/go.mod
@@ -6,11 +6,11 @@ require (
github.com/Azure/azure-pipeline-go v0.2.2 // indirect
github.com/Azure/azure-storage-blob-go v0.7.0
github.com/Azure/go-autorest/autorest/adal v0.8.0 // indirect
- github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect
+ github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect
github.com/VictoriaMetrics/fastcache v1.5.7
- github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847
+ github.com/aristanetworks/goarista v0.0.0-20200609010056-95bcf8053598
github.com/aws/aws-sdk-go v1.25.48
- github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6
+ github.com/btcsuite/btcd v0.20.1-beta
github.com/cespare/cp v0.1.0
github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9
github.com/davecgh/go-spew v1.1.1
@@ -22,12 +22,11 @@ require (
github.com/fatih/color v1.3.0
github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff
- github.com/go-ole/go-ole v1.2.1 // indirect
+ github.com/go-ole/go-ole v1.2.4 // indirect
github.com/go-sourcemap/sourcemap v2.1.2+incompatible // indirect
github.com/go-stack/stack v1.8.0
github.com/golang/protobuf v1.3.3
github.com/golang/snappy v0.0.2-0.20190904063534-ff6b7dc882cf
- github.com/google/go-cmp v0.3.1 // indirect
github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989
github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277
github.com/hashicorp/golang-lru v0.5.4
@@ -35,10 +34,8 @@ require (
github.com/huin/goupnp v1.0.0
github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458
- github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21
+ github.com/julienschmidt/httprouter v1.2.0
github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356
- github.com/kr/pretty v0.1.0 // indirect
- github.com/kylelemons/godebug v1.1.0 // indirect
github.com/mattn/go-colorable v0.1.0
github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035
github.com/naoina/go-stringutil v0.1.0 // indirect
@@ -50,7 +47,7 @@ require (
github.com/rjeczalik/notify v0.9.1
github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00
github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521 // indirect
- github.com/shirou/gopsutil v2.20.5+incompatible
+ github.com/shirou/gopsutil v2.20.6+incompatible
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4
github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 // indirect
@@ -58,12 +55,12 @@ require (
github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d
github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef
github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208
- golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
+ golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899
golang.org/x/net v0.0.0-20200625001655-4c5254603344 // indirect
- golang.org/x/sync v0.0.0-20190423024810-112230192c58
- golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd
+ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
+ golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c
golang.org/x/text v0.3.2
- golang.org/x/time v0.0.0-20190308202827-9d24e82272b4
+ golang.org/x/time v0.0.0-20191024005414-555d28b269f0
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6
gopkg.in/urfave/cli.v1 v1.20.0
diff --git a/go.sum b/go.sum
index d0e87bd69cc3..f00dcfaad8d7 100644
--- a/go.sum
+++ b/go.sum
@@ -1,3 +1,4 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4=
github.com/Azure/azure-pipeline-go v0.2.2 h1:6oiIS9yaG6XCCzhgAgKFfIWyo4LLCiDhZot6ltoThhY=
github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc=
@@ -21,30 +22,50 @@ github.com/Azure/go-autorest/tracing v0.5.0 h1:TRn4WjSnkcSy5AEG3pnbtFSwNtwzjr4VY
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
-github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8=
-github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
+github.com/Shopify/sarama v1.26.1/go.mod h1:NbSGBSSndYaIhRcBtY9V0U7AyH+x71bG668AuWys/yU=
+github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
+github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk=
+github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/VictoriaMetrics/fastcache v1.5.7 h1:4y6y0G8PRzszQUYIQHHssv/jgPHAb5qQuuDNdCbyAgw=
github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8=
+github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8=
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
-github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847 h1:rtI0fD4oG/8eVokGVPYJEW1F88p1ZNgXiEIs9thEE4A=
-github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ=
+github.com/aristanetworks/fsnotify v1.4.2/go.mod h1:D/rtu7LpjYM8tRJphJ0hUBYpjai8SfX+aSNsWDTq/Ks=
+github.com/aristanetworks/glog v0.0.0-20191112221043-67e8567f59f3/go.mod h1:KASm+qXFKs/xjSoWn30NrWBBvdTTQq+UjkhjEJHfSFA=
+github.com/aristanetworks/goarista v0.0.0-20200609010056-95bcf8053598 h1:VbwKXgO1O1JSbI8o3PQqlC/KTem5t3YD7LqvfBT+0Gk=
+github.com/aristanetworks/goarista v0.0.0-20200609010056-95bcf8053598/go.mod h1:QZe5Yh80Hp1b6JxQdpfSEEe8X7hTyTEZSosSrFf/oJE=
+github.com/aristanetworks/splunk-hec-go v0.3.3/go.mod h1:1VHO9r17b0K7WmOlLb9nTk/2YanvOEnLMUgsFrxBROc=
github.com/aws/aws-sdk-go v1.25.48 h1:J82DYDGZHOKHdhx6hD24Tm30c2C3GchYGfN0mf9iKUk=
github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
-github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6 h1:Eey/GGQ/E5Xp1P2Lyx1qj007hLZfbi0+CoVeJruGCtI=
-github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw=
+github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
+github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
+github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
+github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
+github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
+github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
+github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
+github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk=
github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9 h1:J82+/8rub3qSy0HxEnoYD8cs+HDlHWYrqYXe2Vqxluk=
github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -59,41 +80,62 @@ github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf h1:sh8rkQZavChcmak
github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/dop251/goja v0.0.0-20200219165308-d1232e640a87 h1:OMbqMXf9OAXzH1dDH82mQMrddBE8LIIwDtxeK4wE1/A=
github.com/dop251/goja v0.0.0-20200219165308-d1232e640a87/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA=
+github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
+github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
+github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c h1:JHHhtb9XWJrGNMcrVP6vyzO4dusgi/HnceHTgxSejUM=
github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.3.0 h1:YehCCcyeQ6Km0D6+IapqPinWBK6y+0eB5umvZXK9WPs=
github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc h1:jtW8jbpkO4YirRSyepBOH8E+2HEw6/hKkBvFPwhUN8c=
github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
+github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
+github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI=
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk=
+github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0 h1:8HUsc87TaSWLKwrnumgC8/YconD2fJQsRJAsWaPg2ic=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
-github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E=
-github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
+github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
+github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
github.com/go-sourcemap/sourcemap v2.1.2+incompatible h1:0b/xya7BKGhXuqFESKM4oIiRo9WOt2ebz7KxfreD6ug=
github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.2-0.20190904063534-ff6b7dc882cf h1:gFVkHXmVAhEbxZVDln5V9GKrLaluNoFHDbrZwAWZgws=
github.com/golang/snappy v0.0.2-0.20190904063534-ff6b7dc882cf/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989 h1:giknQ4mEuDFmmHSrGcbargOuLHQGtywqo4mheITex54=
github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277 h1:E0whKxgp2ojts0FDgUA8dl62bmH0LxKanMoBr6MDTDM=
github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc=
+github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/holiman/uint256 v1.1.1 h1:4JywC80b+/hSfljFlEBLHrrh+CIONLDz9NuFl0af4Mw=
@@ -105,18 +147,32 @@ github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883 h1:FSeK4fZCo8u40n2JMnyAsd6x7+SbvoOMHvQOU/n10P4=
github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=
+github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458 h1:6OvNmYgJyexcZ3pYbTI9jWx5tHo1Dee/tWbLMfPe2TA=
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
+github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
+github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
-github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21 h1:F/iKcka0K2LgnKy/fgSBf235AETtm1n1TvBzqu40LE0=
-github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/julienschmidt/httprouter v1.2.0 h1:TDTW5Yz1mjftljbcKqRcrYhd4XeOoI98t+9HbQbYf7g=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356 h1:I/yrLt2WilKxlQKCM52clh5rGzTKpVctGT1lH4Dc8Jw=
github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
+github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
+github.com/klauspost/compress v1.9.8/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
+github.com/klauspost/compress v1.10.1/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
+github.com/klauspost/reedsolomon v1.9.3/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
+github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
@@ -133,6 +189,11 @@ github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/naoina/go-stringutil v0.1.0 h1:rCUeRUHjBjGTSHl0VC00jUPLz8/F9dDzYI70Hzifhks=
github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=
github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 h1:shk/vn9oCoOTmwcouEdwIeOtOGA/ELRUw/GwvxwfT+0=
@@ -144,25 +205,45 @@ github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c/go.mod h1
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo=
+github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
+github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/openconfig/gnmi v0.0.0-20190823184014-89b2bf29312c/go.mod h1:t+O9It+LKzfOAhKTT5O0ehDix+MTqbtT0T9t+7zzOvc=
+github.com/openconfig/reference v0.0.0-20190727015836-8dfd928c9696/go.mod h1:ym2A+zigScwkSEb/cVQB0/ZMpU3rqiH6X7WRRsxgOGw=
github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222 h1:goeTyGkArOZIVOMA0dQbyuPWGNQJZGPwPu/QS9GlpnA=
github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34=
github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 h1:oYW+YCJ1pachXTQmzR3rNLYGGz4g/UgFcjb28p/viDM=
github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0=
+github.com/pierrec/lz4 v2.4.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.4.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
+github.com/prometheus/procfs v0.0.10/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150 h1:ZeU+auZj1iNzN8iVhff6M38Mfu73FQiJve/GEXYJBjE=
github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rjeczalik/notify v0.9.1 h1:CLCKso/QK1snAlnhNR/CNvNiFU2saUtjV0bx3EwNeCE=
github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho=
github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00 h1:8DPul/X0IT/1TNMIxoKLwdemEOBBHDC/K4EB16Cw5WE=
@@ -170,9 +251,12 @@ github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9Ac
github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521 h1:3hxavr+IHMsQBrYUPQM5v0CgENFktkkbg1sfpgM3h20=
github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/shirou/gopsutil v2.20.5+incompatible h1:tYH07UPoQt0OCQdgWWMgYHy3/a9bcxNpBIysykNIP7I=
-github.com/shirou/gopsutil v2.20.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
+github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
+github.com/shirou/gopsutil v2.20.6+incompatible h1:P37G9YH8M4vqkKcwBosp+URN5O8Tay67D2MbR361ioY=
+github.com/shirou/gopsutil v2.20.6+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 h1:Gb2Tyox57NRNuZ2d3rmvB3pcmbu7O1RS3m8WRx7ilrg=
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=
@@ -181,51 +265,121 @@ github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 h1:njlZPzLwU639dk2kqnCPPv+wNjq7Xb6EfUxe/oX0/NM=
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d h1:gZZadD8H+fF+n9CmNhYL1Y0dJB+kLOmKd7FbPJLeGHs=
github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA=
+github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU=
+github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4=
+github.com/tjfoc/gmsm v1.3.0/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef h1:wHSqTBrZW24CsNJDfeh9Ex6Pm0Rcpc7qrgKBiL44vF4=
github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208 h1:1cngl9mPEoITZG8s8cVcUy5CeIBYhEESkOB7m6Gmkrk=
github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees=
+github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
+github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
+github.com/xtaci/kcp-go v5.4.20+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
+github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE=
+golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 h1:DZhuSZLsGlFL4CmhA8BcRA0mnthyA/nZ00AqCUo7vHg=
+golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200219091948-cb0a6d8edb6c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c h1:UIcGWL6/wpCfyGuJnRFJRurA+yj8RrW7Q6x2YMCXt6c=
+golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
+golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20200221224223-e1da425f72fd/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20200218151345-dad8c97a84f5/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+gopkg.in/bsm/ratelimit.v1 v1.0.0-20160220154919-db14e161995a/go.mod h1:KF9sEfUPAXdG8Oev9e99iLGnl2uJMjc5B+4y3O7x610=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo=
+gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q=
+gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4=
+gopkg.in/jcmturner/gokrb5.v7 v7.5.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM=
+gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6 h1:a6cXbcDDUkSBlpnkWV1bJ+vv3mOgQEltEJ2rPxroVu0=
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns=
+gopkg.in/redis.v4 v4.2.4/go.mod h1:8KREHdypkCEojGKQcjMqAODMICIVwZAONWq8RowTITA=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0=
@@ -233,5 +387,11 @@ gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHO
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/graphql/service.go b/graphql/service.go
index 302fd678f1d9..fb573a8d78c9 100644
--- a/graphql/service.go
+++ b/graphql/service.go
@@ -17,10 +17,7 @@
package graphql
import (
- "fmt"
-
"github.com/ethereum/go-ethereum/internal/ethapi"
- "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/graph-gophers/graphql-go"
"github.com/graph-gophers/graphql-go/relay"
@@ -47,13 +44,9 @@ func newHandler(stack *node.Node, backend ethapi.Backend, cors, vhosts []string)
h := &relay.Handler{Schema: s}
handler := node.NewHTTPHandlerStack(h, cors, vhosts)
- _ = stack.RegisterPath("/graphql/ui", GraphiQL{})
- _ = stack.RegisterPath("/graphql", handler)
- endpoint := stack.RegisterPath("/graphql/", handler)
+ stack.RegisterPath("GraphQL UI", "/graphql/ui", GraphiQL{})
+ stack.RegisterPath( "GraphQL", "/graphql", handler)
+ stack.RegisterPath("GraphQL", "/graphql/", handler)
- if endpoint != "" {
- log.Info("GraphQL configured on endpoint", "endpoint", fmt.Sprintf("http://%s/graphql", endpoint))
- log.Info("GraphQL web UI enabled", "endpoint", fmt.Sprintf("http://%s/graphql/ui", endpoint))
- }
return nil
}
diff --git a/node/node.go b/node/node.go
index d907d77d9eee..edb161a4c7a9 100644
--- a/node/node.go
+++ b/node/node.go
@@ -444,7 +444,7 @@ func (n *Node) RegisterAPIs(apis []rpc.API) {
}
// RegisterPath mounts the given handler on the given path on the canonical HTTP server.
-func (n *Node) RegisterPath(path string, handler http.Handler) string {
+func (n *Node) RegisterPath(name, path string, handler http.Handler) {
n.lock.Lock()
defer n.lock.Unlock()
@@ -452,7 +452,8 @@ func (n *Node) RegisterPath(path string, handler http.Handler) string {
panic("can't register HTTP handler on running/stopped node")
}
n.http.mux.Handle(path, handler)
- return n.http.endpoint
+
+ n.http.handlerNames[path] = name
}
// Attach creates an RPC client attached to an in-process API handler.
diff --git a/node/node_test.go b/node/node_test.go
index f5d25360c23e..f3f3cc1f3250 100644
--- a/node/node_test.go
+++ b/node/node_test.go
@@ -434,8 +434,7 @@ func TestRegisterPath_Successful(t *testing.T) {
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("success"))
})
- endpoint := node.RegisterPath("/test", handler)
- assert.Equal(t, "127.0.0.1:7878", endpoint)
+ node.RegisterPath("test", "/test", handler)
// start node
if err := node.Start(); err != nil {
@@ -470,8 +469,7 @@ func TestRegisterPath_Unsuccessful(t *testing.T) {
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("success"))
})
- endpoint := node.RegisterPath("/test", handler)
- assert.Equal(t, "", endpoint)
+ node.RegisterPath("test", "/test", handler)
}
// // Tests whether a node can successfully create and register HTTP server
diff --git a/node/rpcstack.go b/node/rpcstack.go
index d1541cd98650..71ed2de09837 100644
--- a/node/rpcstack.go
+++ b/node/rpcstack.go
@@ -90,13 +90,15 @@ type httpServer struct {
port int
config httpConfig
+ handlerNames map[string]string
+
// atomic flags for the handler
rpcAllowedFlag int32
wsAllowedFlag int32
}
func newHTTPServer(log log.Logger, timeouts rpc.HTTPTimeouts) *httpServer {
- return &httpServer{log: log, timeouts: timeouts}
+ return &httpServer{log: log, timeouts: timeouts, handlerNames: make(map[string]string)}
}
// setListenAddr configures the listening address of the server.
@@ -202,11 +204,36 @@ func (h *httpServer) start() error {
}
h.listener = listener
go h.server.Serve(listener)
+
+ // if server is websocket only, return after logging
+ if h.wsAllowed() && !h.rpcAllowed() {
+ h.log.Info("Websocket enabled",
+ "url", fmt.Sprintf("ws://%v/", listener.Addr()),
+ "cors", strings.Join(h.config.CorsAllowedOrigins, ","),
+ "vhosts", strings.Join(h.config.Vhosts, ","),
+ )
+ return nil
+ }
+ // log http endpoint
h.log.Info("HTTP endpoint opened",
"url", fmt.Sprintf("http://%v/", listener.Addr()),
"cors", strings.Join(h.config.CorsAllowedOrigins, ","),
"vhosts", strings.Join(h.config.Vhosts, ","),
)
+ // log ws endpoint
+ if h.wsAllowed() {
+ h.log.Info("Websocket enabled",
+ "url", fmt.Sprintf("ws://%v/", listener.Addr()),
+ "cors", strings.Join(h.config.CorsAllowedOrigins, ","),
+ "vhosts", strings.Join(h.config.Vhosts, ","),
+ )
+ return nil
+ }
+ // log all handlers mounted on server
+ for path, name := range h.handlerNames {
+ log.Info(name + " enabled", "url", "http://" + listener.Addr().String() + path)
+ }
+
return nil
}
From 2d8192978b8722eb5d62cbe5a99343da4617be72 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Mon, 27 Jul 2020 16:23:07 +0200
Subject: [PATCH 139/160] removed ws log
---
node/api.go | 2 +-
node/rpcstack.go | 19 +++----------------
2 files changed, 4 insertions(+), 17 deletions(-)
diff --git a/node/api.go b/node/api.go
index a8b700df481a..11a969b8b313 100644
--- a/node/api.go
+++ b/node/api.go
@@ -269,7 +269,7 @@ func (api *privateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
if err := server.start(); err != nil {
return false, err
}
- api.node.log.Info("WebSocket endpoint opened", "url", api.node.WSEndpoint())
+ api.node.http.log.Info("WebSocket endpoint opened", "url", api.node.WSEndpoint())
return true, nil
}
diff --git a/node/rpcstack.go b/node/rpcstack.go
index 71ed2de09837..4a60a0ce75ab 100644
--- a/node/rpcstack.go
+++ b/node/rpcstack.go
@@ -207,28 +207,15 @@ func (h *httpServer) start() error {
// if server is websocket only, return after logging
if h.wsAllowed() && !h.rpcAllowed() {
- h.log.Info("Websocket enabled",
- "url", fmt.Sprintf("ws://%v/", listener.Addr()),
- "cors", strings.Join(h.config.CorsAllowedOrigins, ","),
- "vhosts", strings.Join(h.config.Vhosts, ","),
- )
+ h.log.Info("Websocket enabled", "url", fmt.Sprintf("ws://%v/", listener.Addr()))
return nil
}
// log http endpoint
- h.log.Info("HTTP endpoint opened",
- "url", fmt.Sprintf("http://%v/", listener.Addr()),
+ h.log.Info("HTTP server started",
+ "endpoint", listener.Addr(),
"cors", strings.Join(h.config.CorsAllowedOrigins, ","),
"vhosts", strings.Join(h.config.Vhosts, ","),
)
- // log ws endpoint
- if h.wsAllowed() {
- h.log.Info("Websocket enabled",
- "url", fmt.Sprintf("ws://%v/", listener.Addr()),
- "cors", strings.Join(h.config.CorsAllowedOrigins, ","),
- "vhosts", strings.Join(h.config.Vhosts, ","),
- )
- return nil
- }
// log all handlers mounted on server
for path, name := range h.handlerNames {
log.Info(name + " enabled", "url", "http://" + listener.Addr().String() + path)
From c985bd4970932506c79c137583e2a06b8c527888 Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Mon, 27 Jul 2020 16:23:50 +0200
Subject: [PATCH 140/160] node: add test for StartRPC API
---
node/api_test.go | 277 ++++++++++++++++++++++++++++++++++++++++++
node/rpcstack_test.go | 16 +++
2 files changed, 293 insertions(+)
create mode 100644 node/api_test.go
diff --git a/node/api_test.go b/node/api_test.go
new file mode 100644
index 000000000000..0fe3d4faccd2
--- /dev/null
+++ b/node/api_test.go
@@ -0,0 +1,277 @@
+// Copyright 2020 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package node
+
+import (
+ "bytes"
+ "io"
+ "net"
+ "net/http"
+ "net/url"
+ "strings"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+// This test uses the admin_startRPC API, checking whether the HTTP server is started
+// correctly.
+func TestStartRPC(t *testing.T) {
+ type test struct {
+ name string
+ cfg Config
+ fn func(*testing.T, *Node, *privateAdminAPI)
+
+ // Checks. These run after the node is configured and all API calls have been made.
+ wantReachable bool // whether the HTTP server should be reachable at all
+ wantHandlers bool // whether RegisterPath handlers should be accessible
+ wantRPC bool // whether JSON-RPC/HTTP should be accessible
+ wantWS bool // whether JSON-RPC/WS should be accessible
+ }
+
+ tests := []test{
+ {
+ name: "all off",
+ cfg: Config{},
+ fn: func(t *testing.T, n *Node, api *privateAdminAPI) {
+ },
+ wantReachable: false,
+ wantHandlers: false,
+ wantRPC: false,
+ wantWS: false,
+ },
+ {
+
+ name: "rpc enabled through config",
+ cfg: Config{HTTPHost: "127.0.0.1"},
+ fn: func(t *testing.T, n *Node, api *privateAdminAPI) {
+ },
+ wantReachable: true,
+ wantHandlers: true,
+ wantRPC: true,
+ wantWS: false,
+ },
+ {
+ name: "rpc enabled through API",
+ cfg: Config{},
+ fn: func(t *testing.T, n *Node, api *privateAdminAPI) {
+ _, err := api.StartRPC(sp("127.0.0.1"), ip(0), nil, nil, nil)
+ assert.NoError(t, err)
+ },
+ wantReachable: true,
+ wantHandlers: true,
+ wantRPC: true,
+ wantWS: false,
+ },
+ {
+ name: "rpc stopped through API",
+ cfg: Config{HTTPHost: "127.0.0.1"},
+ fn: func(t *testing.T, n *Node, api *privateAdminAPI) {
+ _, err := api.StopRPC()
+ assert.NoError(t, err)
+ },
+ wantReachable: false,
+ wantHandlers: false,
+ wantRPC: false,
+ wantWS: false,
+ },
+ {
+ name: "ws enabled through config",
+ cfg: Config{WSHost: "127.0.0.1"},
+ wantReachable: true,
+ wantHandlers: false,
+ wantRPC: false,
+ wantWS: true,
+ },
+ {
+ name: "ws enabled through API",
+ cfg: Config{},
+ fn: func(t *testing.T, n *Node, api *privateAdminAPI) {
+ _, err := api.StartWS(sp("127.0.0.1"), ip(0), nil, nil)
+ assert.NoError(t, err)
+ },
+ wantReachable: true,
+ wantHandlers: false,
+ wantRPC: false,
+ wantWS: true,
+ },
+ {
+ name: "ws stopped through API",
+ cfg: Config{WSHost: "127.0.0.1"},
+ fn: func(t *testing.T, n *Node, api *privateAdminAPI) {
+ _, err := api.StopWS()
+ assert.NoError(t, err)
+ },
+ wantReachable: false,
+ wantHandlers: false,
+ wantRPC: false,
+ wantWS: false,
+ },
+ {
+ name: "ws enabled after RPC",
+ cfg: Config{HTTPHost: "127.0.0.1"},
+ fn: func(t *testing.T, n *Node, api *privateAdminAPI) {
+ wsport := n.http.port
+ _, err := api.StartWS(sp("127.0.0.1"), ip(wsport), nil, nil)
+ assert.NoError(t, err)
+ },
+ wantReachable: true,
+ wantHandlers: true,
+ wantRPC: true,
+ wantWS: true,
+ },
+ {
+ name: "ws enabled after RPC then stopped",
+ cfg: Config{HTTPHost: "127.0.0.1"},
+ fn: func(t *testing.T, n *Node, api *privateAdminAPI) {
+ wsport := n.http.port
+ _, err := api.StartWS(sp("127.0.0.1"), ip(wsport), nil, nil)
+ assert.NoError(t, err)
+
+ _, err = api.StopWS()
+ assert.NoError(t, err)
+ },
+ wantReachable: true,
+ wantHandlers: true,
+ wantRPC: true,
+ wantWS: false,
+ },
+ {
+ name: "rpc stopped with ws enabled",
+ fn: func(t *testing.T, n *Node, api *privateAdminAPI) {
+ _, err := api.StartRPC(sp("127.0.0.1"), ip(0), nil, nil, nil)
+ assert.NoError(t, err)
+
+ wsport := n.http.port
+ _, err = api.StartWS(sp("127.0.0.1"), ip(wsport), nil, nil)
+ assert.NoError(t, err)
+
+ _, err = api.StopRPC()
+ assert.NoError(t, err)
+ },
+ wantReachable: false,
+ wantHandlers: false,
+ wantRPC: false,
+ wantWS: false,
+ },
+ {
+ name: "rpc enabled after ws",
+ fn: func(t *testing.T, n *Node, api *privateAdminAPI) {
+ _, err := api.StartWS(sp("127.0.0.1"), ip(0), nil, nil)
+ assert.NoError(t, err)
+
+ wsport := n.http.port
+ _, err = api.StartRPC(sp("127.0.0.1"), ip(wsport), nil, nil, nil)
+ assert.NoError(t, err)
+ },
+ wantReachable: true,
+ wantHandlers: true,
+ wantRPC: true,
+ wantWS: true,
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ // Apply some sane defaults.
+ config := test.cfg
+ // config.Logger = testlog.Logger(t, log.LvlDebug)
+ config.NoUSB = true
+ config.P2P.NoDiscovery = true
+
+ // Create Node.
+ stack, err := New(&config)
+ if err != nil {
+ t.Fatal("can't create node:", err)
+ }
+ defer stack.Close()
+
+ // Register the test handler.
+ stack.RegisterPath("/test", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Write([]byte("OK"))
+ }))
+
+ if err := stack.Start(); err != nil {
+ t.Fatal("can't start node:", err)
+ }
+
+ // Run the API call hook.
+ if test.fn != nil {
+ test.fn(t, stack, &privateAdminAPI{stack})
+ }
+
+ // Check if the HTTP endpoints are available.
+ baseURL := stack.HTTPEndpoint()
+ reachable := checkReachable(baseURL)
+ handlersAvailable := checkBodyOK(baseURL + "/test")
+ rpcAvailable := checkModules(baseURL, nil) == nil
+ wsAvailable := checkModules(strings.Replace(baseURL, "http://", "ws://", 1), nil) == nil
+ if reachable != test.wantReachable {
+ t.Errorf("HTTP server is %sreachable, want it %sreachable", not(reachable), not(test.wantReachable))
+ }
+ if handlersAvailable != test.wantHandlers {
+ t.Errorf("RegisterPath handlers %savailable, want them %savailable", not(handlersAvailable), not(test.wantHandlers))
+ }
+ if rpcAvailable != test.wantRPC {
+ t.Errorf("HTTP RPC %savailable, want it %savailable", not(rpcAvailable), not(test.wantRPC))
+ }
+ if wsAvailable != test.wantWS {
+ t.Errorf("WS RPC %savailable, want it %savailable", not(wsAvailable), not(test.wantWS))
+ }
+ })
+ }
+}
+
+func checkReachable(rawurl string) bool {
+ u, err := url.Parse(rawurl)
+ if err != nil {
+ panic(err)
+ }
+ conn, err := net.Dial("tcp", u.Host)
+ if err != nil {
+ return false
+ }
+ conn.Close()
+ return true
+}
+
+func checkBodyOK(url string) bool {
+ resp, err := http.Get(url)
+ if err != nil {
+ return false
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode != 200 {
+ return false
+ }
+ buf := make([]byte, 2)
+ if _, err = io.ReadFull(resp.Body, buf); err != nil {
+ return false
+ }
+ return bytes.Equal(buf, []byte("OK"))
+}
+
+func sp(s string) *string { return &s }
+func ip(i int) *int { return &i }
+
+func not(ok bool) string {
+ if ok {
+ return ""
+ }
+ return "not "
+}
diff --git a/node/rpcstack_test.go b/node/rpcstack_test.go
index cd2dbf63b5f9..3ca7015da55d 100644
--- a/node/rpcstack_test.go
+++ b/node/rpcstack_test.go
@@ -1,3 +1,19 @@
+// Copyright 2020 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
package node
import (
From f2dbf7e7aae58c83c7e43f159ee4dc900794bb8e Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Mon, 27 Jul 2020 16:26:46 +0200
Subject: [PATCH 141/160] node: fix test
---
node/api_test.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/node/api_test.go b/node/api_test.go
index 0fe3d4faccd2..718af1ecbf49 100644
--- a/node/api_test.go
+++ b/node/api_test.go
@@ -201,7 +201,7 @@ func TestStartRPC(t *testing.T) {
defer stack.Close()
// Register the test handler.
- stack.RegisterPath("/test", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ stack.RegisterPath("test", "/test", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("OK"))
}))
From 47315c0abf2d8b4c89107861d66e2f2efb99086e Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Mon, 27 Jul 2020 18:20:07 +0200
Subject: [PATCH 142/160] node: delete redundant websocket enabling test
---
node/api_test.go | 24 +++++++++++++++---
node/rpcstack_test.go | 59 -------------------------------------------
2 files changed, 20 insertions(+), 63 deletions(-)
diff --git a/node/api_test.go b/node/api_test.go
index 718af1ecbf49..d0f5620f7add 100644
--- a/node/api_test.go
+++ b/node/api_test.go
@@ -25,11 +25,12 @@ import (
"strings"
"testing"
+ "github.com/ethereum/go-ethereum/rpc"
"github.com/stretchr/testify/assert"
)
-// This test uses the admin_startRPC API, checking whether the HTTP server is started
-// correctly.
+// This test uses the admin_startRPC and admin_startWS APIs,
+// checking whether the HTTP server is started correctly.
func TestStartRPC(t *testing.T) {
type test struct {
name string
@@ -218,8 +219,8 @@ func TestStartRPC(t *testing.T) {
baseURL := stack.HTTPEndpoint()
reachable := checkReachable(baseURL)
handlersAvailable := checkBodyOK(baseURL + "/test")
- rpcAvailable := checkModules(baseURL, nil) == nil
- wsAvailable := checkModules(strings.Replace(baseURL, "http://", "ws://", 1), nil) == nil
+ rpcAvailable := checkModules(baseURL)
+ wsAvailable := checkModules(strings.Replace(baseURL, "http://", "ws://", 1))
if reachable != test.wantReachable {
t.Errorf("HTTP server is %sreachable, want it %sreachable", not(reachable), not(test.wantReachable))
}
@@ -236,6 +237,7 @@ func TestStartRPC(t *testing.T) {
}
}
+// checkReachable checks if the TCP endpoint in rawurl is open.
func checkReachable(rawurl string) bool {
u, err := url.Parse(rawurl)
if err != nil {
@@ -249,6 +251,7 @@ func checkReachable(rawurl string) bool {
return true
}
+// checkBodyOK checks whether the given HTTP URL responds with 200 OK and body "OK".
func checkBodyOK(url string) bool {
resp, err := http.Get(url)
if err != nil {
@@ -266,6 +269,19 @@ func checkBodyOK(url string) bool {
return bytes.Equal(buf, []byte("OK"))
}
+// checkModules checks whether JSON-RPC works against the given URL.
+func checkModules(url string) bool {
+ c, err := rpc.Dial(url)
+ if err != nil {
+ return false
+ }
+ defer c.Close()
+
+ _, err = c.SupportedModules()
+ return err == nil
+}
+
+// string/int pointer helpers.
func sp(s string) *string { return &s }
func ip(i int) *int { return &i }
diff --git a/node/rpcstack_test.go b/node/rpcstack_test.go
index 3ca7015da55d..009c613d3e96 100644
--- a/node/rpcstack_test.go
+++ b/node/rpcstack_test.go
@@ -16,16 +16,6 @@
package node
-import (
- "fmt"
- "strings"
- "testing"
-
- "github.com/ethereum/go-ethereum/internal/testlog"
- "github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/rpc"
-)
-
// func TestNewWebsocketUpgradeHandler_websocket(t *testing.T) {
// h := &httpServer{
// Srv: rpc.NewServer(),
@@ -55,52 +45,3 @@ import (
// response := <-responses
// assert.Equal(t, "websocket", response.Header.Get("Upgrade"))
// }
-
-// Tests that a ws handler can be added to and enabled on an existing HTTPServer
-func TestWSAllowed(t *testing.T) {
- stack, err := New(&Config{
- HTTPHost: "127.0.0.1",
- HTTPPort: 0,
- WSHost: "127.0.0.1",
- WSPort: 0,
- Logger: testlog.Logger(t, log.LvlDebug),
- })
- if err != nil {
- t.Fatalf("could not create node: %v", err)
- }
- defer stack.Close()
-
- // start node
- err = stack.Start()
- if err != nil {
- t.Fatalf("could not start node: %v", err)
- }
-
- // check that HTTP works on the endpoint.
- url := stack.HTTPEndpoint()
- if err := checkModules(url, stack.Config().WSModules); err != nil {
- t.Fatal(err)
- }
-
- // check that WS works on the same endpoint.
- wsURL := strings.Replace(url, "http://", "ws://", 1)
- if err := checkModules(wsURL, stack.Config().WSModules); err != nil {
- t.Fatal(err)
- }
-}
-
-func checkModules(url string, want []string) error {
- c, err := rpc.Dial(url)
- if err != nil {
- return fmt.Errorf("can't create RPC client: %v", err)
- }
- defer c.Close()
-
- _, err = c.SupportedModules()
- if err != nil {
- return fmt.Errorf("can't get modules: %v", err)
- }
-
- // TODO: check module list
- return nil
-}
From 9a1131ce1102d1628eb0319673df688d00db306f Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Mon, 27 Jul 2020 19:14:54 +0200
Subject: [PATCH 143/160] node: fix all the HTTP server API tests
---
node/api.go | 4 +-
node/api_test.go | 31 +++++++++++-
node/rpcstack.go | 129 ++++++++++++++++++++++++++++-------------------
3 files changed, 107 insertions(+), 57 deletions(-)
diff --git a/node/api.go b/node/api.go
index 11a969b8b313..083784f4e4dd 100644
--- a/node/api.go
+++ b/node/api.go
@@ -275,9 +275,7 @@ func (api *privateAdminAPI) StartWS(host *string, port *int, allowedOrigins *str
// StopWS terminates all WebSocket servers.
func (api *privateAdminAPI) StopWS() (bool, error) {
- if api.node.http.wsAllowed() {
- api.node.http.disableWS()
- }
+ api.node.http.stopWS()
api.node.ws.stop()
return true, nil
}
diff --git a/node/api_test.go b/node/api_test.go
index d0f5620f7add..5e0cde7f050c 100644
--- a/node/api_test.go
+++ b/node/api_test.go
@@ -56,7 +56,6 @@ func TestStartRPC(t *testing.T) {
wantWS: false,
},
{
-
name: "rpc enabled through config",
cfg: Config{HTTPHost: "127.0.0.1"},
fn: func(t *testing.T, n *Node, api *privateAdminAPI) {
@@ -90,6 +89,21 @@ func TestStartRPC(t *testing.T) {
wantRPC: false,
wantWS: false,
},
+ {
+ name: "rpc stopped twice",
+ cfg: Config{HTTPHost: "127.0.0.1"},
+ fn: func(t *testing.T, n *Node, api *privateAdminAPI) {
+ _, err := api.StopRPC()
+ assert.NoError(t, err)
+
+ _, err = api.StopRPC()
+ assert.NoError(t, err)
+ },
+ wantReachable: false,
+ wantHandlers: false,
+ wantRPC: false,
+ wantWS: false,
+ },
{
name: "ws enabled through config",
cfg: Config{WSHost: "127.0.0.1"},
@@ -122,6 +136,21 @@ func TestStartRPC(t *testing.T) {
wantRPC: false,
wantWS: false,
},
+ {
+ name: "ws stopped twice",
+ cfg: Config{WSHost: "127.0.0.1"},
+ fn: func(t *testing.T, n *Node, api *privateAdminAPI) {
+ _, err := api.StopWS()
+ assert.NoError(t, err)
+
+ _, err = api.StopWS()
+ assert.NoError(t, err)
+ },
+ wantReachable: false,
+ wantHandlers: false,
+ wantRPC: false,
+ wantWS: false,
+ },
{
name: "ws enabled after RPC",
cfg: Config{HTTPHost: "127.0.0.1"},
diff --git a/node/rpcstack.go b/node/rpcstack.go
index 4a60a0ce75ab..8fbabb66a312 100644
--- a/node/rpcstack.go
+++ b/node/rpcstack.go
@@ -77,28 +77,32 @@ type httpServer struct {
server *http.Server
listener net.Listener // non-nil when server is running
+ // HTTP RPC handler things.
httpConfig httpConfig
- httpRPC *rpc.Server
- httpHandler http.Handler
+ httpHandler atomic.Value // *rpcHandler
+ // WebSocket handler things.
wsConfig wsConfig
- wsRPC *rpc.Server
- wsHandler http.Handler
+ wsHandler atomic.Value // *rpcHandler
+ // These are set by setListenAddr.
endpoint string
host string
port int
- config httpConfig
handlerNames map[string]string
+}
- // atomic flags for the handler
- rpcAllowedFlag int32
- wsAllowedFlag int32
+type rpcHandler struct {
+ http.Handler
+ server *rpc.Server
}
func newHTTPServer(log log.Logger, timeouts rpc.HTTPTimeouts) *httpServer {
- return &httpServer{log: log, timeouts: timeouts, handlerNames: make(map[string]string)}
+ h := &httpServer{log: log, timeouts: timeouts, handlerNames: make(map[string]string)}
+ h.httpHandler.Store((*rpcHandler)(nil))
+ h.wsHandler.Store((*rpcHandler)(nil))
+ return h
}
// setListenAddr configures the listening address of the server.
@@ -132,19 +136,20 @@ func (h *httpServer) enableRPC(apis []rpc.API, config httpConfig) error {
h.mu.Lock()
defer h.mu.Unlock()
- if h.httpRPC != nil {
+ if h.rpcAllowed() {
return fmt.Errorf("JSON-RPC over HTTP is already enabled")
}
- // Create RPC server.
+ // Create RPC server and handler.
srv := rpc.NewServer()
- if err := RegisterApisFromWhitelist(apis, h.httpConfig.Modules, srv, false); err != nil {
+ if err := RegisterApisFromWhitelist(apis, config.Modules, srv, false); err != nil {
return err
}
- // Create handler.
- h.httpRPC = srv
- h.httpHandler = NewHTTPHandlerStack(h.httpRPC, config.CorsAllowedOrigins, config.Vhosts)
- atomic.StoreInt32(&h.rpcAllowedFlag, 1)
+ h.httpConfig = config
+ h.httpHandler.Store(&rpcHandler{
+ Handler: NewHTTPHandlerStack(srv, config.CorsAllowedOrigins, config.Vhosts),
+ server: srv,
+ })
return nil
}
@@ -153,30 +158,37 @@ func (h *httpServer) enableWS(apis []rpc.API, config wsConfig) error {
h.mu.Lock()
defer h.mu.Unlock()
- if h.wsRPC != nil {
+ if h.wsAllowed() {
return fmt.Errorf("JSON-RPC over WebSocket is already enabled")
}
- // Create RPC server.
+ // Create RPC server and handler.
srv := rpc.NewServer()
- if err := RegisterApisFromWhitelist(apis, h.wsConfig.Modules, srv, false); err != nil {
+ if err := RegisterApisFromWhitelist(apis, config.Modules, srv, false); err != nil {
return err
}
- // Create handler.
- h.wsRPC = rpc.NewServer()
- h.wsHandler = h.wsRPC.WebsocketHandler(config.Origins)
- atomic.StoreInt32(&h.wsAllowedFlag, 1)
+ h.wsConfig = config
+ h.wsHandler.Store(&rpcHandler{
+ Handler: srv.WebsocketHandler(config.Origins),
+ server: srv,
+ })
return nil
}
-// disableWS disables JSON-RPC over WebSocket.
-func (h *httpServer) disableWS() {
+// stopWS disables JSON-RPC over WebSocket.
+func (h *httpServer) stopWS() {
h.mu.Lock()
defer h.mu.Unlock()
- atomic.StoreInt32(&h.wsAllowedFlag, 0)
- h.wsRPC.Stop()
- h.wsRPC = nil
+ ws := h.wsHandler.Load().(*rpcHandler)
+ if ws != nil {
+ h.wsHandler.Store((*rpcHandler)(nil))
+ ws.server.Stop()
+ // If this server only served WebSocket, stop the HTTP server as well.
+ if !h.rpcAllowed() {
+ h.doStop()
+ }
+ }
}
// start starts the HTTP server if it is enabled and not already running.
@@ -213,69 +225,80 @@ func (h *httpServer) start() error {
// log http endpoint
h.log.Info("HTTP server started",
"endpoint", listener.Addr(),
- "cors", strings.Join(h.config.CorsAllowedOrigins, ","),
- "vhosts", strings.Join(h.config.Vhosts, ","),
+ "cors", strings.Join(h.httpConfig.CorsAllowedOrigins, ","),
+ "vhosts", strings.Join(h.httpConfig.Vhosts, ","),
)
// log all handlers mounted on server
for path, name := range h.handlerNames {
- log.Info(name + " enabled", "url", "http://" + listener.Addr().String() + path)
+ log.Info(name+" enabled", "url", "http://"+listener.Addr().String()+path)
}
return nil
}
// stop shuts down the HTTP server.
-func (h *httpServer) stop() error {
+func (h *httpServer) stop() {
h.mu.Lock()
defer h.mu.Unlock()
+ h.doStop()
+}
+
+func (h *httpServer) doStop() {
if h.listener == nil {
- return nil // not running
+ return // not running
}
// Shut down the server.
- if h.httpRPC != nil {
- h.httpRPC.Stop()
+ httpHandler := h.httpHandler.Load().(*rpcHandler)
+ wsHandler := h.httpHandler.Load().(*rpcHandler)
+ if httpHandler != nil {
+ h.httpHandler.Store((*rpcHandler)(nil))
+ httpHandler.server.Stop()
}
- if h.wsRPC != nil {
- h.wsRPC.Stop()
+ if wsHandler != nil {
+ h.wsHandler.Store((*rpcHandler)(nil))
+ wsHandler.server.Stop()
}
h.server.Shutdown(context.Background())
h.listener.Close()
- h.log.Info("HTTP endpoint closed", "url", h.endpoint)
+ h.log.Info("HTTP server stopped", "endpoint", h.listener.Addr())
// Clear out everything to allow re-configuring it later.
h.host, h.port, h.endpoint = "", 0, ""
h.server, h.listener = nil, nil
- h.httpRPC, h.httpHandler, h.wsRPC, h.wsHandler = nil, nil, nil, nil
- atomic.StoreInt32(&h.rpcAllowedFlag, 0)
- atomic.StoreInt32(&h.wsAllowedFlag, 0)
- return nil
}
// rpcAllowed returns true when JSON-RPC over HTTP is enabled.
func (h *httpServer) rpcAllowed() bool {
- return atomic.LoadInt32(&h.rpcAllowedFlag) == 1
+ return h.httpHandler.Load().(*rpcHandler) != nil
}
// wsAllowed returns true when JSON-RPC over WebSocket is enabled.
func (h *httpServer) wsAllowed() bool {
- return atomic.LoadInt32(&h.wsAllowedFlag) == 1
+ return h.wsHandler.Load().(*rpcHandler) != nil
}
func (h *httpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
- if h.wsAllowed() && isWebsocket(r) {
- h.wsHandler.ServeHTTP(w, r)
- return
- }
+ rpc := h.httpHandler.Load().(*rpcHandler)
if r.RequestURI == "/" {
- if h.rpcAllowed() {
- h.httpHandler.ServeHTTP(w, r)
- } else {
- w.WriteHeader(404)
+ // Serve JSON-RPC on the root path.
+ ws := h.wsHandler.Load().(*rpcHandler)
+ if ws != nil && isWebsocket(r) {
+ ws.ServeHTTP(w, r)
+ return
}
- } else {
+ if rpc != nil {
+ rpc.ServeHTTP(w, r)
+ return
+ }
+ } else if rpc != nil {
+ // Requests to a path below root are handled by the mux,
+ // which has all the handlers registered via Node.RegisterPath.
+ // These are made available when RPC is enabled.
h.mux.ServeHTTP(w, r)
+ return
}
+ w.WriteHeader(404)
}
// isWebsocket checks the header of an http request for a websocket upgrade request.
From 6d544c6b4b91a3a1deeca0894ff0bad18e6e1187 Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Mon, 27 Jul 2020 19:17:09 +0200
Subject: [PATCH 144/160] node: improve comments
---
node/rpcstack.go | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/node/rpcstack.go b/node/rpcstack.go
index 8fbabb66a312..9e92e9beb3bf 100644
--- a/node/rpcstack.go
+++ b/node/rpcstack.go
@@ -219,16 +219,16 @@ func (h *httpServer) start() error {
// if server is websocket only, return after logging
if h.wsAllowed() && !h.rpcAllowed() {
- h.log.Info("Websocket enabled", "url", fmt.Sprintf("ws://%v/", listener.Addr()))
+ h.log.Info("WebSocket enabled", "url", fmt.Sprintf("ws://%v", listener.Addr()))
return nil
}
- // log http endpoint
+ // Log http endpoint.
h.log.Info("HTTP server started",
"endpoint", listener.Addr(),
"cors", strings.Join(h.httpConfig.CorsAllowedOrigins, ","),
"vhosts", strings.Join(h.httpConfig.Vhosts, ","),
)
- // log all handlers mounted on server
+ // Log all handlers mounted on server.
for path, name := range h.handlerNames {
log.Info(name+" enabled", "url", "http://"+listener.Addr().String()+path)
}
From d7c12580a8091dd26b3044728204f1aab8c8863e Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Mon, 27 Jul 2020 19:27:13 +0200
Subject: [PATCH 145/160] node: fix starting RPC after it failed to listen
---
node/api_test.go | 28 ++++++++++++++++++++++++++++
node/rpcstack.go | 29 +++++++++++++++++++++++++----
2 files changed, 53 insertions(+), 4 deletions(-)
diff --git a/node/api_test.go b/node/api_test.go
index 5e0cde7f050c..74aa40a930a5 100644
--- a/node/api_test.go
+++ b/node/api_test.go
@@ -77,6 +77,34 @@ func TestStartRPC(t *testing.T) {
wantRPC: true,
wantWS: false,
},
+ {
+ name: "rpc start again after failure",
+ cfg: Config{},
+ fn: func(t *testing.T, n *Node, api *privateAdminAPI) {
+ // Listen on a random port.
+ listener, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal("can't listen:", err)
+ }
+ defer listener.Close()
+ port := listener.Addr().(*net.TCPAddr).Port
+
+ // Now try to start RPC on that port. This should fail.
+ _, err = api.StartRPC(sp("127.0.0.1"), ip(port), nil, nil, nil)
+ if err == nil {
+ t.Fatal("StartRPC should have failed on port", port)
+ }
+
+ // Try again after unblocking the port. It should work this time.
+ listener.Close()
+ _, err = api.StartRPC(sp("127.0.0.1"), ip(port), nil, nil, nil)
+ assert.NoError(t, err)
+ },
+ wantReachable: true,
+ wantHandlers: true,
+ wantRPC: true,
+ wantWS: false,
+ },
{
name: "rpc stopped through API",
cfg: Config{HTTPHost: "127.0.0.1"},
diff --git a/node/rpcstack.go b/node/rpcstack.go
index 9e92e9beb3bf..6a572beabf9e 100644
--- a/node/rpcstack.go
+++ b/node/rpcstack.go
@@ -153,6 +153,16 @@ func (h *httpServer) enableRPC(apis []rpc.API, config httpConfig) error {
return nil
}
+// disableRPC stops the HTTP RPC handler. The caller must hold h.mu.
+func (h *httpServer) disableRPC() bool {
+ handler := h.httpHandler.Load().(*rpcHandler)
+ if handler != nil {
+ h.httpHandler.Store((*rpcHandler)(nil))
+ handler.server.Stop()
+ }
+ return handler != nil
+}
+
// enableWS turns on JSON-RPC over WebSocket on the server.
func (h *httpServer) enableWS(apis []rpc.API, config wsConfig) error {
h.mu.Lock()
@@ -180,10 +190,7 @@ func (h *httpServer) stopWS() {
h.mu.Lock()
defer h.mu.Unlock()
- ws := h.wsHandler.Load().(*rpcHandler)
- if ws != nil {
- h.wsHandler.Store((*rpcHandler)(nil))
- ws.server.Stop()
+ if h.disableWS() {
// If this server only served WebSocket, stop the HTTP server as well.
if !h.rpcAllowed() {
h.doStop()
@@ -191,6 +198,16 @@ func (h *httpServer) stopWS() {
}
}
+// disableWS stops the WebSocket handler. The caller must hold h.mu.
+func (h *httpServer) disableWS() bool {
+ ws := h.wsHandler.Load().(*rpcHandler)
+ if ws != nil {
+ h.wsHandler.Store((*rpcHandler)(nil))
+ ws.server.Stop()
+ }
+ return ws != nil
+}
+
// start starts the HTTP server if it is enabled and not already running.
func (h *httpServer) start() error {
h.mu.Lock()
@@ -212,6 +229,10 @@ func (h *httpServer) start() error {
// Start the server.
listener, err := net.Listen("tcp", h.endpoint)
if err != nil {
+ // If the server fails to start, we need to clear out the RPC and WS
+ // configuration so they can be configured another time.
+ h.disableRPC()
+ h.disableWS()
return err
}
h.listener = listener
From b8b1046dd394ba1aa2f9f99c670ee6db5fca03ce Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Mon, 27 Jul 2020 20:02:21 +0200
Subject: [PATCH 146/160] changed node tests
---
node/api_test.go | 8 +--
node/node_test.go | 147 ++++++++++++------------------------------
node/rpcstack_test.go | 42 ++++--------
3 files changed, 58 insertions(+), 139 deletions(-)
diff --git a/node/api_test.go b/node/api_test.go
index 74aa40a930a5..a576b2387557 100644
--- a/node/api_test.go
+++ b/node/api_test.go
@@ -276,8 +276,8 @@ func TestStartRPC(t *testing.T) {
baseURL := stack.HTTPEndpoint()
reachable := checkReachable(baseURL)
handlersAvailable := checkBodyOK(baseURL + "/test")
- rpcAvailable := checkModules(baseURL)
- wsAvailable := checkModules(strings.Replace(baseURL, "http://", "ws://", 1))
+ rpcAvailable := checkRPC(baseURL)
+ wsAvailable := checkRPC(strings.Replace(baseURL, "http://", "ws://", 1))
if reachable != test.wantReachable {
t.Errorf("HTTP server is %sreachable, want it %sreachable", not(reachable), not(test.wantReachable))
}
@@ -326,8 +326,8 @@ func checkBodyOK(url string) bool {
return bytes.Equal(buf, []byte("OK"))
}
-// checkModules checks whether JSON-RPC works against the given URL.
-func checkModules(url string) bool {
+// checkRPC checks whether JSON-RPC works against the given URL.
+func checkRPC(url string) bool {
c, err := rpc.Dial(url)
if err != nil {
return false
diff --git a/node/node_test.go b/node/node_test.go
index f3f3cc1f3250..e7fbe8f835e6 100644
--- a/node/node_test.go
+++ b/node/node_test.go
@@ -18,11 +18,14 @@ package node
import (
"errors"
+ "fmt"
"io"
"io/ioutil"
+ "net"
"net/http"
"os"
"reflect"
+ "strings"
"testing"
"github.com/ethereum/go-ethereum/crypto"
@@ -348,7 +351,7 @@ func TestLifecycleTerminationGuarantee(t *testing.T) {
failer := &InstrumentedService{stop: failure}
stack.RegisterLifecycle(failer)
- // Start the protocol stack, and ensure that a failing shut down terminates all // TODO, deleting loop because constructors no longer stored on node.
+ // Start the protocol stack, and ensure that a failing shut down terminates all
// Start the stack and make sure all is online
if err := stack.Start(); err != nil {
t.Fatalf("failed to start protocol stack: %v", err)
@@ -386,45 +389,6 @@ func TestLifecycleTerminationGuarantee(t *testing.T) {
stack.server.PrivateKey = testNodeKey
}
-// // Tests whether a given httpServer can be registered on the node
-// func TestRegisterHTTPServer(t *testing.T) {
-// stack, err := New(testNodeConfig())
-// if err != nil {
-// t.Fatalf("failed to create protocol stack: %v", err)
-// }
-// defer stack.Close()
-//
-// srv1 := &httpServer{
-// host: "test1",
-// port: 0001,
-// }
-// endpoint1 := fmt.Sprintf("%s:%d", srv1.host, srv1.port)
-// stack.registerHTTPServer(endpoint1, srv1)
-//
-// srv2 := &httpServer{
-// host: "test2",
-// port: 0002,
-// }
-// endpoint2 := fmt.Sprintf("%s:%d", srv2.host, srv2.port)
-// stack.registerHTTPServer(endpoint2, srv2)
-//
-// noop := &httpServer{
-// host: "test",
-// port: 0000,
-// }
-// endpointNoop := fmt.Sprintf("%s:%d", noop.host, noop.port)
-//
-// if srv1 != stack.existingHTTPServer(endpoint1) {
-// t.Fatalf("server %v was not properly registered on the given endpoint %s", srv1, endpoint1)
-// }
-// if srv2 != stack.existingHTTPServer(endpoint2) {
-// t.Fatalf("server %v was not properly registered on the given endpoint %s", srv2, endpoint2)
-// }
-// if noop == stack.existingHTTPServer(endpointNoop) {
-// t.Fatalf("server %v was incorrectly registered on the given endpoint %s", noop, endpointNoop)
-// }
-// }
-
// Tests whether a handler can be successfully mounted on the canonical HTTP server
// on the given path
func TestRegisterPath_Successful(t *testing.T) {
@@ -472,83 +436,54 @@ func TestRegisterPath_Unsuccessful(t *testing.T) {
node.RegisterPath("test", "/test", handler)
}
-// // Tests whether a node can successfully create and register HTTP server
-// // lifecycles on the node.
-// func TestHTTPServerCreateAndStop(t *testing.T) {
-// // test on same ports
-// node1 := startHTTP(t, 7453, 7453)
-// if len(node1.httpServers) != 1 {
-// t.Fatalf("node has more than 1 http server")
-// }
-// // check to make sure http servers are registered
-// if !containsLifecycle(node1.lifecycles, &node1.httpServers) {
-// t.Fatal("HTTP servers not registered as lifecycles on the node")
-// }
-// // check to make sure http servers are configured properly
-// for _, server := range node1.httpServers {
-// if atomic.LoadInt32(&server.WSAllowed) == 0 && atomic.LoadInt32(&server.RPCAllowed) == 0 {
-// t.Fatalf("node's http server is not configured to handle both rpc and ws")
-// }
-// node1.stopServer(server)
-// if node1.existingHTTPServer(server.endpoint) != nil {
-// t.Fatalf("failed to remove server %v from node after stopping it", server)
-// }
-// }
-// node1.Close()
-//
-// // test on separate ports
-// node2 := startHTTP(t, 7453, 9393)
-// if len(node2.httpServers) != 2 {
-// t.Fatalf("amount of http servers on the node is not equal to 2")
-// }
-// // check to make sure http servers are registered
-// if !containsLifecycle(node2.lifecycles, &node2.httpServers) {
-// t.Fatal("HTTP servers not registered as lifecycles on the node")
-// }
-// // check that neither http server has both ws and rpc enabled
-// for _, server := range node2.httpServers {
-// if atomic.LoadInt32(&server.WSAllowed) == 1 && atomic.LoadInt32(&server.RPCAllowed) == 1 {
-// t.Fatalf("both rpc and ws allowed on a single http server")
-// }
-// node2.stopServer(server)
-// if node2.existingHTTPServer(server.endpoint) != nil {
-// t.Fatalf("failed to remove server %v from node after stopping it", server)
-// }
-// }
-// node2.Close()
-// }
-
// Tests whether websocket requests can be handled on the same port as a regular http server.
func TestWebsocketHTTPOnSamePort_WebsocketRequest(t *testing.T) {
- node := startHTTP(t, 7453, 7453)
+ node := startHTTP(t, 0, 0)
defer node.Close()
- wsReq, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:7453", nil)
- if err != nil {
- t.Error("could not issue new http request ", err)
- }
- wsReq.Header.Set("Connection", "upgrade")
- wsReq.Header.Set("Upgrade", "websocket")
- wsReq.Header.Set("Sec-WebSocket-Version", "13")
- wsReq.Header.Set("Sec-Websocket-Key", "SGVsbG8sIHdvcmxkIQ==")
+ ws := strings.Replace(node.HTTPEndpoint() , "http://", "ws://", 1)
- resp := doHTTPRequest(t, wsReq)
- assert.Equal(t, "websocket", resp.Header.Get("Upgrade"))
+ if node.WSEndpoint() != ws {
+ t.Fatalf("endpoints should be the same")
+ }
+ if !checkRPC(ws) {
+ t.Fatalf("ws request failed")
+ }
+ if !checkRPC(node.HTTPEndpoint()) {
+ t.Fatalf("http request failed")
+ }
}
-// Tests whether http requests can be handled successfully.
-func TestWebsocketHTTPOnSamePort_HTTPRequest(t *testing.T) {
- node := startHTTP(t, 7453, 7453)
+func TestWebsocketHTTPOnSeparatePort_WSRequest(t *testing.T) {
+ // try and get a free port
+ listener, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal("can't listen:", err)
+ }
+ port := listener.Addr().(*net.TCPAddr).Port
+ listener.Close()
+
+ node := startHTTP(t, 0, port)
defer node.Close()
- httpReq, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:7453", nil)
- if err != nil {
- t.Error("could not issue new http request ", err)
+ wsOnHTTP := strings.Replace(node.HTTPEndpoint() , "http://", "ws://", 1)
+ ws := fmt.Sprintf("ws://127.0.0.1:%d", port)
+
+ if node.WSEndpoint() == wsOnHTTP {
+ t.Fatalf("endpoints should not be the same")
+ }
+ // ensure ws endpoint matches the expected endpoint
+ if node.WSEndpoint() != ws {
+ t.Fatalf("ws endpoint is incorrect: expected %s, got %s", ws, node.WSEndpoint())
+ }
+
+ if !checkRPC(ws) {
+ t.Fatalf("ws request failed")
+ }
+ if !checkRPC(node.HTTPEndpoint()) {
+ t.Fatalf("http request failed")
}
- httpReq.Header.Set("Accept-Encoding", "gzip")
- resp := doHTTPRequest(t, httpReq)
- assert.Equal(t, "gzip", resp.Header.Get("Content-Encoding"))
}
func createNode(t *testing.T, httpPort, wsPort int) *Node {
diff --git a/node/rpcstack_test.go b/node/rpcstack_test.go
index 009c613d3e96..4b09aa7460e4 100644
--- a/node/rpcstack_test.go
+++ b/node/rpcstack_test.go
@@ -16,32 +16,16 @@
package node
-// func TestNewWebsocketUpgradeHandler_websocket(t *testing.T) {
-// h := &httpServer{
-// Srv: rpc.NewServer(),
-// WSAllowed: 1,
-// }
-// handler := h.NewWebsocketUpgradeHandler(nil, h.Srv.WebsocketHandler([]string{}))
-// ts := httptest.NewServer(handler)
-// defer ts.Close()
-//
-// responses := make(chan *http.Response)
-// go func(responses chan *http.Response) {
-// client := &http.Client{}
-//
-// req, _ := http.NewRequest(http.MethodGet, ts.URL, nil)
-// req.Header.Set("Connection", "upgrade")
-// req.Header.Set("Upgrade", "websocket")
-// req.Header.Set("Sec-WebSocket-Version", "13")
-// req.Header.Set("Sec-Websocket-Key", "SGVsbG8sIHdvcmxkIQ==")
-//
-// resp, err := client.Do(req)
-// if err != nil {
-// t.Fatalf("could not issue a GET request to the test http server %v", err)
-// }
-// responses <- resp
-// }(responses)
-//
-// response := <-responses
-// assert.Equal(t, "websocket", response.Header.Get("Upgrade"))
-// }
+import (
+ "github.com/ethereum/go-ethereum/internal/testlog"
+ "github.com/ethereum/go-ethereum/log"
+ "github.com/ethereum/go-ethereum/rpc"
+ "testing"
+)
+
+func TestCorsHandler(t *testing.T) {
+ srv := newHTTPServer(testlog.Logger(t, log.LvlDebug), rpc.DefaultHTTPTimeouts)
+
+}
+
+
From 858096248446c6edc99700ac03e0d78d4bdd38e6 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Mon, 27 Jul 2020 20:25:16 +0200
Subject: [PATCH 147/160] rpcstack tests
---
node/node_test.go | 2 +-
node/rpcstack_test.go | 45 ++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 45 insertions(+), 2 deletions(-)
diff --git a/node/node_test.go b/node/node_test.go
index e7fbe8f835e6..c78f5e7b063b 100644
--- a/node/node_test.go
+++ b/node/node_test.go
@@ -511,7 +511,7 @@ func startHTTP(t *testing.T, httpPort, wsPort int) *Node {
}
func doHTTPRequest(t *testing.T, req *http.Request) *http.Response {
- client := &http.Client{}
+ client := http.DefaultClient
resp, err := client.Do(req)
if err != nil {
t.Fatalf("could not issue a GET request to the given endpoint: %v", err)
diff --git a/node/rpcstack_test.go b/node/rpcstack_test.go
index 4b09aa7460e4..9b4af6135e29 100644
--- a/node/rpcstack_test.go
+++ b/node/rpcstack_test.go
@@ -17,15 +17,58 @@
package node
import (
+ "bytes"
"github.com/ethereum/go-ethereum/internal/testlog"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc"
+ "github.com/stretchr/testify/assert"
+ "net/http"
"testing"
)
func TestCorsHandler(t *testing.T) {
+ // TODO put this in separate func
srv := newHTTPServer(testlog.Logger(t, log.LvlDebug), rpc.DefaultHTTPTimeouts)
-
+ assert.NoError(t, srv.enableRPC(nil, httpConfig{
+ CorsAllowedOrigins: []string{"test", "test.com"},
+ }))
+ assert.NoError(t, srv.setListenAddr("localhost", 0))
+ assert.NoError(t, srv.start())
+ defer srv.stop()
+
+ resp := testRequest(t, "test.com", srv)
+ if resp.Header.Get("Access-Control-Allow-Origin") != "test.com" {
+ t.Fatalf("cors not recognized")
+ }
+ resp2 := testRequest(t, "bad", srv)
+ if resp2.Header.Get("Access-Control-Allow-Origin") != ""{
+ t.Fatalf("cors not properly set, bad cors recognized")
+ }
+}
+
+func testRequest(t *testing.T, origin string, srv *httpServer) *http.Response {
+ t.Helper()
+
+ body := bytes.NewReader([]byte(`{"jsonrpc":"2.0","id":1,method":"rpc_modules"}`))
+ req, _ := http.NewRequest("POST", "http://" + srv.listenAddr(), body)
+ req.Header.Set("content-type", "application/json")
+ req.Header.Set("origin", origin)
+
+ client := http.DefaultClient
+ resp, err := client.Do(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ return resp
+}
+
+func TestVhosts(t *testing.T) {
+ // TODO
+}
+
+func TestWebsocketOrigins(t *testing.T) {
+ // TODO
}
From 68cc90c5ecd3ac17693cba2483f0d7c5ddb7d9e1 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Tue, 28 Jul 2020 18:19:16 +0200
Subject: [PATCH 148/160] linted and new tests
---
go.mod | 5 ++-
go.sum | 6 +++
graphql/service.go | 2 +-
node/node_test.go | 4 +-
node/rpcstack_test.go | 95 ++++++++++++++++++++++++++++++-------------
5 files changed, 79 insertions(+), 33 deletions(-)
diff --git a/go.mod b/go.mod
index 9d418a2d58f9..f2cba91c9765 100644
--- a/go.mod
+++ b/go.mod
@@ -44,6 +44,8 @@ require (
github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222
github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7
github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150
+ github.com/reiver/go-oi v1.0.0
+ github.com/reiver/go-telnet v0.0.0-20180421082511-9ff0b2ab096e
github.com/rjeczalik/notify v0.9.1
github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00
github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521 // indirect
@@ -51,12 +53,13 @@ require (
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4
github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 // indirect
+ github.com/streadway/amqp v1.0.0
github.com/stretchr/testify v1.4.0
github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d
github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef
github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899
- golang.org/x/net v0.0.0-20200625001655-4c5254603344 // indirect
+ golang.org/x/net v0.0.0-20200625001655-4c5254603344
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c
golang.org/x/text v0.3.2
diff --git a/go.sum b/go.sum
index f00dcfaad8d7..39f6419b99a1 100644
--- a/go.sum
+++ b/go.sum
@@ -244,6 +244,10 @@ github.com/prometheus/procfs v0.0.10/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+G
github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150 h1:ZeU+auZj1iNzN8iVhff6M38Mfu73FQiJve/GEXYJBjE=
github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
+github.com/reiver/go-oi v1.0.0 h1:nvECWD7LF+vOs8leNGV/ww+F2iZKf3EYjYZ527turzM=
+github.com/reiver/go-oi v1.0.0/go.mod h1:RrDBct90BAhoDTxB1fenZwfykqeGvhI6LsNfStJoEkI=
+github.com/reiver/go-telnet v0.0.0-20180421082511-9ff0b2ab096e h1:quuzZLi72kkJjl+f5AQ93FMcadG19WkS7MO6TXFOSas=
+github.com/reiver/go-telnet v0.0.0-20180421082511-9ff0b2ab096e/go.mod h1:+5vNVvEWwEIx86DB9Ke/+a5wBI464eDRo3eF0LcfpWg=
github.com/rjeczalik/notify v0.9.1 h1:CLCKso/QK1snAlnhNR/CNvNiFU2saUtjV0bx3EwNeCE=
github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho=
github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00 h1:8DPul/X0IT/1TNMIxoKLwdemEOBBHDC/K4EB16Cw5WE=
@@ -264,6 +268,8 @@ github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570 h1:gIlAHnH1
github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw=
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 h1:njlZPzLwU639dk2kqnCPPv+wNjq7Xb6EfUxe/oX0/NM=
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU=
+github.com/streadway/amqp v1.0.0 h1:kuuDrUJFZL1QYL9hUNuCxNObNzB0bV/ZG5jV3RWAQgo=
+github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
diff --git a/graphql/service.go b/graphql/service.go
index fb573a8d78c9..60aeca37e38b 100644
--- a/graphql/service.go
+++ b/graphql/service.go
@@ -45,7 +45,7 @@ func newHandler(stack *node.Node, backend ethapi.Backend, cors, vhosts []string)
handler := node.NewHTTPHandlerStack(h, cors, vhosts)
stack.RegisterPath("GraphQL UI", "/graphql/ui", GraphiQL{})
- stack.RegisterPath( "GraphQL", "/graphql", handler)
+ stack.RegisterPath("GraphQL", "/graphql", handler)
stack.RegisterPath("GraphQL", "/graphql/", handler)
return nil
diff --git a/node/node_test.go b/node/node_test.go
index c78f5e7b063b..92575fb76c20 100644
--- a/node/node_test.go
+++ b/node/node_test.go
@@ -441,7 +441,7 @@ func TestWebsocketHTTPOnSamePort_WebsocketRequest(t *testing.T) {
node := startHTTP(t, 0, 0)
defer node.Close()
- ws := strings.Replace(node.HTTPEndpoint() , "http://", "ws://", 1)
+ ws := strings.Replace(node.HTTPEndpoint(), "http://", "ws://", 1)
if node.WSEndpoint() != ws {
t.Fatalf("endpoints should be the same")
@@ -466,7 +466,7 @@ func TestWebsocketHTTPOnSeparatePort_WSRequest(t *testing.T) {
node := startHTTP(t, 0, port)
defer node.Close()
- wsOnHTTP := strings.Replace(node.HTTPEndpoint() , "http://", "ws://", 1)
+ wsOnHTTP := strings.Replace(node.HTTPEndpoint(), "http://", "ws://", 1)
ws := fmt.Sprintf("ws://127.0.0.1:%d", port)
if node.WSEndpoint() == wsOnHTTP {
diff --git a/node/rpcstack_test.go b/node/rpcstack_test.go
index 9b4af6135e29..ad0deea82b8b 100644
--- a/node/rpcstack_test.go
+++ b/node/rpcstack_test.go
@@ -18,57 +18,94 @@ package node
import (
"bytes"
+ "net/http"
+ "testing"
+
"github.com/ethereum/go-ethereum/internal/testlog"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc"
+
+ "github.com/gorilla/websocket"
"github.com/stretchr/testify/assert"
- "net/http"
- "testing"
)
+// TestCorsHandler makes sure CORS are properly handled on the http server.
func TestCorsHandler(t *testing.T) {
- // TODO put this in separate func
+ srv := createAndStartServer(t, httpConfig{CorsAllowedOrigins: []string{"test", "test.com"}}, false, wsConfig{})
+ defer srv.stop()
+
+ resp := testRequest(t, "origin", "test.com", "", srv)
+ assert.Equal(t, "test.com", resp.Header.Get("Access-Control-Allow-Origin"))
+
+ resp2 := testRequest(t, "origin", "bad", "", srv)
+ assert.Equal(t, "", resp2.Header.Get("Access-Control-Allow-Origin"))
+}
+
+// TestVhosts makes sure vhosts are properly handled on the http server.
+func TestVhosts(t *testing.T) {
+ srv := createAndStartServer(t, httpConfig{Vhosts: []string{"test"}}, false, wsConfig{})
+ defer srv.stop()
+
+ resp := testRequest(t, "", "", "test", srv)
+ assert.Equal(t, resp.StatusCode, http.StatusOK)
+
+ resp2 := testRequest(t, "", "", "bad", srv)
+ assert.Equal(t, resp2.StatusCode, http.StatusForbidden)
+}
+
+// TestWebsocketOrigins makes sure the websocket origins are properly handled on the websocket server.
+func TestWebsocketOrigins(t *testing.T) {
+ srv := createAndStartServer(t, httpConfig{}, true, wsConfig{Origins: []string{"test"}})
+ defer srv.stop()
+
+ dialer := websocket.DefaultDialer
+ _, _, err := dialer.Dial("ws://"+srv.listenAddr(), http.Header{
+ "Content-type": []string{"application/json"},
+ "Sec-WebSocket-Version": []string{"13"},
+ "Origin": []string{"test"},
+ })
+ assert.NoError(t, err)
+
+ _, _, err = dialer.Dial("ws://"+srv.listenAddr(), http.Header{
+ "Content-type": []string{"application/json"},
+ "Sec-WebSocket-Version": []string{"13"},
+ "Origin": []string{"bad"},
+ })
+ assert.Error(t, err)
+}
+
+func createAndStartServer(t *testing.T, conf httpConfig, ws bool, wsConf wsConfig) *httpServer {
+ t.Helper()
+
srv := newHTTPServer(testlog.Logger(t, log.LvlDebug), rpc.DefaultHTTPTimeouts)
- assert.NoError(t, srv.enableRPC(nil, httpConfig{
- CorsAllowedOrigins: []string{"test", "test.com"},
- }))
+
+ assert.NoError(t, srv.enableRPC(nil, conf))
+ if ws {
+ assert.NoError(t, srv.enableWS(nil, wsConf))
+ }
assert.NoError(t, srv.setListenAddr("localhost", 0))
assert.NoError(t, srv.start())
- defer srv.stop()
- resp := testRequest(t, "test.com", srv)
- if resp.Header.Get("Access-Control-Allow-Origin") != "test.com" {
- t.Fatalf("cors not recognized")
- }
- resp2 := testRequest(t, "bad", srv)
- if resp2.Header.Get("Access-Control-Allow-Origin") != ""{
- t.Fatalf("cors not properly set, bad cors recognized")
- }
+ return srv
}
-func testRequest(t *testing.T, origin string, srv *httpServer) *http.Response {
+func testRequest(t *testing.T, key, value, host string, srv *httpServer) *http.Response {
t.Helper()
body := bytes.NewReader([]byte(`{"jsonrpc":"2.0","id":1,method":"rpc_modules"}`))
- req, _ := http.NewRequest("POST", "http://" + srv.listenAddr(), body)
+ req, _ := http.NewRequest("POST", "http://"+srv.listenAddr(), body)
req.Header.Set("content-type", "application/json")
- req.Header.Set("origin", origin)
+ if key != "" && value != "" {
+ req.Header.Set(key, value)
+ }
+ if host != "" {
+ req.Host = host
+ }
client := http.DefaultClient
resp, err := client.Do(req)
if err != nil {
t.Fatal(err)
}
-
return resp
}
-
-func TestVhosts(t *testing.T) {
- // TODO
-}
-
-func TestWebsocketOrigins(t *testing.T) {
- // TODO
-}
-
-
From 917135fc01c7630dc782ec745440d8ea0e549b91 Mon Sep 17 00:00:00 2001
From: renaynay <41963722+renaynay@users.noreply.github.com>
Date: Tue, 28 Jul 2020 18:24:11 +0200
Subject: [PATCH 149/160] reshuffling some funcs in rpcstack
---
node/rpcstack.go | 234 +++++++++++++++++++++++------------------------
1 file changed, 117 insertions(+), 117 deletions(-)
diff --git a/node/rpcstack.go b/node/rpcstack.go
index 6a572beabf9e..0f4529c4a4bc 100644
--- a/node/rpcstack.go
+++ b/node/rpcstack.go
@@ -33,28 +33,6 @@ import (
"github.com/rs/cors"
)
-// RegisterApisFromWhitelist checks the given modules' availability, generates a whitelist based on the allowed modules,
-// and then registers all of the APIs exposed by the services.
-func RegisterApisFromWhitelist(apis []rpc.API, modules []string, srv *rpc.Server, exposeAll bool) error {
- if bad, available := checkModuleAvailability(modules, apis); len(bad) > 0 {
- log.Error("Unavailable modules in HTTP API list", "unavailable", bad, "available", available)
- }
- // Generate the whitelist based on the allowed modules
- whitelist := make(map[string]bool)
- for _, module := range modules {
- whitelist[module] = true
- }
- // Register all the APIs exposed by the services
- for _, api := range apis {
- if exposeAll || whitelist[api.Namespace] || (len(whitelist) == 0 && api.Public) {
- if err := srv.RegisterName(api.Namespace, api.Service); err != nil {
- return err
- }
- }
- }
- return nil
-}
-
// httpConfig is the JSON-RPC/HTTP configuration.
type httpConfig struct {
Modules []string
@@ -68,6 +46,11 @@ type wsConfig struct {
Modules []string
}
+type rpcHandler struct {
+ http.Handler
+ server *rpc.Server
+}
+
type httpServer struct {
log log.Logger
timeouts rpc.HTTPTimeouts
@@ -93,11 +76,6 @@ type httpServer struct {
handlerNames map[string]string
}
-type rpcHandler struct {
- http.Handler
- server *rpc.Server
-}
-
func newHTTPServer(log log.Logger, timeouts rpc.HTTPTimeouts) *httpServer {
h := &httpServer{log: log, timeouts: timeouts, handlerNames: make(map[string]string)}
h.httpHandler.Store((*rpcHandler)(nil))
@@ -131,73 +109,6 @@ func (h *httpServer) listenAddr() string {
return h.endpoint
}
-// enableRPC turns on JSON-RPC over HTTP on the server.
-func (h *httpServer) enableRPC(apis []rpc.API, config httpConfig) error {
- h.mu.Lock()
- defer h.mu.Unlock()
-
- if h.rpcAllowed() {
- return fmt.Errorf("JSON-RPC over HTTP is already enabled")
- }
-
- // Create RPC server and handler.
- srv := rpc.NewServer()
- if err := RegisterApisFromWhitelist(apis, config.Modules, srv, false); err != nil {
- return err
- }
- h.httpConfig = config
- h.httpHandler.Store(&rpcHandler{
- Handler: NewHTTPHandlerStack(srv, config.CorsAllowedOrigins, config.Vhosts),
- server: srv,
- })
- return nil
-}
-
-// disableRPC stops the HTTP RPC handler. The caller must hold h.mu.
-func (h *httpServer) disableRPC() bool {
- handler := h.httpHandler.Load().(*rpcHandler)
- if handler != nil {
- h.httpHandler.Store((*rpcHandler)(nil))
- handler.server.Stop()
- }
- return handler != nil
-}
-
-// enableWS turns on JSON-RPC over WebSocket on the server.
-func (h *httpServer) enableWS(apis []rpc.API, config wsConfig) error {
- h.mu.Lock()
- defer h.mu.Unlock()
-
- if h.wsAllowed() {
- return fmt.Errorf("JSON-RPC over WebSocket is already enabled")
- }
-
- // Create RPC server and handler.
- srv := rpc.NewServer()
- if err := RegisterApisFromWhitelist(apis, config.Modules, srv, false); err != nil {
- return err
- }
- h.wsConfig = config
- h.wsHandler.Store(&rpcHandler{
- Handler: srv.WebsocketHandler(config.Origins),
- server: srv,
- })
- return nil
-}
-
-// stopWS disables JSON-RPC over WebSocket.
-func (h *httpServer) stopWS() {
- h.mu.Lock()
- defer h.mu.Unlock()
-
- if h.disableWS() {
- // If this server only served WebSocket, stop the HTTP server as well.
- if !h.rpcAllowed() {
- h.doStop()
- }
- }
-}
-
// disableWS stops the WebSocket handler. The caller must hold h.mu.
func (h *httpServer) disableWS() bool {
ws := h.wsHandler.Load().(*rpcHandler)
@@ -257,6 +168,29 @@ func (h *httpServer) start() error {
return nil
}
+func (h *httpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ rpc := h.httpHandler.Load().(*rpcHandler)
+ if r.RequestURI == "/" {
+ // Serve JSON-RPC on the root path.
+ ws := h.wsHandler.Load().(*rpcHandler)
+ if ws != nil && isWebsocket(r) {
+ ws.ServeHTTP(w, r)
+ return
+ }
+ if rpc != nil {
+ rpc.ServeHTTP(w, r)
+ return
+ }
+ } else if rpc != nil {
+ // Requests to a path below root are handled by the mux,
+ // which has all the handlers registered via Node.RegisterPath.
+ // These are made available when RPC is enabled.
+ h.mux.ServeHTTP(w, r)
+ return
+ }
+ w.WriteHeader(404)
+}
+
// stop shuts down the HTTP server.
func (h *httpServer) stop() {
h.mu.Lock()
@@ -289,6 +223,73 @@ func (h *httpServer) doStop() {
h.server, h.listener = nil, nil
}
+// enableRPC turns on JSON-RPC over HTTP on the server.
+func (h *httpServer) enableRPC(apis []rpc.API, config httpConfig) error {
+ h.mu.Lock()
+ defer h.mu.Unlock()
+
+ if h.rpcAllowed() {
+ return fmt.Errorf("JSON-RPC over HTTP is already enabled")
+ }
+
+ // Create RPC server and handler.
+ srv := rpc.NewServer()
+ if err := RegisterApisFromWhitelist(apis, config.Modules, srv, false); err != nil {
+ return err
+ }
+ h.httpConfig = config
+ h.httpHandler.Store(&rpcHandler{
+ Handler: NewHTTPHandlerStack(srv, config.CorsAllowedOrigins, config.Vhosts),
+ server: srv,
+ })
+ return nil
+}
+
+// disableRPC stops the HTTP RPC handler. The caller must hold h.mu.
+func (h *httpServer) disableRPC() bool {
+ handler := h.httpHandler.Load().(*rpcHandler)
+ if handler != nil {
+ h.httpHandler.Store((*rpcHandler)(nil))
+ handler.server.Stop()
+ }
+ return handler != nil
+}
+
+// enableWS turns on JSON-RPC over WebSocket on the server.
+func (h *httpServer) enableWS(apis []rpc.API, config wsConfig) error {
+ h.mu.Lock()
+ defer h.mu.Unlock()
+
+ if h.wsAllowed() {
+ return fmt.Errorf("JSON-RPC over WebSocket is already enabled")
+ }
+
+ // Create RPC server and handler.
+ srv := rpc.NewServer()
+ if err := RegisterApisFromWhitelist(apis, config.Modules, srv, false); err != nil {
+ return err
+ }
+ h.wsConfig = config
+ h.wsHandler.Store(&rpcHandler{
+ Handler: srv.WebsocketHandler(config.Origins),
+ server: srv,
+ })
+ return nil
+}
+
+// stopWS disables JSON-RPC over WebSocket.
+func (h *httpServer) stopWS() {
+ h.mu.Lock()
+ defer h.mu.Unlock()
+
+ if h.disableWS() {
+ // If this server only served WebSocket, stop the HTTP server as well.
+ if !h.rpcAllowed() {
+ h.doStop()
+ }
+ }
+}
+
// rpcAllowed returns true when JSON-RPC over HTTP is enabled.
func (h *httpServer) rpcAllowed() bool {
return h.httpHandler.Load().(*rpcHandler) != nil
@@ -299,29 +300,6 @@ func (h *httpServer) wsAllowed() bool {
return h.wsHandler.Load().(*rpcHandler) != nil
}
-func (h *httpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
- rpc := h.httpHandler.Load().(*rpcHandler)
- if r.RequestURI == "/" {
- // Serve JSON-RPC on the root path.
- ws := h.wsHandler.Load().(*rpcHandler)
- if ws != nil && isWebsocket(r) {
- ws.ServeHTTP(w, r)
- return
- }
- if rpc != nil {
- rpc.ServeHTTP(w, r)
- return
- }
- } else if rpc != nil {
- // Requests to a path below root are handled by the mux,
- // which has all the handlers registered via Node.RegisterPath.
- // These are made available when RPC is enabled.
- h.mux.ServeHTTP(w, r)
- return
- }
- w.WriteHeader(404)
-}
-
// isWebsocket checks the header of an http request for a websocket upgrade request.
func isWebsocket(r *http.Request) bool {
return strings.ToLower(r.Header.Get("Upgrade")) == "websocket" &&
@@ -481,3 +459,25 @@ func (is *ipcServer) stop() error {
is.log.Info("IPC endpoint closed", "url", is.endpoint)
return err
}
+
+// RegisterApisFromWhitelist checks the given modules' availability, generates a whitelist based on the allowed modules,
+// and then registers all of the APIs exposed by the services.
+func RegisterApisFromWhitelist(apis []rpc.API, modules []string, srv *rpc.Server, exposeAll bool) error {
+ if bad, available := checkModuleAvailability(modules, apis); len(bad) > 0 {
+ log.Error("Unavailable modules in HTTP API list", "unavailable", bad, "available", available)
+ }
+ // Generate the whitelist based on the allowed modules
+ whitelist := make(map[string]bool)
+ for _, module := range modules {
+ whitelist[module] = true
+ }
+ // Register all the APIs exposed by the services
+ for _, api := range apis {
+ if exposeAll || whitelist[api.Namespace] || (len(whitelist) == 0 && api.Public) {
+ if err := srv.RegisterName(api.Namespace, api.Service); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
From 3664dd5efce06c1cd5e9e4995079d899860e914f Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Mon, 3 Aug 2020 11:39:03 +0200
Subject: [PATCH 150/160] node: move disableWS down as well
---
node/rpcstack.go | 23 +++++++++++------------
1 file changed, 11 insertions(+), 12 deletions(-)
diff --git a/node/rpcstack.go b/node/rpcstack.go
index 0f4529c4a4bc..b47ddc871b23 100644
--- a/node/rpcstack.go
+++ b/node/rpcstack.go
@@ -109,16 +109,6 @@ func (h *httpServer) listenAddr() string {
return h.endpoint
}
-// disableWS stops the WebSocket handler. The caller must hold h.mu.
-func (h *httpServer) disableWS() bool {
- ws := h.wsHandler.Load().(*rpcHandler)
- if ws != nil {
- h.wsHandler.Store((*rpcHandler)(nil))
- ws.server.Stop()
- }
- return ws != nil
-}
-
// start starts the HTTP server if it is enabled and not already running.
func (h *httpServer) start() error {
h.mu.Lock()
@@ -277,13 +267,22 @@ func (h *httpServer) enableWS(apis []rpc.API, config wsConfig) error {
return nil
}
-// stopWS disables JSON-RPC over WebSocket.
+// disableWS stops the WebSocket handler. The caller must hold h.mu.
+func (h *httpServer) disableWS() bool {
+ ws := h.wsHandler.Load().(*rpcHandler)
+ if ws != nil {
+ h.wsHandler.Store((*rpcHandler)(nil))
+ ws.server.Stop()
+ }
+ return ws != nil
+}
+
+// stopWS disables JSON-RPC over WebSocket and also stops the server if it only serves WebSocket.
func (h *httpServer) stopWS() {
h.mu.Lock()
defer h.mu.Unlock()
if h.disableWS() {
- // If this server only served WebSocket, stop the HTTP server as well.
if !h.rpcAllowed() {
h.doStop()
}
From de11bb1a4ca5866e5726add24221d23cf172b4e5 Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Mon, 3 Aug 2020 11:41:00 +0200
Subject: [PATCH 151/160] node: improve comments
---
node/rpcstack.go | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/node/rpcstack.go b/node/rpcstack.go
index b47ddc871b23..80a91e4bd7e8 100644
--- a/node/rpcstack.go
+++ b/node/rpcstack.go
@@ -235,7 +235,7 @@ func (h *httpServer) enableRPC(apis []rpc.API, config httpConfig) error {
return nil
}
-// disableRPC stops the HTTP RPC handler. The caller must hold h.mu.
+// disableRPC stops the HTTP RPC handler. This is internal, the caller must hold h.mu.
func (h *httpServer) disableRPC() bool {
handler := h.httpHandler.Load().(*rpcHandler)
if handler != nil {
@@ -267,16 +267,6 @@ func (h *httpServer) enableWS(apis []rpc.API, config wsConfig) error {
return nil
}
-// disableWS stops the WebSocket handler. The caller must hold h.mu.
-func (h *httpServer) disableWS() bool {
- ws := h.wsHandler.Load().(*rpcHandler)
- if ws != nil {
- h.wsHandler.Store((*rpcHandler)(nil))
- ws.server.Stop()
- }
- return ws != nil
-}
-
// stopWS disables JSON-RPC over WebSocket and also stops the server if it only serves WebSocket.
func (h *httpServer) stopWS() {
h.mu.Lock()
@@ -289,6 +279,16 @@ func (h *httpServer) stopWS() {
}
}
+// disableWS disables the WebSocket handler. This is internal, the caller must hold h.mu.
+func (h *httpServer) disableWS() bool {
+ ws := h.wsHandler.Load().(*rpcHandler)
+ if ws != nil {
+ h.wsHandler.Store((*rpcHandler)(nil))
+ ws.server.Stop()
+ }
+ return ws != nil
+}
+
// rpcAllowed returns true when JSON-RPC over HTTP is enabled.
func (h *httpServer) rpcAllowed() bool {
return h.httpHandler.Load().(*rpcHandler) != nil
From 98cf053b77f707ee7a5ee7cb2ebd40c1e8b95d23 Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Mon, 3 Aug 2020 11:50:39 +0200
Subject: [PATCH 152/160] go.mod: revert dependency updates
---
go.mod | 32 ++++-----
go.sum | 202 +++++----------------------------------------------------
2 files changed, 33 insertions(+), 201 deletions(-)
diff --git a/go.mod b/go.mod
index f2cba91c9765..2299eb501753 100644
--- a/go.mod
+++ b/go.mod
@@ -6,11 +6,11 @@ require (
github.com/Azure/azure-pipeline-go v0.2.2 // indirect
github.com/Azure/azure-storage-blob-go v0.7.0
github.com/Azure/go-autorest/autorest/adal v0.8.0 // indirect
- github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect
+ github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect
github.com/VictoriaMetrics/fastcache v1.5.7
- github.com/aristanetworks/goarista v0.0.0-20200609010056-95bcf8053598
+ github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847
github.com/aws/aws-sdk-go v1.25.48
- github.com/btcsuite/btcd v0.20.1-beta
+ github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6
github.com/cespare/cp v0.1.0
github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9
github.com/davecgh/go-spew v1.1.1
@@ -22,11 +22,12 @@ require (
github.com/fatih/color v1.3.0
github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff
- github.com/go-ole/go-ole v1.2.4 // indirect
+ github.com/go-ole/go-ole v1.2.1 // indirect
github.com/go-sourcemap/sourcemap v2.1.2+incompatible // indirect
github.com/go-stack/stack v1.8.0
- github.com/golang/protobuf v1.3.3
- github.com/golang/snappy v0.0.2-0.20190904063534-ff6b7dc882cf
+ github.com/golang/protobuf v1.3.2-0.20190517061210-b285ee9cfc6c
+ github.com/golang/snappy v0.0.2-0.20200707131729-196ae77b8a26
+ github.com/google/go-cmp v0.3.1 // indirect
github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989
github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277
github.com/hashicorp/golang-lru v0.5.4
@@ -34,8 +35,10 @@ require (
github.com/huin/goupnp v1.0.0
github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458
- github.com/julienschmidt/httprouter v1.2.0
+ github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21
github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356
+ github.com/kr/pretty v0.1.0 // indirect
+ github.com/kylelemons/godebug v1.1.0 // indirect
github.com/mattn/go-colorable v0.1.0
github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035
github.com/naoina/go-stringutil v0.1.0 // indirect
@@ -44,26 +47,23 @@ require (
github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222
github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7
github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150
- github.com/reiver/go-oi v1.0.0
- github.com/reiver/go-telnet v0.0.0-20180421082511-9ff0b2ab096e
github.com/rjeczalik/notify v0.9.1
github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00
github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521 // indirect
- github.com/shirou/gopsutil v2.20.6+incompatible
+ github.com/shirou/gopsutil v2.20.5+incompatible
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4
github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 // indirect
- github.com/streadway/amqp v1.0.0
github.com/stretchr/testify v1.4.0
github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d
github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef
github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208
- golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899
- golang.org/x/net v0.0.0-20200625001655-4c5254603344
- golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
- golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c
+ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
+ golang.org/x/net v0.0.0-20200625001655-4c5254603344 // indirect
+ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f
+ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd
golang.org/x/text v0.3.2
- golang.org/x/time v0.0.0-20191024005414-555d28b269f0
+ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6
gopkg.in/urfave/cli.v1 v1.20.0
diff --git a/go.sum b/go.sum
index 39f6419b99a1..4c46eeb5afb0 100644
--- a/go.sum
+++ b/go.sum
@@ -1,4 +1,3 @@
-cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4=
github.com/Azure/azure-pipeline-go v0.2.2 h1:6oiIS9yaG6XCCzhgAgKFfIWyo4LLCiDhZot6ltoThhY=
github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc=
@@ -22,50 +21,30 @@ github.com/Azure/go-autorest/tracing v0.5.0 h1:TRn4WjSnkcSy5AEG3pnbtFSwNtwzjr4VY
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
-github.com/Shopify/sarama v1.26.1/go.mod h1:NbSGBSSndYaIhRcBtY9V0U7AyH+x71bG668AuWys/yU=
-github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
-github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk=
-github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
+github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8=
+github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/VictoriaMetrics/fastcache v1.5.7 h1:4y6y0G8PRzszQUYIQHHssv/jgPHAb5qQuuDNdCbyAgw=
github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8=
-github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
-github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
-github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8=
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
-github.com/aristanetworks/fsnotify v1.4.2/go.mod h1:D/rtu7LpjYM8tRJphJ0hUBYpjai8SfX+aSNsWDTq/Ks=
-github.com/aristanetworks/glog v0.0.0-20191112221043-67e8567f59f3/go.mod h1:KASm+qXFKs/xjSoWn30NrWBBvdTTQq+UjkhjEJHfSFA=
-github.com/aristanetworks/goarista v0.0.0-20200609010056-95bcf8053598 h1:VbwKXgO1O1JSbI8o3PQqlC/KTem5t3YD7LqvfBT+0Gk=
-github.com/aristanetworks/goarista v0.0.0-20200609010056-95bcf8053598/go.mod h1:QZe5Yh80Hp1b6JxQdpfSEEe8X7hTyTEZSosSrFf/oJE=
-github.com/aristanetworks/splunk-hec-go v0.3.3/go.mod h1:1VHO9r17b0K7WmOlLb9nTk/2YanvOEnLMUgsFrxBROc=
+github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847 h1:rtI0fD4oG/8eVokGVPYJEW1F88p1ZNgXiEIs9thEE4A=
+github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ=
github.com/aws/aws-sdk-go v1.25.48 h1:J82DYDGZHOKHdhx6hD24Tm30c2C3GchYGfN0mf9iKUk=
github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
-github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
-github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
-github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw=
-github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
-github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
-github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
-github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
-github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
-github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
-github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
-github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
-github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6 h1:Eey/GGQ/E5Xp1P2Lyx1qj007hLZfbi0+CoVeJruGCtI=
+github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ=
github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk=
github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9 h1:J82+/8rub3qSy0HxEnoYD8cs+HDlHWYrqYXe2Vqxluk=
github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
-github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -80,62 +59,40 @@ github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf h1:sh8rkQZavChcmak
github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/dop251/goja v0.0.0-20200219165308-d1232e640a87 h1:OMbqMXf9OAXzH1dDH82mQMrddBE8LIIwDtxeK4wE1/A=
github.com/dop251/goja v0.0.0-20200219165308-d1232e640a87/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA=
-github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
-github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
-github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c h1:JHHhtb9XWJrGNMcrVP6vyzO4dusgi/HnceHTgxSejUM=
github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
-github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.3.0 h1:YehCCcyeQ6Km0D6+IapqPinWBK6y+0eB5umvZXK9WPs=
github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc h1:jtW8jbpkO4YirRSyepBOH8E+2HEw6/hKkBvFPwhUN8c=
github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
-github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
-github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI=
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
-github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk=
-github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0 h1:8HUsc87TaSWLKwrnumgC8/YconD2fJQsRJAsWaPg2ic=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
-github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA=
-github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
-github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
-github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
+github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E=
+github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
github.com/go-sourcemap/sourcemap v2.1.2+incompatible h1:0b/xya7BKGhXuqFESKM4oIiRo9WOt2ebz7KxfreD6ug=
github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
-github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
-github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.2-0.20190517061210-b285ee9cfc6c h1:zqAKixg3cTcIasAMJV+EcfVbWwLpOZ7LeoWJvcuD/5Q=
+github.com/golang/protobuf v1.3.2-0.20190517061210-b285ee9cfc6c/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/golang/snappy v0.0.2-0.20190904063534-ff6b7dc882cf h1:gFVkHXmVAhEbxZVDln5V9GKrLaluNoFHDbrZwAWZgws=
-github.com/golang/snappy v0.0.2-0.20190904063534-ff6b7dc882cf/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/golang/snappy v0.0.2-0.20200707131729-196ae77b8a26 h1:lMm2hD9Fy0ynom5+85/pbdkiYcBqM1JWmhpAXLmy0fw=
+github.com/golang/snappy v0.0.2-0.20200707131729-196ae77b8a26/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
-github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989 h1:giknQ4mEuDFmmHSrGcbargOuLHQGtywqo4mheITex54=
github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277 h1:E0whKxgp2ojts0FDgUA8dl62bmH0LxKanMoBr6MDTDM=
github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc=
-github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/holiman/uint256 v1.1.1 h1:4JywC80b+/hSfljFlEBLHrrh+CIONLDz9NuFl0af4Mw=
@@ -147,32 +104,18 @@ github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883 h1:FSeK4fZCo8u40n2JMnyAsd6x7+SbvoOMHvQOU/n10P4=
github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=
-github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458 h1:6OvNmYgJyexcZ3pYbTI9jWx5tHo1Dee/tWbLMfPe2TA=
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
-github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
-github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
-github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
-github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
-github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
-github.com/julienschmidt/httprouter v1.2.0 h1:TDTW5Yz1mjftljbcKqRcrYhd4XeOoI98t+9HbQbYf7g=
-github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21 h1:F/iKcka0K2LgnKy/fgSBf235AETtm1n1TvBzqu40LE0=
+github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356 h1:I/yrLt2WilKxlQKCM52clh5rGzTKpVctGT1lH4Dc8Jw=
github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
-github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
-github.com/klauspost/compress v1.9.8/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
-github.com/klauspost/compress v1.10.1/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
-github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
-github.com/klauspost/reedsolomon v1.9.3/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4=
-github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
-github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
@@ -189,11 +132,6 @@ github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
-github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/naoina/go-stringutil v0.1.0 h1:rCUeRUHjBjGTSHl0VC00jUPLz8/F9dDzYI70Hzifhks=
github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=
github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 h1:shk/vn9oCoOTmwcouEdwIeOtOGA/ELRUw/GwvxwfT+0=
@@ -205,49 +143,25 @@ github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c/go.mod h1
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo=
-github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
-github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
-github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
-github.com/openconfig/gnmi v0.0.0-20190823184014-89b2bf29312c/go.mod h1:t+O9It+LKzfOAhKTT5O0ehDix+MTqbtT0T9t+7zzOvc=
-github.com/openconfig/reference v0.0.0-20190727015836-8dfd928c9696/go.mod h1:ym2A+zigScwkSEb/cVQB0/ZMpU3rqiH6X7WRRsxgOGw=
github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222 h1:goeTyGkArOZIVOMA0dQbyuPWGNQJZGPwPu/QS9GlpnA=
github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34=
github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 h1:oYW+YCJ1pachXTQmzR3rNLYGGz4g/UgFcjb28p/viDM=
github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0=
-github.com/pierrec/lz4 v2.4.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
-github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
-github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
-github.com/prometheus/client_golang v1.4.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
-github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
-github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
-github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
-github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
-github.com/prometheus/procfs v0.0.10/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150 h1:ZeU+auZj1iNzN8iVhff6M38Mfu73FQiJve/GEXYJBjE=
github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
-github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
-github.com/reiver/go-oi v1.0.0 h1:nvECWD7LF+vOs8leNGV/ww+F2iZKf3EYjYZ527turzM=
-github.com/reiver/go-oi v1.0.0/go.mod h1:RrDBct90BAhoDTxB1fenZwfykqeGvhI6LsNfStJoEkI=
-github.com/reiver/go-telnet v0.0.0-20180421082511-9ff0b2ab096e h1:quuzZLi72kkJjl+f5AQ93FMcadG19WkS7MO6TXFOSas=
-github.com/reiver/go-telnet v0.0.0-20180421082511-9ff0b2ab096e/go.mod h1:+5vNVvEWwEIx86DB9Ke/+a5wBI464eDRo3eF0LcfpWg=
github.com/rjeczalik/notify v0.9.1 h1:CLCKso/QK1snAlnhNR/CNvNiFU2saUtjV0bx3EwNeCE=
github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho=
github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00 h1:8DPul/X0IT/1TNMIxoKLwdemEOBBHDC/K4EB16Cw5WE=
@@ -255,12 +169,9 @@ github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9Ac
github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521 h1:3hxavr+IHMsQBrYUPQM5v0CgENFktkkbg1sfpgM3h20=
github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
-github.com/shirou/gopsutil v2.20.6+incompatible h1:P37G9YH8M4vqkKcwBosp+URN5O8Tay67D2MbR361ioY=
-github.com/shirou/gopsutil v2.20.6+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
+github.com/shirou/gopsutil v2.20.5+incompatible h1:tYH07UPoQt0OCQdgWWMgYHy3/a9bcxNpBIysykNIP7I=
+github.com/shirou/gopsutil v2.20.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
-github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
-github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 h1:Gb2Tyox57NRNuZ2d3rmvB3pcmbu7O1RS3m8WRx7ilrg=
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=
@@ -268,124 +179,51 @@ github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570 h1:gIlAHnH1
github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw=
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 h1:njlZPzLwU639dk2kqnCPPv+wNjq7Xb6EfUxe/oX0/NM=
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU=
-github.com/streadway/amqp v1.0.0 h1:kuuDrUJFZL1QYL9hUNuCxNObNzB0bV/ZG5jV3RWAQgo=
-github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d h1:gZZadD8H+fF+n9CmNhYL1Y0dJB+kLOmKd7FbPJLeGHs=
github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA=
-github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU=
-github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4=
-github.com/tjfoc/gmsm v1.3.0/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef h1:wHSqTBrZW24CsNJDfeh9Ex6Pm0Rcpc7qrgKBiL44vF4=
github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208 h1:1cngl9mPEoITZG8s8cVcUy5CeIBYhEESkOB7m6Gmkrk=
github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees=
-github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
-github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
-github.com/xtaci/kcp-go v5.4.20+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
-github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE=
-golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 h1:DZhuSZLsGlFL4CmhA8BcRA0mnthyA/nZ00AqCUo7vHg=
-golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
-golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
-golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
-golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200219091948-cb0a6d8edb6c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c h1:UIcGWL6/wpCfyGuJnRFJRurA+yj8RrW7Q6x2YMCXt6c=
-golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
-golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
-golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20200221224223-e1da425f72fd/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
-google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
-google.golang.org/genproto v0.0.0-20200218151345-dad8c97a84f5/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
-google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
-gopkg.in/bsm/ratelimit.v1 v1.0.0-20160220154919-db14e161995a/go.mod h1:KF9sEfUPAXdG8Oev9e99iLGnl2uJMjc5B+4y3O7x610=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
-gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
-gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo=
-gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q=
-gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4=
-gopkg.in/jcmturner/gokrb5.v7 v7.5.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM=
-gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6 h1:a6cXbcDDUkSBlpnkWV1bJ+vv3mOgQEltEJ2rPxroVu0=
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns=
-gopkg.in/redis.v4 v4.2.4/go.mod h1:8KREHdypkCEojGKQcjMqAODMICIVwZAONWq8RowTITA=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0=
@@ -393,11 +231,5 @@ gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHO
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
-gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
-honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
From b265e2ced02803bfa68f16969b5ce47b386346ea Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Mon, 3 Aug 2020 11:52:12 +0200
Subject: [PATCH 153/160] eth: fix compile issue in backend.go
---
eth/backend.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/eth/backend.go b/eth/backend.go
index fa03f547e167..3fd027137c7f 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -162,7 +162,7 @@ func New(stack *node.Node, config *Config) (*Ethereum, error) {
}
cacheConfig = &core.CacheConfig{
TrieCleanLimit: config.TrieCleanCache,
- TrieCleanJournal: ctx.ResolvePath(config.TrieCleanCacheJournal),
+ TrieCleanJournal: stack.ResolvePath(config.TrieCleanCacheJournal),
TrieCleanRejournal: config.TrieCleanCacheRejournal,
TrieCleanNoPrefetch: config.NoPrefetch,
TrieDirtyLimit: config.TrieDirtyCache,
From 1c639bd6d7fa797787c247f7a179fd248ee4039a Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Mon, 3 Aug 2020 12:03:19 +0200
Subject: [PATCH 154/160] node: fix IPC API registration
---
node/node.go | 2 +-
node/rpcstack.go | 5 ++---
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/node/node.go b/node/node.go
index edb161a4c7a9..400589b35ad3 100644
--- a/node/node.go
+++ b/node/node.go
@@ -332,7 +332,7 @@ func (n *Node) startRPC() error {
// Configure IPC.
if n.ipc.endpoint != "" {
- if err := n.ipc.start(); err != nil {
+ if err := n.ipc.start(n.rpcAPIs); err != nil {
return err
}
}
diff --git a/node/rpcstack.go b/node/rpcstack.go
index 80a91e4bd7e8..554421d87aed 100644
--- a/node/rpcstack.go
+++ b/node/rpcstack.go
@@ -421,7 +421,6 @@ type ipcServer struct {
mu sync.Mutex
listener net.Listener
srv *rpc.Server
- apis []rpc.API
}
func newIPCServer(log log.Logger, endpoint string) *ipcServer {
@@ -429,14 +428,14 @@ func newIPCServer(log log.Logger, endpoint string) *ipcServer {
}
// Start starts the httpServer's http.Server
-func (is *ipcServer) start() error {
+func (is *ipcServer) start(apis []rpc.API) error {
is.mu.Lock()
defer is.mu.Unlock()
if is.listener != nil {
return nil // already running
}
- listener, srv, err := rpc.StartIPCEndpoint(is.endpoint, is.apis)
+ listener, srv, err := rpc.StartIPCEndpoint(is.endpoint, apis)
if err != nil {
return err
}
From e11bc43a10b1b5d3c2fa2e8466b8c492b22aea8a Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Mon, 3 Aug 2020 12:07:26 +0200
Subject: [PATCH 155/160] graphql: fix test
---
graphql/graphql_test.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go
index 091102889144..5ba9c955375d 100644
--- a/graphql/graphql_test.go
+++ b/graphql/graphql_test.go
@@ -86,8 +86,8 @@ func TestGraphQLHTTPOnSamePort_GQLRequest_Unsuccessful(t *testing.T) {
t.Fatalf("could not read from response body: %v", err)
}
// make sure the request is not handled successfully
- expected := "{\"jsonrpc\":\"2.0\",\"id\":null,\"error\":{\"code\":-32600,\"message\":\"invalid request\"}}\n"
- assert.Equal(t, string(bodyBytes), expected)
+ assert.Equal(t, 404, resp.StatusCode)
+ assert.Equal(t, "404 page not found\n", string(bodyBytes))
}
func createNode(t *testing.T, gqlEnabled bool) *node.Node {
From f1b1b333a07dd79db4f4d7e61e93eb8bf4c42721 Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Mon, 3 Aug 2020 12:21:33 +0200
Subject: [PATCH 156/160] node: remove blank line
---
node/rpcstack_test.go | 1 -
1 file changed, 1 deletion(-)
diff --git a/node/rpcstack_test.go b/node/rpcstack_test.go
index ad0deea82b8b..efab5b37dc5a 100644
--- a/node/rpcstack_test.go
+++ b/node/rpcstack_test.go
@@ -24,7 +24,6 @@ import (
"github.com/ethereum/go-ethereum/internal/testlog"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc"
-
"github.com/gorilla/websocket"
"github.com/stretchr/testify/assert"
)
From 3001cf53f87989c2562d26c3b32059c49371cab4 Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Mon, 3 Aug 2020 12:39:41 +0200
Subject: [PATCH 157/160] node: sort+dedup logged HTTP handlers
---
node/node.go | 1 -
node/rpcstack.go | 19 +++++++++++++++----
2 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/node/node.go b/node/node.go
index 400589b35ad3..63d32adff44c 100644
--- a/node/node.go
+++ b/node/node.go
@@ -452,7 +452,6 @@ func (n *Node) RegisterPath(name, path string, handler http.Handler) {
panic("can't register HTTP handler on running/stopped node")
}
n.http.mux.Handle(path, handler)
-
n.http.handlerNames[path] = name
}
diff --git a/node/rpcstack.go b/node/rpcstack.go
index 554421d87aed..1a6f2666c657 100644
--- a/node/rpcstack.go
+++ b/node/rpcstack.go
@@ -24,6 +24,7 @@ import (
"io/ioutil"
"net"
"net/http"
+ "sort"
"strings"
"sync"
"sync/atomic"
@@ -150,11 +151,21 @@ func (h *httpServer) start() error {
"cors", strings.Join(h.httpConfig.CorsAllowedOrigins, ","),
"vhosts", strings.Join(h.httpConfig.Vhosts, ","),
)
+
// Log all handlers mounted on server.
- for path, name := range h.handlerNames {
- log.Info(name+" enabled", "url", "http://"+listener.Addr().String()+path)
+ var paths []string
+ for path, _ := range h.handlerNames {
+ paths = append(paths, path)
+ }
+ sort.Strings(paths)
+ logged := make(map[string]bool, len(paths))
+ for _, path := range paths {
+ name := h.handlerNames[path]
+ if !logged[name] {
+ log.Info(name+" enabled", "url", "http://"+listener.Addr().String()+path)
+ logged[name] = true
+ }
}
-
return nil
}
@@ -321,8 +332,8 @@ func newCorsHandler(srv http.Handler, allowedOrigins []string) http.Handler {
c := cors.New(cors.Options{
AllowedOrigins: allowedOrigins,
AllowedMethods: []string{http.MethodPost, http.MethodGet},
- MaxAge: 600,
AllowedHeaders: []string{"*"},
+ MaxAge: 600,
})
return c.Handler(srv)
}
From 4d42e9f043e000e5e65d8dba4da359820c849813 Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Mon, 3 Aug 2020 14:09:43 +0200
Subject: [PATCH 158/160] node: fix lint issue
---
node/rpcstack.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/node/rpcstack.go b/node/rpcstack.go
index 1a6f2666c657..047de65dca55 100644
--- a/node/rpcstack.go
+++ b/node/rpcstack.go
@@ -154,7 +154,7 @@ func (h *httpServer) start() error {
// Log all handlers mounted on server.
var paths []string
- for path, _ := range h.handlerNames {
+ for path := range h.handlerNames {
paths = append(paths, path)
}
sort.Strings(paths)
From 2b5bd5ee2759b7b286c0f935982e8d078a68e8ed Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Mon, 3 Aug 2020 15:01:42 +0200
Subject: [PATCH 159/160] node: rename RegisterPath -> RegisterHandler
I'm not happy with 'path' for this because we also have ResolvePath
to find file paths in the datadir.
---
graphql/service.go | 6 +++---
node/api_test.go | 6 +++---
node/node.go | 4 ++--
node/node_test.go | 8 ++++----
node/rpcstack.go | 2 +-
5 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/graphql/service.go b/graphql/service.go
index 60aeca37e38b..ae962e5b365a 100644
--- a/graphql/service.go
+++ b/graphql/service.go
@@ -44,9 +44,9 @@ func newHandler(stack *node.Node, backend ethapi.Backend, cors, vhosts []string)
h := &relay.Handler{Schema: s}
handler := node.NewHTTPHandlerStack(h, cors, vhosts)
- stack.RegisterPath("GraphQL UI", "/graphql/ui", GraphiQL{})
- stack.RegisterPath("GraphQL", "/graphql", handler)
- stack.RegisterPath("GraphQL", "/graphql/", handler)
+ stack.RegisterHandler("GraphQL UI", "/graphql/ui", GraphiQL{})
+ stack.RegisterHandler("GraphQL", "/graphql", handler)
+ stack.RegisterHandler("GraphQL", "/graphql/", handler)
return nil
}
diff --git a/node/api_test.go b/node/api_test.go
index a576b2387557..e4c08962c3a3 100644
--- a/node/api_test.go
+++ b/node/api_test.go
@@ -39,7 +39,7 @@ func TestStartRPC(t *testing.T) {
// Checks. These run after the node is configured and all API calls have been made.
wantReachable bool // whether the HTTP server should be reachable at all
- wantHandlers bool // whether RegisterPath handlers should be accessible
+ wantHandlers bool // whether RegisterHandler handlers should be accessible
wantRPC bool // whether JSON-RPC/HTTP should be accessible
wantWS bool // whether JSON-RPC/WS should be accessible
}
@@ -259,7 +259,7 @@ func TestStartRPC(t *testing.T) {
defer stack.Close()
// Register the test handler.
- stack.RegisterPath("test", "/test", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ stack.RegisterHandler("test", "/test", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("OK"))
}))
@@ -282,7 +282,7 @@ func TestStartRPC(t *testing.T) {
t.Errorf("HTTP server is %sreachable, want it %sreachable", not(reachable), not(test.wantReachable))
}
if handlersAvailable != test.wantHandlers {
- t.Errorf("RegisterPath handlers %savailable, want them %savailable", not(handlersAvailable), not(test.wantHandlers))
+ t.Errorf("RegisterHandler handlers %savailable, want them %savailable", not(handlersAvailable), not(test.wantHandlers))
}
if rpcAvailable != test.wantRPC {
t.Errorf("HTTP RPC %savailable, want it %savailable", not(rpcAvailable), not(test.wantRPC))
diff --git a/node/node.go b/node/node.go
index 63d32adff44c..7ab2520b1b8b 100644
--- a/node/node.go
+++ b/node/node.go
@@ -443,8 +443,8 @@ func (n *Node) RegisterAPIs(apis []rpc.API) {
n.rpcAPIs = append(n.rpcAPIs, apis...)
}
-// RegisterPath mounts the given handler on the given path on the canonical HTTP server.
-func (n *Node) RegisterPath(name, path string, handler http.Handler) {
+// RegisterHandler mounts a handler on the given path on the canonical HTTP server.
+func (n *Node) RegisterHandler(name, path string, handler http.Handler) {
n.lock.Lock()
defer n.lock.Unlock()
diff --git a/node/node_test.go b/node/node_test.go
index 92575fb76c20..8f306ef0219d 100644
--- a/node/node_test.go
+++ b/node/node_test.go
@@ -391,14 +391,14 @@ func TestLifecycleTerminationGuarantee(t *testing.T) {
// Tests whether a handler can be successfully mounted on the canonical HTTP server
// on the given path
-func TestRegisterPath_Successful(t *testing.T) {
+func TestRegisterHandler_Successful(t *testing.T) {
node := createNode(t, 7878, 7979)
// create and mount handler
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("success"))
})
- node.RegisterPath("test", "/test", handler)
+ node.RegisterHandler("test", "/test", handler)
// start node
if err := node.Start(); err != nil {
@@ -423,7 +423,7 @@ func TestRegisterPath_Successful(t *testing.T) {
// Tests that the given handler will not be successfully mounted since no HTTP server
// is enabled for RPC
-func TestRegisterPath_Unsuccessful(t *testing.T) {
+func TestRegisterHandler_Unsuccessful(t *testing.T) {
node, err := New(&DefaultConfig)
if err != nil {
t.Fatalf("could not create new node: %v", err)
@@ -433,7 +433,7 @@ func TestRegisterPath_Unsuccessful(t *testing.T) {
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("success"))
})
- node.RegisterPath("test", "/test", handler)
+ node.RegisterHandler("test", "/test", handler)
}
// Tests whether websocket requests can be handled on the same port as a regular http server.
diff --git a/node/rpcstack.go b/node/rpcstack.go
index 047de65dca55..caf7e5b7a83d 100644
--- a/node/rpcstack.go
+++ b/node/rpcstack.go
@@ -184,7 +184,7 @@ func (h *httpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
} else if rpc != nil {
// Requests to a path below root are handled by the mux,
- // which has all the handlers registered via Node.RegisterPath.
+ // which has all the handlers registered via Node.RegisterHandler.
// These are made available when RPC is enabled.
h.mux.ServeHTTP(w, r)
return
From 74e2aa93a71477536865c9fd7f09ceea8e90346e Mon Sep 17 00:00:00 2001
From: Felix Lange
Date: Mon, 3 Aug 2020 15:04:50 +0200
Subject: [PATCH 160/160] node: explain RegisterHandler 'name' parameter in
docs
---
node/node.go | 3 +++
1 file changed, 3 insertions(+)
diff --git a/node/node.go b/node/node.go
index 7ab2520b1b8b..c66ebb89d016 100644
--- a/node/node.go
+++ b/node/node.go
@@ -444,6 +444,9 @@ func (n *Node) RegisterAPIs(apis []rpc.API) {
}
// RegisterHandler mounts a handler on the given path on the canonical HTTP server.
+//
+// The name of the handler is shown in a log message when the HTTP server starts
+// and should be a descriptive term for the service provided by the handler.
func (n *Node) RegisterHandler(name, path string, handler http.Handler) {
n.lock.Lock()
defer n.lock.Unlock()