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