github.com/murrekatt/go-ethereum@v1.5.8-0.20170123175102-fc52f2c007fb/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  	if cors == nil {
    96  		cors = &api.node.config.HTTPCors
    97  	}
    98  
    99  	modules := api.node.httpWhitelist
   100  	if apis != nil {
   101  		modules = nil
   102  		for _, m := range strings.Split(*apis, ",") {
   103  			modules = append(modules, strings.TrimSpace(m))
   104  		}
   105  	}
   106  
   107  	if err := api.node.startHTTP(fmt.Sprintf("%s:%d", *host, *port), api.node.rpcAPIs, modules, *cors); err != nil {
   108  		return false, err
   109  	}
   110  	return true, nil
   111  }
   112  
   113  // StopRPC terminates an already running HTTP RPC API endpoint.
   114  func (api *PrivateAdminAPI) StopRPC() (bool, error) {
   115  	api.node.lock.Lock()
   116  	defer api.node.lock.Unlock()
   117  
   118  	if api.node.httpHandler == nil {
   119  		return false, fmt.Errorf("HTTP RPC not running")
   120  	}
   121  	api.node.stopHTTP()
   122  	return true, nil
   123  }
   124  
   125  // StartWS starts the websocket RPC API server.
   126  func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *string, apis *string) (bool, error) {
   127  	api.node.lock.Lock()
   128  	defer api.node.lock.Unlock()
   129  
   130  	if api.node.wsHandler != nil {
   131  		return false, fmt.Errorf("WebSocket RPC already running on %s", api.node.wsEndpoint)
   132  	}
   133  
   134  	if host == nil {
   135  		h := DefaultWSHost
   136  		if api.node.config.WSHost != "" {
   137  			h = api.node.config.WSHost
   138  		}
   139  		host = &h
   140  	}
   141  	if port == nil {
   142  		port = &api.node.config.WSPort
   143  	}
   144  	if allowedOrigins == nil {
   145  		allowedOrigins = &api.node.config.WSOrigins
   146  	}
   147  
   148  	modules := api.node.config.WSModules
   149  	if apis != nil {
   150  		modules = nil
   151  		for _, m := range strings.Split(*apis, ",") {
   152  			modules = append(modules, strings.TrimSpace(m))
   153  		}
   154  	}
   155  
   156  	if err := api.node.startWS(fmt.Sprintf("%s:%d", *host, *port), api.node.rpcAPIs, modules, *allowedOrigins); err != nil {
   157  		return false, err
   158  	}
   159  	return true, nil
   160  }
   161  
   162  // StopRPC terminates an already running websocket RPC API endpoint.
   163  func (api *PrivateAdminAPI) StopWS() (bool, error) {
   164  	api.node.lock.Lock()
   165  	defer api.node.lock.Unlock()
   166  
   167  	if api.node.wsHandler == nil {
   168  		return false, fmt.Errorf("WebSocket RPC not running")
   169  	}
   170  	api.node.stopWS()
   171  	return true, nil
   172  }
   173  
   174  // PublicAdminAPI is the collection of administrative API methods exposed over
   175  // both secure and unsecure RPC channels.
   176  type PublicAdminAPI struct {
   177  	node *Node // Node interfaced by this API
   178  }
   179  
   180  // NewPublicAdminAPI creates a new API definition for the public admin methods
   181  // of the node itself.
   182  func NewPublicAdminAPI(node *Node) *PublicAdminAPI {
   183  	return &PublicAdminAPI{node: node}
   184  }
   185  
   186  // Peers retrieves all the information we know about each individual peer at the
   187  // protocol granularity.
   188  func (api *PublicAdminAPI) Peers() ([]*p2p.PeerInfo, error) {
   189  	server := api.node.Server()
   190  	if server == nil {
   191  		return nil, ErrNodeStopped
   192  	}
   193  	return server.PeersInfo(), nil
   194  }
   195  
   196  // NodeInfo retrieves all the information we know about the host node at the
   197  // protocol granularity.
   198  func (api *PublicAdminAPI) NodeInfo() (*p2p.NodeInfo, error) {
   199  	server := api.node.Server()
   200  	if server == nil {
   201  		return nil, ErrNodeStopped
   202  	}
   203  	return server.NodeInfo(), nil
   204  }
   205  
   206  // Datadir retrieves the current data directory the node is using.
   207  func (api *PublicAdminAPI) Datadir() string {
   208  	return api.node.DataDir()
   209  }
   210  
   211  // PublicDebugAPI is the collection of debugging related API methods exposed over
   212  // both secure and unsecure RPC channels.
   213  type PublicDebugAPI struct {
   214  	node *Node // Node interfaced by this API
   215  }
   216  
   217  // NewPublicDebugAPI creates a new API definition for the public debug methods
   218  // of the node itself.
   219  func NewPublicDebugAPI(node *Node) *PublicDebugAPI {
   220  	return &PublicDebugAPI{node: node}
   221  }
   222  
   223  // Metrics retrieves all the known system metric collected by the node.
   224  func (api *PublicDebugAPI) Metrics(raw bool) (map[string]interface{}, error) {
   225  	// Create a rate formatter
   226  	units := []string{"", "K", "M", "G", "T", "E", "P"}
   227  	round := func(value float64, prec int) string {
   228  		unit := 0
   229  		for value >= 1000 {
   230  			unit, value, prec = unit+1, value/1000, 2
   231  		}
   232  		return fmt.Sprintf(fmt.Sprintf("%%.%df%s", prec, units[unit]), value)
   233  	}
   234  	format := func(total float64, rate float64) string {
   235  		return fmt.Sprintf("%s (%s/s)", round(total, 0), round(rate, 2))
   236  	}
   237  	// Iterate over all the metrics, and just dump for now
   238  	counters := make(map[string]interface{})
   239  	metrics.DefaultRegistry.Each(func(name string, metric interface{}) {
   240  		// Create or retrieve the counter hierarchy for this metric
   241  		root, parts := counters, strings.Split(name, "/")
   242  		for _, part := range parts[:len(parts)-1] {
   243  			if _, ok := root[part]; !ok {
   244  				root[part] = make(map[string]interface{})
   245  			}
   246  			root = root[part].(map[string]interface{})
   247  		}
   248  		name = parts[len(parts)-1]
   249  
   250  		// Fill the counter with the metric details, formatting if requested
   251  		if raw {
   252  			switch metric := metric.(type) {
   253  			case metrics.Meter:
   254  				root[name] = map[string]interface{}{
   255  					"AvgRate01Min": metric.Rate1(),
   256  					"AvgRate05Min": metric.Rate5(),
   257  					"AvgRate15Min": metric.Rate15(),
   258  					"MeanRate":     metric.RateMean(),
   259  					"Overall":      float64(metric.Count()),
   260  				}
   261  
   262  			case metrics.Timer:
   263  				root[name] = map[string]interface{}{
   264  					"AvgRate01Min": metric.Rate1(),
   265  					"AvgRate05Min": metric.Rate5(),
   266  					"AvgRate15Min": metric.Rate15(),
   267  					"MeanRate":     metric.RateMean(),
   268  					"Overall":      float64(metric.Count()),
   269  					"Percentiles": map[string]interface{}{
   270  						"5":  metric.Percentile(0.05),
   271  						"20": metric.Percentile(0.2),
   272  						"50": metric.Percentile(0.5),
   273  						"80": metric.Percentile(0.8),
   274  						"95": metric.Percentile(0.95),
   275  					},
   276  				}
   277  
   278  			default:
   279  				root[name] = "Unknown metric type"
   280  			}
   281  		} else {
   282  			switch metric := metric.(type) {
   283  			case metrics.Meter:
   284  				root[name] = map[string]interface{}{
   285  					"Avg01Min": format(metric.Rate1()*60, metric.Rate1()),
   286  					"Avg05Min": format(metric.Rate5()*300, metric.Rate5()),
   287  					"Avg15Min": format(metric.Rate15()*900, metric.Rate15()),
   288  					"Overall":  format(float64(metric.Count()), metric.RateMean()),
   289  				}
   290  
   291  			case metrics.Timer:
   292  				root[name] = map[string]interface{}{
   293  					"Avg01Min": format(metric.Rate1()*60, metric.Rate1()),
   294  					"Avg05Min": format(metric.Rate5()*300, metric.Rate5()),
   295  					"Avg15Min": format(metric.Rate15()*900, metric.Rate15()),
   296  					"Overall":  format(float64(metric.Count()), metric.RateMean()),
   297  					"Maximum":  time.Duration(metric.Max()).String(),
   298  					"Minimum":  time.Duration(metric.Min()).String(),
   299  					"Percentiles": map[string]interface{}{
   300  						"5":  time.Duration(metric.Percentile(0.05)).String(),
   301  						"20": time.Duration(metric.Percentile(0.2)).String(),
   302  						"50": time.Duration(metric.Percentile(0.5)).String(),
   303  						"80": time.Duration(metric.Percentile(0.8)).String(),
   304  						"95": time.Duration(metric.Percentile(0.95)).String(),
   305  					},
   306  				}
   307  
   308  			default:
   309  				root[name] = "Unknown metric type"
   310  			}
   311  		}
   312  	})
   313  	return counters, nil
   314  }
   315  
   316  // PublicWeb3API offers helper utils
   317  type PublicWeb3API struct {
   318  	stack *Node
   319  }
   320  
   321  // NewPublicWeb3API creates a new Web3Service instance
   322  func NewPublicWeb3API(stack *Node) *PublicWeb3API {
   323  	return &PublicWeb3API{stack}
   324  }
   325  
   326  // ClientVersion returns the node name
   327  func (s *PublicWeb3API) ClientVersion() string {
   328  	return s.stack.Server().Name
   329  }
   330  
   331  // Sha3 applies the ethereum sha3 implementation on the input.
   332  // It assumes the input is hex encoded.
   333  func (s *PublicWeb3API) Sha3(input hexutil.Bytes) hexutil.Bytes {
   334  	return crypto.Keccak256(input)
   335  }