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