gitlab.com/aquachain/aquachain@v1.17.16-rc3.0.20221018032414-e3ddf1e1c055/node/api.go (about)

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