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