github.com/cxptek/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 }