github.com/klaytn/klaytn@v1.10.2/node/api.go (about)

     1  // Modifications Copyright 2018 The klaytn Authors
     2  // Copyright 2015 The go-ethereum Authors
     3  // This file is part of go-ethereum.
     4  //
     5  // The go-ethereum library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Lesser General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // The go-ethereum library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  // GNU Lesser General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public License
    16  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  // This file is derived from node/api.go (2018/06/04).
    19  // Modified and improved for the klaytn development.
    20  
    21  package node
    22  
    23  import (
    24  	"context"
    25  	"fmt"
    26  	"strings"
    27  	"time"
    28  
    29  	"github.com/klaytn/klaytn/common/hexutil"
    30  	"github.com/klaytn/klaytn/crypto"
    31  	"github.com/klaytn/klaytn/networks/p2p"
    32  	"github.com/klaytn/klaytn/networks/p2p/discover"
    33  	"github.com/klaytn/klaytn/networks/rpc"
    34  	"github.com/rcrowley/go-metrics"
    35  )
    36  
    37  // PrivateAdminAPI is the collection of administrative API methods exposed only
    38  // over a secure RPC channel.
    39  type PrivateAdminAPI struct {
    40  	node *Node // Node interfaced by this API
    41  }
    42  
    43  // NewPrivateAdminAPI creates a new API definition for the private admin methods
    44  // of the node itself.
    45  func NewPrivateAdminAPI(node *Node) *PrivateAdminAPI {
    46  	return &PrivateAdminAPI{node: node}
    47  }
    48  
    49  // addPeerInternal does common part for AddPeer.
    50  func addPeerInternal(server p2p.Server, url string, onParentChain bool) (*discover.Node, error) {
    51  	// Try to add the url as a static peer and return
    52  	node, err := discover.ParseNode(url)
    53  	if err != nil {
    54  		return nil, fmt.Errorf("invalid kni: %v", err)
    55  	}
    56  	server.AddPeer(node)
    57  	return node, nil
    58  }
    59  
    60  // AddPeer requests connecting to a remote node, and also maintaining the new
    61  // connection at all times, even reconnecting if it is lost.
    62  func (api *PrivateAdminAPI) AddPeer(url string) (bool, error) {
    63  	// Make sure the server is running, fail otherwise
    64  	server := api.node.Server()
    65  	if server == nil {
    66  		return false, ErrNodeStopped
    67  	}
    68  	// TODO-Klaytn Refactoring this to check whether the url is valid or not by dialing and return it.
    69  	if _, err := addPeerInternal(server, url, false); err != nil {
    70  		return false, err
    71  	} else {
    72  		return true, nil
    73  	}
    74  }
    75  
    76  // RemovePeer disconnects from a a remote node if the connection exists
    77  func (api *PrivateAdminAPI) RemovePeer(url string) (bool, error) {
    78  	// Make sure the server is running, fail otherwise
    79  	server := api.node.Server()
    80  	if server == nil {
    81  		return false, ErrNodeStopped
    82  	}
    83  	// Try to remove the url as a static peer and return
    84  	node, err := discover.ParseNode(url)
    85  	if err != nil {
    86  		return false, fmt.Errorf("invalid kni: %v", err)
    87  	}
    88  	server.RemovePeer(node)
    89  	return true, nil
    90  }
    91  
    92  // PeerEvents creates an RPC subscription which receives peer events from the
    93  // node's p2p.Server
    94  func (api *PrivateAdminAPI) PeerEvents(ctx context.Context) (*rpc.Subscription, error) {
    95  	// Make sure the server is running, fail otherwise
    96  	server := api.node.Server()
    97  	if server == nil {
    98  		return nil, ErrNodeStopped
    99  	}
   100  
   101  	// Create the subscription
   102  	notifier, supported := rpc.NotifierFromContext(ctx)
   103  	if !supported {
   104  		return nil, rpc.ErrNotificationsUnsupported
   105  	}
   106  	rpcSub := notifier.CreateSubscription()
   107  
   108  	go func() {
   109  		events := make(chan *p2p.PeerEvent)
   110  		sub := server.SubscribeEvents(events)
   111  		defer sub.Unsubscribe()
   112  
   113  		for {
   114  			select {
   115  			case event := <-events:
   116  				notifier.Notify(rpcSub.ID, event)
   117  			case <-sub.Err():
   118  				return
   119  			case <-rpcSub.Err():
   120  				return
   121  			case <-notifier.Closed():
   122  				return
   123  			}
   124  		}
   125  	}()
   126  
   127  	return rpcSub, nil
   128  }
   129  
   130  // StartHTTP starts the HTTP RPC API server.
   131  func (api *PrivateAdminAPI) StartHTTP(host *string, port *int, cors *string, apis *string, vhosts *string) (bool, error) {
   132  	api.node.lock.Lock()
   133  	defer api.node.lock.Unlock()
   134  
   135  	if api.node.httpHandler != nil {
   136  		return false, fmt.Errorf("HTTP RPC already running on %s", api.node.httpEndpoint)
   137  	}
   138  
   139  	if host == nil {
   140  		h := DefaultHTTPHost
   141  		if api.node.config.HTTPHost != "" {
   142  			h = api.node.config.HTTPHost
   143  		}
   144  		host = &h
   145  	}
   146  	if port == nil {
   147  		port = &api.node.config.HTTPPort
   148  	}
   149  
   150  	allowedOrigins := api.node.config.HTTPCors
   151  	if cors != nil {
   152  		allowedOrigins = nil
   153  		for _, origin := range strings.Split(*cors, ",") {
   154  			allowedOrigins = append(allowedOrigins, strings.TrimSpace(origin))
   155  		}
   156  	}
   157  
   158  	allowedVHosts := api.node.config.HTTPVirtualHosts
   159  	if vhosts != nil {
   160  		allowedVHosts = nil
   161  		for _, vhost := range strings.Split(*host, ",") {
   162  			allowedVHosts = append(allowedVHosts, strings.TrimSpace(vhost))
   163  		}
   164  	}
   165  
   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(
   175  		fmt.Sprintf("%s:%d", *host, *port),
   176  		api.node.rpcAPIs, modules, allowedOrigins, allowedVHosts, api.node.config.HTTPTimeouts); err != nil {
   177  		return false, err
   178  	}
   179  
   180  	return true, nil
   181  }
   182  
   183  // StartRPC starts the HTTP RPC API server.
   184  // This method is deprecated. Use StartHTTP instead.
   185  func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis *string, vhosts *string) (bool, error) {
   186  	logger.Warn("Deprecation warning", "method", "admin.StartRPC", "use-instead", "admin.StartHTTP")
   187  	return api.StartHTTP(host, port, cors, apis, vhosts)
   188  }
   189  
   190  // StopHTTP terminates an already running HTTP RPC API endpoint.
   191  func (api *PrivateAdminAPI) StopHTTP() (bool, error) {
   192  	api.node.lock.Lock()
   193  	defer api.node.lock.Unlock()
   194  
   195  	if api.node.httpHandler == nil {
   196  		return false, fmt.Errorf("HTTP RPC not running")
   197  	}
   198  	api.node.stopHTTP()
   199  	return true, nil
   200  }
   201  
   202  // StopRPC terminates an already running HTTP RPC API endpoint.
   203  // This method is deprecated. Use StopHTTP instead.
   204  func (api *PrivateAdminAPI) StopRPC() (bool, error) {
   205  	logger.Warn("Deprecation warning", "method", "admin.StopRPC", "use-instead", "admin.StopHTTP")
   206  	return api.StopHTTP()
   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(
   246  		fmt.Sprintf("%s:%d", *host, *port),
   247  		api.node.rpcAPIs, modules, origins, api.node.config.WSExposeAll); err != nil {
   248  		return false, err
   249  	}
   250  
   251  	return true, nil
   252  }
   253  
   254  // StopRPC terminates an already running websocket RPC API endpoint.
   255  func (api *PrivateAdminAPI) StopWS() (bool, error) {
   256  	api.node.lock.Lock()
   257  	defer api.node.lock.Unlock()
   258  
   259  	if api.node.wsHandler == nil {
   260  		return false, fmt.Errorf("WebSocket RPC not running")
   261  	}
   262  	api.node.stopWS()
   263  	return true, nil
   264  }
   265  
   266  func (api *PrivateAdminAPI) SetMaxSubscriptionPerWSConn(num int32) {
   267  	logger.Info("Change the max subscription number for a websocket connection",
   268  		"old", rpc.MaxSubscriptionPerWSConn, "new", num)
   269  	rpc.MaxSubscriptionPerWSConn = num
   270  }
   271  
   272  // PublicAdminAPI is the collection of administrative API methods exposed over
   273  // both secure and unsecure RPC channels.
   274  type PublicAdminAPI struct {
   275  	node *Node // Node interfaced by this API
   276  }
   277  
   278  // NewPublicAdminAPI creates a new API definition for the public admin methods
   279  // of the node itself.
   280  func NewPublicAdminAPI(node *Node) *PublicAdminAPI {
   281  	return &PublicAdminAPI{node: node}
   282  }
   283  
   284  // Peers retrieves all the information we know about each individual peer at the
   285  // protocol granularity.
   286  func (api *PublicAdminAPI) Peers() ([]*p2p.PeerInfo, error) {
   287  	server := api.node.Server()
   288  	if server == nil {
   289  		return nil, ErrNodeStopped
   290  	}
   291  	return server.PeersInfo(), nil
   292  }
   293  
   294  // NodeInfo retrieves all the information we know about the host node at the
   295  // protocol granularity.
   296  func (api *PublicAdminAPI) NodeInfo() (*p2p.NodeInfo, error) {
   297  	server := api.node.Server()
   298  	if server == nil {
   299  		return nil, ErrNodeStopped
   300  	}
   301  	return server.NodeInfo(), nil
   302  }
   303  
   304  // Datadir retrieves the current data directory the node is using.
   305  func (api *PublicAdminAPI) Datadir() string {
   306  	return api.node.DataDir()
   307  }
   308  
   309  // PublicDebugAPI is the collection of debugging related API methods exposed over
   310  // both secure and unsecure RPC channels.
   311  type PublicDebugAPI struct {
   312  	node *Node // Node interfaced by this API
   313  }
   314  
   315  // NewPublicDebugAPI creates a new API definition for the public debug methods
   316  // of the node itself.
   317  func NewPublicDebugAPI(node *Node) *PublicDebugAPI {
   318  	return &PublicDebugAPI{node: node}
   319  }
   320  
   321  // Metrics retrieves all the known system metric collected by the node.
   322  func (api *PublicDebugAPI) Metrics(raw bool) (map[string]interface{}, error) {
   323  	// Create a rate formatter
   324  	units := []string{"", "K", "M", "G", "T", "E", "P"}
   325  	round := func(value float64, prec int) string {
   326  		unit := 0
   327  		for value >= 1000 {
   328  			unit, value, prec = unit+1, value/1000, 2
   329  		}
   330  		return fmt.Sprintf(fmt.Sprintf("%%.%df%s", prec, units[unit]), value)
   331  	}
   332  	format := func(total float64, rate float64) string {
   333  		return fmt.Sprintf("%s (%s/s)", round(total, 0), round(rate, 2))
   334  	}
   335  	// Iterate over all the metrics, and just dump for now
   336  	counters := make(map[string]interface{})
   337  	metrics.DefaultRegistry.Each(func(name string, metric interface{}) {
   338  		// Create or retrieve the counter hierarchy for this metric
   339  		root, parts := counters, strings.Split(name, "/")
   340  		for _, part := range parts[:len(parts)-1] {
   341  			if _, ok := root[part]; !ok {
   342  				root[part] = make(map[string]interface{})
   343  			}
   344  			root = root[part].(map[string]interface{})
   345  		}
   346  		name = parts[len(parts)-1]
   347  
   348  		// Fill the counter with the metric details, formatting if requested
   349  		if raw {
   350  			switch metric := metric.(type) {
   351  			case metrics.Counter:
   352  				root[name] = map[string]interface{}{
   353  					"Overall": float64(metric.Count()),
   354  				}
   355  
   356  			case metrics.Meter:
   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  				}
   364  
   365  			case metrics.Timer:
   366  				root[name] = map[string]interface{}{
   367  					"AvgRate01Min": metric.Rate1(),
   368  					"AvgRate05Min": metric.Rate5(),
   369  					"AvgRate15Min": metric.Rate15(),
   370  					"MeanRate":     metric.RateMean(),
   371  					"Mean":         metric.Mean(),
   372  					"StdDev":       metric.StdDev(),
   373  					"Overall":      float64(metric.Count()),
   374  					"Percentiles": map[string]interface{}{
   375  						"5":  metric.Percentile(0.05),
   376  						"20": metric.Percentile(0.2),
   377  						"50": metric.Percentile(0.5),
   378  						"80": metric.Percentile(0.8),
   379  						"95": metric.Percentile(0.95),
   380  					},
   381  				}
   382  
   383  			default:
   384  				root[name] = "Unknown metric type"
   385  			}
   386  		} else {
   387  			switch metric := metric.(type) {
   388  			case metrics.Counter:
   389  				root[name] = map[string]interface{}{
   390  					"Overall": float64(metric.Count()),
   391  				}
   392  
   393  			case metrics.Meter:
   394  				root[name] = map[string]interface{}{
   395  					"Avg01Min": format(metric.Rate1()*60, metric.Rate1()),
   396  					"Avg05Min": format(metric.Rate5()*300, metric.Rate5()),
   397  					"Avg15Min": format(metric.Rate15()*900, metric.Rate15()),
   398  					"Overall":  format(float64(metric.Count()), metric.RateMean()),
   399  				}
   400  
   401  			case metrics.Timer:
   402  				root[name] = map[string]interface{}{
   403  					"Avg01Min": format(metric.Rate1()*60, metric.Rate1()),
   404  					"Avg05Min": format(metric.Rate5()*300, metric.Rate5()),
   405  					"Avg15Min": format(metric.Rate15()*900, metric.Rate15()),
   406  					"Overall":  format(float64(metric.Count()), metric.RateMean()),
   407  					"Maximum":  time.Duration(metric.Max()).String(),
   408  					"Minimum":  time.Duration(metric.Min()).String(),
   409  					"Percentiles": map[string]interface{}{
   410  						"5":  time.Duration(metric.Percentile(0.05)).String(),
   411  						"20": time.Duration(metric.Percentile(0.2)).String(),
   412  						"50": time.Duration(metric.Percentile(0.5)).String(),
   413  						"80": time.Duration(metric.Percentile(0.8)).String(),
   414  						"95": time.Duration(metric.Percentile(0.95)).String(),
   415  					},
   416  				}
   417  
   418  			default:
   419  				root[name] = "Unknown metric type"
   420  			}
   421  		}
   422  	})
   423  	return counters, nil
   424  }
   425  
   426  // PublicKlayAPI offers helper utils
   427  type PublicKlayAPI struct {
   428  	stack *Node
   429  }
   430  
   431  // NewPublicKlayAPI creates a new Web3Service instance
   432  func NewPublicKlayAPI(stack *Node) *PublicKlayAPI {
   433  	return &PublicKlayAPI{stack}
   434  }
   435  
   436  // ClientVersion returns the node name
   437  func (s *PublicKlayAPI) ClientVersion() string {
   438  	return s.stack.Server().Name()
   439  }
   440  
   441  // Sha3 applies the Klaytn sha3 implementation on the input.
   442  // It assumes the input is hex encoded.
   443  func (s *PublicKlayAPI) Sha3(input hexutil.Bytes) hexutil.Bytes {
   444  	return crypto.Keccak256(input)
   445  }