github.com/ylsGit/go-ethereum@v1.6.5/node/api.go (about)

     1  // Copyright 2015 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package node
    18  
    19  import (
    20  	"fmt"
    21  	"strings"
    22  	"time"
    23  
    24  	"github.com/ethereum/go-ethereum/common/hexutil"
    25  	"github.com/ethereum/go-ethereum/crypto"
    26  	"github.com/ethereum/go-ethereum/p2p"
    27  	"github.com/ethereum/go-ethereum/p2p/discover"
    28  	"github.com/rcrowley/go-metrics"
    29  )
    30  
    31  // PrivateAdminAPI is the collection of administrative API methods exposed only
    32  // over a secure RPC channel.
    33  type PrivateAdminAPI struct {
    34  	node *Node // Node interfaced by this API
    35  }
    36  
    37  // NewPrivateAdminAPI creates a new API definition for the private admin methods
    38  // of the node itself.
    39  func NewPrivateAdminAPI(node *Node) *PrivateAdminAPI {
    40  	return &PrivateAdminAPI{node: node}
    41  }
    42  
    43  // AddPeer requests connecting to a remote node, and also maintaining the new
    44  // connection at all times, even reconnecting if it is lost.
    45  func (api *PrivateAdminAPI) AddPeer(url string) (bool, error) {
    46  	// Make sure the server is running, fail otherwise
    47  	server := api.node.Server()
    48  	if server == nil {
    49  		return false, ErrNodeStopped
    50  	}
    51  	// Try to add the url as a static peer and return
    52  	node, err := discover.ParseNode(url)
    53  	if err != nil {
    54  		return false, fmt.Errorf("invalid enode: %v", err)
    55  	}
    56  	server.AddPeer(node)
    57  	return true, nil
    58  }
    59  
    60  // RemovePeer disconnects from a a remote node if the connection exists
    61  func (api *PrivateAdminAPI) RemovePeer(url string) (bool, error) {
    62  	// Make sure the server is running, fail otherwise
    63  	server := api.node.Server()
    64  	if server == nil {
    65  		return false, ErrNodeStopped
    66  	}
    67  	// Try to remove the url as a static peer and return
    68  	node, err := discover.ParseNode(url)
    69  	if err != nil {
    70  		return false, fmt.Errorf("invalid enode: %v", err)
    71  	}
    72  	server.RemovePeer(node)
    73  	return true, nil
    74  }
    75  
    76  // StartRPC starts the HTTP RPC API server.
    77  func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis *string) (bool, error) {
    78  	api.node.lock.Lock()
    79  	defer api.node.lock.Unlock()
    80  
    81  	if api.node.httpHandler != nil {
    82  		return false, fmt.Errorf("HTTP RPC already running on %s", api.node.httpEndpoint)
    83  	}
    84  
    85  	if host == nil {
    86  		h := DefaultHTTPHost
    87  		if api.node.config.HTTPHost != "" {
    88  			h = api.node.config.HTTPHost
    89  		}
    90  		host = &h
    91  	}
    92  	if port == nil {
    93  		port = &api.node.config.HTTPPort
    94  	}
    95  
    96  	allowedOrigins := api.node.config.HTTPCors
    97  	if cors != nil {
    98  		allowedOrigins = nil
    99  		for _, origin := range strings.Split(*cors, ",") {
   100  			allowedOrigins = append(allowedOrigins, strings.TrimSpace(origin))
   101  		}
   102  	}
   103  
   104  	modules := api.node.httpWhitelist
   105  	if apis != nil {
   106  		modules = nil
   107  		for _, m := range strings.Split(*apis, ",") {
   108  			modules = append(modules, strings.TrimSpace(m))
   109  		}
   110  	}
   111  
   112  	if err := api.node.startHTTP(fmt.Sprintf("%s:%d", *host, *port), api.node.rpcAPIs, modules, allowedOrigins); err != nil {
   113  		return false, err
   114  	}
   115  	return true, nil
   116  }
   117  
   118  // StopRPC terminates an already running HTTP RPC API endpoint.
   119  func (api *PrivateAdminAPI) StopRPC() (bool, error) {
   120  	api.node.lock.Lock()
   121  	defer api.node.lock.Unlock()
   122  
   123  	if api.node.httpHandler == nil {
   124  		return false, fmt.Errorf("HTTP RPC not running")
   125  	}
   126  	api.node.stopHTTP()
   127  	return true, nil
   128  }
   129  
   130  // StartWS starts the websocket RPC API server.
   131  func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *string, apis *string) (bool, error) {
   132  	api.node.lock.Lock()
   133  	defer api.node.lock.Unlock()
   134  
   135  	if api.node.wsHandler != nil {
   136  		return false, fmt.Errorf("WebSocket RPC already running on %s", api.node.wsEndpoint)
   137  	}
   138  
   139  	if host == nil {
   140  		h := DefaultWSHost
   141  		if api.node.config.WSHost != "" {
   142  			h = api.node.config.WSHost
   143  		}
   144  		host = &h
   145  	}
   146  	if port == nil {
   147  		port = &api.node.config.WSPort
   148  	}
   149  
   150  	origins := api.node.config.WSOrigins
   151  	if allowedOrigins != nil {
   152  		origins = nil
   153  		for _, origin := range strings.Split(*allowedOrigins, ",") {
   154  			origins = append(origins, strings.TrimSpace(origin))
   155  		}
   156  	}
   157  
   158  	modules := api.node.config.WSModules
   159  	if apis != nil {
   160  		modules = nil
   161  		for _, m := range strings.Split(*apis, ",") {
   162  			modules = append(modules, strings.TrimSpace(m))
   163  		}
   164  	}
   165  
   166  	if err := api.node.startWS(fmt.Sprintf("%s:%d", *host, *port), api.node.rpcAPIs, modules, origins); err != nil {
   167  		return false, err
   168  	}
   169  	return true, nil
   170  }
   171  
   172  // StopRPC terminates an already running websocket RPC API endpoint.
   173  func (api *PrivateAdminAPI) StopWS() (bool, error) {
   174  	api.node.lock.Lock()
   175  	defer api.node.lock.Unlock()
   176  
   177  	if api.node.wsHandler == nil {
   178  		return false, fmt.Errorf("WebSocket RPC not running")
   179  	}
   180  	api.node.stopWS()
   181  	return true, nil
   182  }
   183  
   184  // PublicAdminAPI is the collection of administrative API methods exposed over
   185  // both secure and unsecure RPC channels.
   186  type PublicAdminAPI struct {
   187  	node *Node // Node interfaced by this API
   188  }
   189  
   190  // NewPublicAdminAPI creates a new API definition for the public admin methods
   191  // of the node itself.
   192  func NewPublicAdminAPI(node *Node) *PublicAdminAPI {
   193  	return &PublicAdminAPI{node: node}
   194  }
   195  
   196  // Peers retrieves all the information we know about each individual peer at the
   197  // protocol granularity.
   198  func (api *PublicAdminAPI) Peers() ([]*p2p.PeerInfo, error) {
   199  	server := api.node.Server()
   200  	if server == nil {
   201  		return nil, ErrNodeStopped
   202  	}
   203  	return server.PeersInfo(), nil
   204  }
   205  
   206  // NodeInfo retrieves all the information we know about the host node at the
   207  // protocol granularity.
   208  func (api *PublicAdminAPI) NodeInfo() (*p2p.NodeInfo, error) {
   209  	server := api.node.Server()
   210  	if server == nil {
   211  		return nil, ErrNodeStopped
   212  	}
   213  	return server.NodeInfo(), nil
   214  }
   215  
   216  // Datadir retrieves the current data directory the node is using.
   217  func (api *PublicAdminAPI) Datadir() string {
   218  	return api.node.DataDir()
   219  }
   220  
   221  // PublicDebugAPI is the collection of debugging related API methods exposed over
   222  // both secure and unsecure RPC channels.
   223  type PublicDebugAPI struct {
   224  	node *Node // Node interfaced by this API
   225  }
   226  
   227  // NewPublicDebugAPI creates a new API definition for the public debug methods
   228  // of the node itself.
   229  func NewPublicDebugAPI(node *Node) *PublicDebugAPI {
   230  	return &PublicDebugAPI{node: node}
   231  }
   232  
   233  // Metrics retrieves all the known system metric collected by the node.
   234  func (api *PublicDebugAPI) Metrics(raw bool) (map[string]interface{}, error) {
   235  	// Create a rate formatter
   236  	units := []string{"", "K", "M", "G", "T", "E", "P"}
   237  	round := func(value float64, prec int) string {
   238  		unit := 0
   239  		for value >= 1000 {
   240  			unit, value, prec = unit+1, value/1000, 2
   241  		}
   242  		return fmt.Sprintf(fmt.Sprintf("%%.%df%s", prec, units[unit]), value)
   243  	}
   244  	format := func(total float64, rate float64) string {
   245  		return fmt.Sprintf("%s (%s/s)", round(total, 0), round(rate, 2))
   246  	}
   247  	// Iterate over all the metrics, and just dump for now
   248  	counters := make(map[string]interface{})
   249  	metrics.DefaultRegistry.Each(func(name string, metric interface{}) {
   250  		// Create or retrieve the counter hierarchy for this metric
   251  		root, parts := counters, strings.Split(name, "/")
   252  		for _, part := range parts[:len(parts)-1] {
   253  			if _, ok := root[part]; !ok {
   254  				root[part] = make(map[string]interface{})
   255  			}
   256  			root = root[part].(map[string]interface{})
   257  		}
   258  		name = parts[len(parts)-1]
   259  
   260  		// Fill the counter with the metric details, formatting if requested
   261  		if raw {
   262  			switch metric := metric.(type) {
   263  			case metrics.Meter:
   264  				root[name] = map[string]interface{}{
   265  					"AvgRate01Min": metric.Rate1(),
   266  					"AvgRate05Min": metric.Rate5(),
   267  					"AvgRate15Min": metric.Rate15(),
   268  					"MeanRate":     metric.RateMean(),
   269  					"Overall":      float64(metric.Count()),
   270  				}
   271  
   272  			case metrics.Timer:
   273  				root[name] = map[string]interface{}{
   274  					"AvgRate01Min": metric.Rate1(),
   275  					"AvgRate05Min": metric.Rate5(),
   276  					"AvgRate15Min": metric.Rate15(),
   277  					"MeanRate":     metric.RateMean(),
   278  					"Overall":      float64(metric.Count()),
   279  					"Percentiles": map[string]interface{}{
   280  						"5":  metric.Percentile(0.05),
   281  						"20": metric.Percentile(0.2),
   282  						"50": metric.Percentile(0.5),
   283  						"80": metric.Percentile(0.8),
   284  						"95": metric.Percentile(0.95),
   285  					},
   286  				}
   287  
   288  			default:
   289  				root[name] = "Unknown metric type"
   290  			}
   291  		} else {
   292  			switch metric := metric.(type) {
   293  			case metrics.Meter:
   294  				root[name] = map[string]interface{}{
   295  					"Avg01Min": format(metric.Rate1()*60, metric.Rate1()),
   296  					"Avg05Min": format(metric.Rate5()*300, metric.Rate5()),
   297  					"Avg15Min": format(metric.Rate15()*900, metric.Rate15()),
   298  					"Overall":  format(float64(metric.Count()), metric.RateMean()),
   299  				}
   300  
   301  			case metrics.Timer:
   302  				root[name] = map[string]interface{}{
   303  					"Avg01Min": format(metric.Rate1()*60, metric.Rate1()),
   304  					"Avg05Min": format(metric.Rate5()*300, metric.Rate5()),
   305  					"Avg15Min": format(metric.Rate15()*900, metric.Rate15()),
   306  					"Overall":  format(float64(metric.Count()), metric.RateMean()),
   307  					"Maximum":  time.Duration(metric.Max()).String(),
   308  					"Minimum":  time.Duration(metric.Min()).String(),
   309  					"Percentiles": map[string]interface{}{
   310  						"5":  time.Duration(metric.Percentile(0.05)).String(),
   311  						"20": time.Duration(metric.Percentile(0.2)).String(),
   312  						"50": time.Duration(metric.Percentile(0.5)).String(),
   313  						"80": time.Duration(metric.Percentile(0.8)).String(),
   314  						"95": time.Duration(metric.Percentile(0.95)).String(),
   315  					},
   316  				}
   317  
   318  			default:
   319  				root[name] = "Unknown metric type"
   320  			}
   321  		}
   322  	})
   323  	return counters, nil
   324  }
   325  
   326  // PublicWeb3API offers helper utils
   327  type PublicWeb3API struct {
   328  	stack *Node
   329  }
   330  
   331  // NewPublicWeb3API creates a new Web3Service instance
   332  func NewPublicWeb3API(stack *Node) *PublicWeb3API {
   333  	return &PublicWeb3API{stack}
   334  }
   335  
   336  // ClientVersion returns the node name
   337  func (s *PublicWeb3API) ClientVersion() string {
   338  	return s.stack.Server().Name
   339  }
   340  
   341  // Sha3 applies the ethereum sha3 implementation on the input.
   342  // It assumes the input is hex encoded.
   343  func (s *PublicWeb3API) Sha3(input hexutil.Bytes) hexutil.Bytes {
   344  	return crypto.Keccak256(input)
   345  }