github.com/luckypickle/go-ethereum-vet@v1.14.2/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  	"context"
    21  	"fmt"
    22  	"strings"
    23  	"time"
    24  
    25  	"github.com/luckypickle/go-ethereum-vet/common/hexutil"
    26  	"github.com/luckypickle/go-ethereum-vet/crypto"
    27  	"github.com/luckypickle/go-ethereum-vet/metrics"
    28  	"github.com/luckypickle/go-ethereum-vet/p2p"
    29  	"github.com/luckypickle/go-ethereum-vet/p2p/discover"
    30  	"github.com/luckypickle/go-ethereum-vet/rpc"
    31  )
    32  
    33  // PrivateAdminAPI is the collection of administrative API methods exposed only
    34  // over a secure RPC channel.
    35  type PrivateAdminAPI struct {
    36  	node *Node // Node interfaced by this API
    37  }
    38  
    39  // NewPrivateAdminAPI creates a new API definition for the private admin methods
    40  // of the node itself.
    41  func NewPrivateAdminAPI(node *Node) *PrivateAdminAPI {
    42  	return &PrivateAdminAPI{node: node}
    43  }
    44  
    45  // AddPeer requests connecting to a remote node, and also maintaining the new
    46  // connection at all times, even reconnecting if it is lost.
    47  func (api *PrivateAdminAPI) AddPeer(url string) (bool, error) {
    48  	// Make sure the server is running, fail otherwise
    49  	server := api.node.Server()
    50  	if server == nil {
    51  		return false, ErrNodeStopped
    52  	}
    53  	// Try to add the url as a static peer and return
    54  	node, err := discover.ParseNode(url)
    55  	if err != nil {
    56  		return false, fmt.Errorf("invalid enode: %v", err)
    57  	}
    58  	server.AddPeer(node)
    59  	return true, nil
    60  }
    61  
    62  // RemovePeer disconnects from a remote node if the connection exists
    63  func (api *PrivateAdminAPI) RemovePeer(url string) (bool, error) {
    64  	// Make sure the server is running, fail otherwise
    65  	server := api.node.Server()
    66  	if server == nil {
    67  		return false, ErrNodeStopped
    68  	}
    69  	// Try to remove the url as a static peer and return
    70  	node, err := discover.ParseNode(url)
    71  	if err != nil {
    72  		return false, fmt.Errorf("invalid enode: %v", err)
    73  	}
    74  	server.RemovePeer(node)
    75  	return true, nil
    76  }
    77  
    78  // AddTrustedPeer allows a remote node to always connect, even if slots are full
    79  func (api *PrivateAdminAPI) AddTrustedPeer(url string) (bool, error) {
    80  	// Make sure the server is running, fail otherwise
    81  	server := api.node.Server()
    82  	if server == nil {
    83  		return false, ErrNodeStopped
    84  	}
    85  	node, err := discover.ParseNode(url)
    86  	if err != nil {
    87  		return false, fmt.Errorf("invalid enode: %v", err)
    88  	}
    89  	server.AddTrustedPeer(node)
    90  	return true, nil
    91  }
    92  
    93  // RemoveTrustedPeer removes a remote node from the trusted peer set, but it
    94  // does not disconnect it automatically.
    95  func (api *PrivateAdminAPI) RemoveTrustedPeer(url string) (bool, error) {
    96  	// Make sure the server is running, fail otherwise
    97  	server := api.node.Server()
    98  	if server == nil {
    99  		return false, ErrNodeStopped
   100  	}
   101  	node, err := discover.ParseNode(url)
   102  	if err != nil {
   103  		return false, fmt.Errorf("invalid enode: %v", err)
   104  	}
   105  	server.RemoveTrustedPeer(node)
   106  	return true, nil
   107  }
   108  
   109  // PeerEvents creates an RPC subscription which receives peer events from the
   110  // node's p2p.Server
   111  func (api *PrivateAdminAPI) PeerEvents(ctx context.Context) (*rpc.Subscription, error) {
   112  	// Make sure the server is running, fail otherwise
   113  	server := api.node.Server()
   114  	if server == nil {
   115  		return nil, ErrNodeStopped
   116  	}
   117  
   118  	// Create the subscription
   119  	notifier, supported := rpc.NotifierFromContext(ctx)
   120  	if !supported {
   121  		return nil, rpc.ErrNotificationsUnsupported
   122  	}
   123  	rpcSub := notifier.CreateSubscription()
   124  
   125  	go func() {
   126  		events := make(chan *p2p.PeerEvent)
   127  		sub := server.SubscribeEvents(events)
   128  		defer sub.Unsubscribe()
   129  
   130  		for {
   131  			select {
   132  			case event := <-events:
   133  				notifier.Notify(rpcSub.ID, event)
   134  			case <-sub.Err():
   135  				return
   136  			case <-rpcSub.Err():
   137  				return
   138  			case <-notifier.Closed():
   139  				return
   140  			}
   141  		}
   142  	}()
   143  
   144  	return rpcSub, nil
   145  }
   146  
   147  // StartRPC starts the HTTP RPC API server.
   148  func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis *string, vhosts *string) (bool, error) {
   149  	api.node.lock.Lock()
   150  	defer api.node.lock.Unlock()
   151  
   152  	if api.node.httpHandler != nil {
   153  		return false, fmt.Errorf("HTTP RPC already running on %s", api.node.httpEndpoint)
   154  	}
   155  
   156  	if host == nil {
   157  		h := DefaultHTTPHost
   158  		if api.node.config.HTTPHost != "" {
   159  			h = api.node.config.HTTPHost
   160  		}
   161  		host = &h
   162  	}
   163  	if port == nil {
   164  		port = &api.node.config.HTTPPort
   165  	}
   166  
   167  	allowedOrigins := api.node.config.HTTPCors
   168  	if cors != nil {
   169  		allowedOrigins = nil
   170  		for _, origin := range strings.Split(*cors, ",") {
   171  			allowedOrigins = append(allowedOrigins, strings.TrimSpace(origin))
   172  		}
   173  	}
   174  
   175  	allowedVHosts := api.node.config.HTTPVirtualHosts
   176  	if vhosts != nil {
   177  		allowedVHosts = nil
   178  		for _, vhost := range strings.Split(*host, ",") {
   179  			allowedVHosts = append(allowedVHosts, strings.TrimSpace(vhost))
   180  		}
   181  	}
   182  
   183  	modules := api.node.httpWhitelist
   184  	if apis != nil {
   185  		modules = nil
   186  		for _, m := range strings.Split(*apis, ",") {
   187  			modules = append(modules, strings.TrimSpace(m))
   188  		}
   189  	}
   190  
   191  	if err := api.node.startHTTP(fmt.Sprintf("%s:%d", *host, *port), api.node.rpcAPIs, modules, allowedOrigins, allowedVHosts, api.node.config.HTTPTimeouts); err != nil {
   192  		return false, err
   193  	}
   194  	return true, nil
   195  }
   196  
   197  // StopRPC terminates an already running HTTP RPC API endpoint.
   198  func (api *PrivateAdminAPI) StopRPC() (bool, error) {
   199  	api.node.lock.Lock()
   200  	defer api.node.lock.Unlock()
   201  
   202  	if api.node.httpHandler == nil {
   203  		return false, fmt.Errorf("HTTP RPC not running")
   204  	}
   205  	api.node.stopHTTP()
   206  	return true, nil
   207  }
   208  
   209  // StartWS starts the websocket RPC API server.
   210  func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *string, apis *string) (bool, error) {
   211  	api.node.lock.Lock()
   212  	defer api.node.lock.Unlock()
   213  
   214  	if api.node.wsHandler != nil {
   215  		return false, fmt.Errorf("WebSocket RPC already running on %s", api.node.wsEndpoint)
   216  	}
   217  
   218  	if host == nil {
   219  		h := DefaultWSHost
   220  		if api.node.config.WSHost != "" {
   221  			h = api.node.config.WSHost
   222  		}
   223  		host = &h
   224  	}
   225  	if port == nil {
   226  		port = &api.node.config.WSPort
   227  	}
   228  
   229  	origins := api.node.config.WSOrigins
   230  	if allowedOrigins != nil {
   231  		origins = nil
   232  		for _, origin := range strings.Split(*allowedOrigins, ",") {
   233  			origins = append(origins, strings.TrimSpace(origin))
   234  		}
   235  	}
   236  
   237  	modules := api.node.config.WSModules
   238  	if apis != nil {
   239  		modules = nil
   240  		for _, m := range strings.Split(*apis, ",") {
   241  			modules = append(modules, strings.TrimSpace(m))
   242  		}
   243  	}
   244  
   245  	if err := api.node.startWS(fmt.Sprintf("%s:%d", *host, *port), api.node.rpcAPIs, modules, origins, api.node.config.WSExposeAll); err != nil {
   246  		return false, err
   247  	}
   248  	return true, nil
   249  }
   250  
   251  // StopWS terminates an already running websocket RPC API endpoint.
   252  func (api *PrivateAdminAPI) StopWS() (bool, error) {
   253  	api.node.lock.Lock()
   254  	defer api.node.lock.Unlock()
   255  
   256  	if api.node.wsHandler == nil {
   257  		return false, fmt.Errorf("WebSocket RPC not running")
   258  	}
   259  	api.node.stopWS()
   260  	return true, nil
   261  }
   262  
   263  // PublicAdminAPI is the collection of administrative API methods exposed over
   264  // both secure and unsecure RPC channels.
   265  type PublicAdminAPI struct {
   266  	node *Node // Node interfaced by this API
   267  }
   268  
   269  // NewPublicAdminAPI creates a new API definition for the public admin methods
   270  // of the node itself.
   271  func NewPublicAdminAPI(node *Node) *PublicAdminAPI {
   272  	return &PublicAdminAPI{node: node}
   273  }
   274  
   275  // Peers retrieves all the information we know about each individual peer at the
   276  // protocol granularity.
   277  func (api *PublicAdminAPI) Peers() ([]*p2p.PeerInfo, error) {
   278  	server := api.node.Server()
   279  	if server == nil {
   280  		return nil, ErrNodeStopped
   281  	}
   282  	return server.PeersInfo(), nil
   283  }
   284  
   285  // NodeInfo retrieves all the information we know about the host node at the
   286  // protocol granularity.
   287  func (api *PublicAdminAPI) NodeInfo() (*p2p.NodeInfo, error) {
   288  	server := api.node.Server()
   289  	if server == nil {
   290  		return nil, ErrNodeStopped
   291  	}
   292  	return server.NodeInfo(), nil
   293  }
   294  
   295  // Datadir retrieves the current data directory the node is using.
   296  func (api *PublicAdminAPI) Datadir() string {
   297  	return api.node.DataDir()
   298  }
   299  
   300  // PublicDebugAPI is the collection of debugging related API methods exposed over
   301  // both secure and unsecure RPC channels.
   302  type PublicDebugAPI struct {
   303  	node *Node // Node interfaced by this API
   304  }
   305  
   306  // NewPublicDebugAPI creates a new API definition for the public debug methods
   307  // of the node itself.
   308  func NewPublicDebugAPI(node *Node) *PublicDebugAPI {
   309  	return &PublicDebugAPI{node: node}
   310  }
   311  
   312  // Metrics retrieves all the known system metric collected by the node.
   313  func (api *PublicDebugAPI) Metrics(raw bool) (map[string]interface{}, error) {
   314  	// Create a rate formatter
   315  	units := []string{"", "K", "M", "G", "T", "E", "P"}
   316  	round := func(value float64, prec int) string {
   317  		unit := 0
   318  		for value >= 1000 {
   319  			unit, value, prec = unit+1, value/1000, 2
   320  		}
   321  		return fmt.Sprintf(fmt.Sprintf("%%.%df%s", prec, units[unit]), value)
   322  	}
   323  	format := func(total float64, rate float64) string {
   324  		return fmt.Sprintf("%s (%s/s)", round(total, 0), round(rate, 2))
   325  	}
   326  	// Iterate over all the metrics, and just dump for now
   327  	counters := make(map[string]interface{})
   328  	metrics.DefaultRegistry.Each(func(name string, metric interface{}) {
   329  		// Create or retrieve the counter hierarchy for this metric
   330  		root, parts := counters, strings.Split(name, "/")
   331  		for _, part := range parts[:len(parts)-1] {
   332  			if _, ok := root[part]; !ok {
   333  				root[part] = make(map[string]interface{})
   334  			}
   335  			root = root[part].(map[string]interface{})
   336  		}
   337  		name = parts[len(parts)-1]
   338  
   339  		// Fill the counter with the metric details, formatting if requested
   340  		if raw {
   341  			switch metric := metric.(type) {
   342  			case metrics.Counter:
   343  				root[name] = map[string]interface{}{
   344  					"Overall": float64(metric.Count()),
   345  				}
   346  
   347  			case metrics.Meter:
   348  				root[name] = map[string]interface{}{
   349  					"AvgRate01Min": metric.Rate1(),
   350  					"AvgRate05Min": metric.Rate5(),
   351  					"AvgRate15Min": metric.Rate15(),
   352  					"MeanRate":     metric.RateMean(),
   353  					"Overall":      float64(metric.Count()),
   354  				}
   355  
   356  			case metrics.Timer:
   357  				root[name] = map[string]interface{}{
   358  					"AvgRate01Min": metric.Rate1(),
   359  					"AvgRate05Min": metric.Rate5(),
   360  					"AvgRate15Min": metric.Rate15(),
   361  					"MeanRate":     metric.RateMean(),
   362  					"Overall":      float64(metric.Count()),
   363  					"Percentiles": map[string]interface{}{
   364  						"5":  metric.Percentile(0.05),
   365  						"20": metric.Percentile(0.2),
   366  						"50": metric.Percentile(0.5),
   367  						"80": metric.Percentile(0.8),
   368  						"95": metric.Percentile(0.95),
   369  					},
   370  				}
   371  
   372  			case metrics.ResettingTimer:
   373  				t := metric.Snapshot()
   374  				ps := t.Percentiles([]float64{5, 20, 50, 80, 95})
   375  				root[name] = map[string]interface{}{
   376  					"Measurements": len(t.Values()),
   377  					"Mean":         t.Mean(),
   378  					"Percentiles": map[string]interface{}{
   379  						"5":  ps[0],
   380  						"20": ps[1],
   381  						"50": ps[2],
   382  						"80": ps[3],
   383  						"95": ps[4],
   384  					},
   385  				}
   386  
   387  			default:
   388  				root[name] = "Unknown metric type"
   389  			}
   390  		} else {
   391  			switch metric := metric.(type) {
   392  			case metrics.Counter:
   393  				root[name] = map[string]interface{}{
   394  					"Overall": float64(metric.Count()),
   395  				}
   396  
   397  			case metrics.Meter:
   398  				root[name] = map[string]interface{}{
   399  					"Avg01Min": format(metric.Rate1()*60, metric.Rate1()),
   400  					"Avg05Min": format(metric.Rate5()*300, metric.Rate5()),
   401  					"Avg15Min": format(metric.Rate15()*900, metric.Rate15()),
   402  					"Overall":  format(float64(metric.Count()), metric.RateMean()),
   403  				}
   404  
   405  			case metrics.Timer:
   406  				root[name] = map[string]interface{}{
   407  					"Avg01Min": format(metric.Rate1()*60, metric.Rate1()),
   408  					"Avg05Min": format(metric.Rate5()*300, metric.Rate5()),
   409  					"Avg15Min": format(metric.Rate15()*900, metric.Rate15()),
   410  					"Overall":  format(float64(metric.Count()), metric.RateMean()),
   411  					"Maximum":  time.Duration(metric.Max()).String(),
   412  					"Minimum":  time.Duration(metric.Min()).String(),
   413  					"Percentiles": map[string]interface{}{
   414  						"5":  time.Duration(metric.Percentile(0.05)).String(),
   415  						"20": time.Duration(metric.Percentile(0.2)).String(),
   416  						"50": time.Duration(metric.Percentile(0.5)).String(),
   417  						"80": time.Duration(metric.Percentile(0.8)).String(),
   418  						"95": time.Duration(metric.Percentile(0.95)).String(),
   419  					},
   420  				}
   421  
   422  			case metrics.ResettingTimer:
   423  				t := metric.Snapshot()
   424  				ps := t.Percentiles([]float64{5, 20, 50, 80, 95})
   425  				root[name] = map[string]interface{}{
   426  					"Measurements": len(t.Values()),
   427  					"Mean":         time.Duration(t.Mean()).String(),
   428  					"Percentiles": map[string]interface{}{
   429  						"5":  time.Duration(ps[0]).String(),
   430  						"20": time.Duration(ps[1]).String(),
   431  						"50": time.Duration(ps[2]).String(),
   432  						"80": time.Duration(ps[3]).String(),
   433  						"95": time.Duration(ps[4]).String(),
   434  					},
   435  				}
   436  
   437  			default:
   438  				root[name] = "Unknown metric type"
   439  			}
   440  		}
   441  	})
   442  	return counters, nil
   443  }
   444  
   445  // PublicWeb3API offers helper utils
   446  type PublicWeb3API struct {
   447  	stack *Node
   448  }
   449  
   450  // NewPublicWeb3API creates a new Web3Service instance
   451  func NewPublicWeb3API(stack *Node) *PublicWeb3API {
   452  	return &PublicWeb3API{stack}
   453  }
   454  
   455  // ClientVersion returns the node name
   456  func (s *PublicWeb3API) ClientVersion() string {
   457  	return s.stack.Server().Name
   458  }
   459  
   460  // Sha3 applies the ethereum sha3 implementation on the input.
   461  // It assumes the input is hex encoded.
   462  func (s *PublicWeb3API) Sha3(input hexutil.Bytes) hexutil.Bytes {
   463  	return crypto.Keccak256(input)
   464  }