github.com/aiyaya188/klaytn@v0.0.0-20220629133911-2c66fd5546f4/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  
    24  	"github.com/aiyaya188/klaytn/common/hexutil"
    25  	"github.com/aiyaya188/klaytn/crypto"
    26  	"github.com/aiyaya188/klaytn/internal/debug"
    27  	"github.com/aiyaya188/klaytn/log"
    28  	"github.com/aiyaya188/klaytn/p2p"
    29  	"github.com/aiyaya188/klaytn/p2p/enode"
    30  	"github.com/aiyaya188/klaytn/rpc"
    31  )
    32  
    33  // apis returns the collection of built-in RPC APIs.
    34  func (n *Node) apis() []rpc.API {
    35  	return []rpc.API{
    36  		{
    37  			Namespace: "admin",
    38  			Version:   "1.0",
    39  			Service:   &adminAPI{n},
    40  		}, {
    41  			Namespace: "debug",
    42  			Version:   "1.0",
    43  			Service:   debug.Handler,
    44  		}, {
    45  			Namespace: "web3",
    46  			Version:   "1.0",
    47  			Service:   &web3API{n},
    48  		},
    49  	}
    50  }
    51  
    52  // adminAPI is the collection of administrative API methods exposed over
    53  // both secure and unsecure RPC channels.
    54  type adminAPI struct {
    55  	node *Node // Node interfaced by this API
    56  }
    57  
    58  // AddPeer requests connecting to a remote node, and also maintaining the new
    59  // connection at all times, even reconnecting if it is lost.
    60  func (api *adminAPI) AddPeer(url string) (bool, error) {
    61  	// Make sure the server is running, fail otherwise
    62  	server := api.node.Server()
    63  	if server == nil {
    64  		return false, ErrNodeStopped
    65  	}
    66  	// Try to add the url as a static peer and return
    67  	node, err := enode.Parse(enode.ValidSchemes, url)
    68  	if err != nil {
    69  		return false, fmt.Errorf("invalid enode: %v", err)
    70  	}
    71  	server.AddPeer(node)
    72  	return true, nil
    73  }
    74  
    75  // RemovePeer disconnects from a remote node if the connection exists
    76  func (api *adminAPI) RemovePeer(url string) (bool, error) {
    77  	// Make sure the server is running, fail otherwise
    78  	server := api.node.Server()
    79  	if server == nil {
    80  		return false, ErrNodeStopped
    81  	}
    82  	// Try to remove the url as a static peer and return
    83  	node, err := enode.Parse(enode.ValidSchemes, url)
    84  	if err != nil {
    85  		return false, fmt.Errorf("invalid enode: %v", err)
    86  	}
    87  	server.RemovePeer(node)
    88  	return true, nil
    89  }
    90  
    91  // AddTrustedPeer allows a remote node to always connect, even if slots are full
    92  func (api *adminAPI) AddTrustedPeer(url string) (bool, error) {
    93  	// Make sure the server is running, fail otherwise
    94  	server := api.node.Server()
    95  	if server == nil {
    96  		return false, ErrNodeStopped
    97  	}
    98  	node, err := enode.Parse(enode.ValidSchemes, url)
    99  	if err != nil {
   100  		return false, fmt.Errorf("invalid enode: %v", err)
   101  	}
   102  	server.AddTrustedPeer(node)
   103  	return true, nil
   104  }
   105  
   106  // RemoveTrustedPeer removes a remote node from the trusted peer set, but it
   107  // does not disconnect it automatically.
   108  func (api *adminAPI) RemoveTrustedPeer(url string) (bool, error) {
   109  	// Make sure the server is running, fail otherwise
   110  	server := api.node.Server()
   111  	if server == nil {
   112  		return false, ErrNodeStopped
   113  	}
   114  	node, err := enode.Parse(enode.ValidSchemes, url)
   115  	if err != nil {
   116  		return false, fmt.Errorf("invalid enode: %v", err)
   117  	}
   118  	server.RemoveTrustedPeer(node)
   119  	return true, nil
   120  }
   121  
   122  // PeerEvents creates an RPC subscription which receives peer events from the
   123  // node's p2p.Server
   124  func (api *adminAPI) PeerEvents(ctx context.Context) (*rpc.Subscription, error) {
   125  	// Make sure the server is running, fail otherwise
   126  	server := api.node.Server()
   127  	if server == nil {
   128  		return nil, ErrNodeStopped
   129  	}
   130  
   131  	// Create the subscription
   132  	notifier, supported := rpc.NotifierFromContext(ctx)
   133  	if !supported {
   134  		return nil, rpc.ErrNotificationsUnsupported
   135  	}
   136  	rpcSub := notifier.CreateSubscription()
   137  
   138  	go func() {
   139  		events := make(chan *p2p.PeerEvent)
   140  		sub := server.SubscribeEvents(events)
   141  		defer sub.Unsubscribe()
   142  
   143  		for {
   144  			select {
   145  			case event := <-events:
   146  				notifier.Notify(rpcSub.ID, event)
   147  			case <-sub.Err():
   148  				return
   149  			case <-rpcSub.Err():
   150  				return
   151  			case <-notifier.Closed():
   152  				return
   153  			}
   154  		}
   155  	}()
   156  
   157  	return rpcSub, nil
   158  }
   159  
   160  // StartHTTP starts the HTTP RPC API server.
   161  func (api *adminAPI) StartHTTP(host *string, port *int, cors *string, apis *string, vhosts *string) (bool, error) {
   162  	api.node.lock.Lock()
   163  	defer api.node.lock.Unlock()
   164  
   165  	// Determine host and port.
   166  	if host == nil {
   167  		h := DefaultHTTPHost
   168  		if api.node.config.HTTPHost != "" {
   169  			h = api.node.config.HTTPHost
   170  		}
   171  		host = &h
   172  	}
   173  	if port == nil {
   174  		port = &api.node.config.HTTPPort
   175  	}
   176  
   177  	// Determine config.
   178  	config := httpConfig{
   179  		CorsAllowedOrigins: api.node.config.HTTPCors,
   180  		Vhosts:             api.node.config.HTTPVirtualHosts,
   181  		Modules:            api.node.config.HTTPModules,
   182  	}
   183  	if cors != nil {
   184  		config.CorsAllowedOrigins = nil
   185  		for _, origin := range strings.Split(*cors, ",") {
   186  			config.CorsAllowedOrigins = append(config.CorsAllowedOrigins, strings.TrimSpace(origin))
   187  		}
   188  	}
   189  	if vhosts != nil {
   190  		config.Vhosts = nil
   191  		for _, vhost := range strings.Split(*host, ",") {
   192  			config.Vhosts = append(config.Vhosts, strings.TrimSpace(vhost))
   193  		}
   194  	}
   195  	if apis != nil {
   196  		config.Modules = nil
   197  		for _, m := range strings.Split(*apis, ",") {
   198  			config.Modules = append(config.Modules, strings.TrimSpace(m))
   199  		}
   200  	}
   201  
   202  	if err := api.node.http.setListenAddr(*host, *port); err != nil {
   203  		return false, err
   204  	}
   205  	if err := api.node.http.enableRPC(api.node.rpcAPIs, config); err != nil {
   206  		return false, err
   207  	}
   208  	if err := api.node.http.start(); err != nil {
   209  		return false, err
   210  	}
   211  	return true, nil
   212  }
   213  
   214  // StartRPC starts the HTTP RPC API server.
   215  // Deprecated: use StartHTTP instead.
   216  func (api *adminAPI) StartRPC(host *string, port *int, cors *string, apis *string, vhosts *string) (bool, error) {
   217  	log.Warn("Deprecation warning", "method", "admin.StartRPC", "use-instead", "admin.StartHTTP")
   218  	return api.StartHTTP(host, port, cors, apis, vhosts)
   219  }
   220  
   221  // StopHTTP shuts down the HTTP server.
   222  func (api *adminAPI) StopHTTP() (bool, error) {
   223  	api.node.http.stop()
   224  	return true, nil
   225  }
   226  
   227  // StopRPC shuts down the HTTP server.
   228  // Deprecated: use StopHTTP instead.
   229  func (api *adminAPI) StopRPC() (bool, error) {
   230  	log.Warn("Deprecation warning", "method", "admin.StopRPC", "use-instead", "admin.StopHTTP")
   231  	return api.StopHTTP()
   232  }
   233  
   234  // StartWS starts the websocket RPC API server.
   235  func (api *adminAPI) StartWS(host *string, port *int, allowedOrigins *string, apis *string) (bool, error) {
   236  	api.node.lock.Lock()
   237  	defer api.node.lock.Unlock()
   238  
   239  	// Determine host and port.
   240  	if host == nil {
   241  		h := DefaultWSHost
   242  		if api.node.config.WSHost != "" {
   243  			h = api.node.config.WSHost
   244  		}
   245  		host = &h
   246  	}
   247  	if port == nil {
   248  		port = &api.node.config.WSPort
   249  	}
   250  
   251  	// Determine config.
   252  	config := wsConfig{
   253  		Modules: api.node.config.WSModules,
   254  		Origins: api.node.config.WSOrigins,
   255  		// ExposeAll: api.node.config.WSExposeAll,
   256  	}
   257  	if apis != nil {
   258  		config.Modules = nil
   259  		for _, m := range strings.Split(*apis, ",") {
   260  			config.Modules = append(config.Modules, strings.TrimSpace(m))
   261  		}
   262  	}
   263  	if allowedOrigins != nil {
   264  		config.Origins = nil
   265  		for _, origin := range strings.Split(*allowedOrigins, ",") {
   266  			config.Origins = append(config.Origins, strings.TrimSpace(origin))
   267  		}
   268  	}
   269  
   270  	// Enable WebSocket on the server.
   271  	server := api.node.wsServerForPort(*port, false)
   272  	if err := server.setListenAddr(*host, *port); err != nil {
   273  		return false, err
   274  	}
   275  	openApis, _ := api.node.GetAPIs()
   276  	if err := server.enableWS(openApis, config); err != nil {
   277  		return false, err
   278  	}
   279  	if err := server.start(); err != nil {
   280  		return false, err
   281  	}
   282  	api.node.http.log.Info("WebSocket endpoint opened", "url", api.node.WSEndpoint())
   283  	return true, nil
   284  }
   285  
   286  // StopWS terminates all WebSocket servers.
   287  func (api *adminAPI) StopWS() (bool, error) {
   288  	api.node.http.stopWS()
   289  	api.node.ws.stop()
   290  	return true, nil
   291  }
   292  
   293  // Peers retrieves all the information we know about each individual peer at the
   294  // protocol granularity.
   295  func (api *adminAPI) Peers() ([]*p2p.PeerInfo, error) {
   296  	server := api.node.Server()
   297  	if server == nil {
   298  		return nil, ErrNodeStopped
   299  	}
   300  	return server.PeersInfo(), nil
   301  }
   302  
   303  // NodeInfo retrieves all the information we know about the host node at the
   304  // protocol granularity.
   305  func (api *adminAPI) NodeInfo() (*p2p.NodeInfo, error) {
   306  	server := api.node.Server()
   307  	if server == nil {
   308  		return nil, ErrNodeStopped
   309  	}
   310  	return server.NodeInfo(), nil
   311  }
   312  
   313  // Datadir retrieves the current data directory the node is using.
   314  func (api *adminAPI) Datadir() string {
   315  	return api.node.DataDir()
   316  }
   317  
   318  // web3API offers helper utils
   319  type web3API struct {
   320  	stack *Node
   321  }
   322  
   323  // ClientVersion returns the node name
   324  func (s *web3API) ClientVersion() string {
   325  	return s.stack.Server().Name
   326  }
   327  
   328  // Sha3 applies the ethereum sha3 implementation on the input.
   329  // It assumes the input is hex encoded.
   330  func (s *web3API) Sha3(input hexutil.Bytes) hexutil.Bytes {
   331  	return crypto.Keccak256(input)
   332  }