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