github.com/4000d/go-ethereum@v1.8.2-0.20180223170251-423c8bb1d821/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 "time" 24 25 "github.com/ethereum/go-ethereum/common/hexutil" 26 "github.com/ethereum/go-ethereum/crypto" 27 "github.com/ethereum/go-ethereum/metrics" 28 "github.com/ethereum/go-ethereum/p2p" 29 "github.com/ethereum/go-ethereum/p2p/discover" 30 "github.com/ethereum/go-ethereum/rpc" 31 ) 32 33 // PrivateAdminAPI is the collection of administrative API methods exposed only 34 // over a secure RPC channel. 35 type PrivateAdminAPI struct { 36 node *Node // Node interfaced by this API 37 } 38 39 // NewPrivateAdminAPI creates a new API definition for the private admin methods 40 // of the node itself. 41 func NewPrivateAdminAPI(node *Node) *PrivateAdminAPI { 42 return &PrivateAdminAPI{node: node} 43 } 44 45 // AddPeer requests connecting to a remote node, and also maintaining the new 46 // connection at all times, even reconnecting if it is lost. 47 func (api *PrivateAdminAPI) AddPeer(url string) (bool, error) { 48 // Make sure the server is running, fail otherwise 49 server := api.node.Server() 50 if server == nil { 51 return false, ErrNodeStopped 52 } 53 // Try to add the url as a static peer and return 54 node, err := discover.ParseNode(url) 55 if err != nil { 56 return false, fmt.Errorf("invalid enode: %v", err) 57 } 58 server.AddPeer(node) 59 return true, nil 60 } 61 62 // RemovePeer disconnects from a a remote node if the connection exists 63 func (api *PrivateAdminAPI) RemovePeer(url string) (bool, error) { 64 // Make sure the server is running, fail otherwise 65 server := api.node.Server() 66 if server == nil { 67 return false, ErrNodeStopped 68 } 69 // Try to remove the url as a static peer and return 70 node, err := discover.ParseNode(url) 71 if err != nil { 72 return false, fmt.Errorf("invalid enode: %v", err) 73 } 74 server.RemovePeer(node) 75 return true, nil 76 } 77 78 // PeerEvents creates an RPC subscription which receives peer events from the 79 // node's p2p.Server 80 func (api *PrivateAdminAPI) PeerEvents(ctx context.Context) (*rpc.Subscription, error) { 81 // Make sure the server is running, fail otherwise 82 server := api.node.Server() 83 if server == nil { 84 return nil, ErrNodeStopped 85 } 86 87 // Create the subscription 88 notifier, supported := rpc.NotifierFromContext(ctx) 89 if !supported { 90 return nil, rpc.ErrNotificationsUnsupported 91 } 92 rpcSub := notifier.CreateSubscription() 93 94 go func() { 95 events := make(chan *p2p.PeerEvent) 96 sub := server.SubscribeEvents(events) 97 defer sub.Unsubscribe() 98 99 for { 100 select { 101 case event := <-events: 102 notifier.Notify(rpcSub.ID, event) 103 case <-sub.Err(): 104 return 105 case <-rpcSub.Err(): 106 return 107 case <-notifier.Closed(): 108 return 109 } 110 } 111 }() 112 113 return rpcSub, nil 114 } 115 116 // StartRPC starts the HTTP RPC API server. 117 func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis *string, vhosts *string) (bool, error) { 118 api.node.lock.Lock() 119 defer api.node.lock.Unlock() 120 121 if api.node.httpHandler != nil { 122 return false, fmt.Errorf("HTTP RPC already running on %s", api.node.httpEndpoint) 123 } 124 125 if host == nil { 126 h := DefaultHTTPHost 127 if api.node.config.HTTPHost != "" { 128 h = api.node.config.HTTPHost 129 } 130 host = &h 131 } 132 if port == nil { 133 port = &api.node.config.HTTPPort 134 } 135 136 allowedOrigins := api.node.config.HTTPCors 137 if cors != nil { 138 allowedOrigins = nil 139 for _, origin := range strings.Split(*cors, ",") { 140 allowedOrigins = append(allowedOrigins, strings.TrimSpace(origin)) 141 } 142 } 143 144 allowedVHosts := api.node.config.HTTPVirtualHosts 145 if vhosts != nil { 146 allowedVHosts = nil 147 for _, vhost := range strings.Split(*host, ",") { 148 allowedVHosts = append(allowedVHosts, strings.TrimSpace(vhost)) 149 } 150 } 151 152 modules := api.node.httpWhitelist 153 if apis != nil { 154 modules = nil 155 for _, m := range strings.Split(*apis, ",") { 156 modules = append(modules, strings.TrimSpace(m)) 157 } 158 } 159 160 if err := api.node.startHTTP(fmt.Sprintf("%s:%d", *host, *port), api.node.rpcAPIs, modules, allowedOrigins, allowedVHosts); err != nil { 161 return false, err 162 } 163 return true, nil 164 } 165 166 // StopRPC terminates an already running HTTP RPC API endpoint. 167 func (api *PrivateAdminAPI) StopRPC() (bool, error) { 168 api.node.lock.Lock() 169 defer api.node.lock.Unlock() 170 171 if api.node.httpHandler == nil { 172 return false, fmt.Errorf("HTTP RPC not running") 173 } 174 api.node.stopHTTP() 175 return true, nil 176 } 177 178 // StartWS starts the websocket RPC API server. 179 func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *string, apis *string) (bool, error) { 180 api.node.lock.Lock() 181 defer api.node.lock.Unlock() 182 183 if api.node.wsHandler != nil { 184 return false, fmt.Errorf("WebSocket RPC already running on %s", api.node.wsEndpoint) 185 } 186 187 if host == nil { 188 h := DefaultWSHost 189 if api.node.config.WSHost != "" { 190 h = api.node.config.WSHost 191 } 192 host = &h 193 } 194 if port == nil { 195 port = &api.node.config.WSPort 196 } 197 198 origins := api.node.config.WSOrigins 199 if allowedOrigins != nil { 200 origins = nil 201 for _, origin := range strings.Split(*allowedOrigins, ",") { 202 origins = append(origins, strings.TrimSpace(origin)) 203 } 204 } 205 206 modules := api.node.config.WSModules 207 if apis != nil { 208 modules = nil 209 for _, m := range strings.Split(*apis, ",") { 210 modules = append(modules, strings.TrimSpace(m)) 211 } 212 } 213 214 if err := api.node.startWS(fmt.Sprintf("%s:%d", *host, *port), api.node.rpcAPIs, modules, origins, api.node.config.WSExposeAll); err != nil { 215 return false, err 216 } 217 return true, nil 218 } 219 220 // StopRPC terminates an already running websocket RPC API endpoint. 221 func (api *PrivateAdminAPI) StopWS() (bool, error) { 222 api.node.lock.Lock() 223 defer api.node.lock.Unlock() 224 225 if api.node.wsHandler == nil { 226 return false, fmt.Errorf("WebSocket RPC not running") 227 } 228 api.node.stopWS() 229 return true, nil 230 } 231 232 // PublicAdminAPI is the collection of administrative API methods exposed over 233 // both secure and unsecure RPC channels. 234 type PublicAdminAPI struct { 235 node *Node // Node interfaced by this API 236 } 237 238 // NewPublicAdminAPI creates a new API definition for the public admin methods 239 // of the node itself. 240 func NewPublicAdminAPI(node *Node) *PublicAdminAPI { 241 return &PublicAdminAPI{node: node} 242 } 243 244 // Peers retrieves all the information we know about each individual peer at the 245 // protocol granularity. 246 func (api *PublicAdminAPI) Peers() ([]*p2p.PeerInfo, error) { 247 server := api.node.Server() 248 if server == nil { 249 return nil, ErrNodeStopped 250 } 251 return server.PeersInfo(), nil 252 } 253 254 // NodeInfo retrieves all the information we know about the host node at the 255 // protocol granularity. 256 func (api *PublicAdminAPI) NodeInfo() (*p2p.NodeInfo, error) { 257 server := api.node.Server() 258 if server == nil { 259 return nil, ErrNodeStopped 260 } 261 return server.NodeInfo(), nil 262 } 263 264 // Datadir retrieves the current data directory the node is using. 265 func (api *PublicAdminAPI) Datadir() string { 266 return api.node.DataDir() 267 } 268 269 // PublicDebugAPI is the collection of debugging related API methods exposed over 270 // both secure and unsecure RPC channels. 271 type PublicDebugAPI struct { 272 node *Node // Node interfaced by this API 273 } 274 275 // NewPublicDebugAPI creates a new API definition for the public debug methods 276 // of the node itself. 277 func NewPublicDebugAPI(node *Node) *PublicDebugAPI { 278 return &PublicDebugAPI{node: node} 279 } 280 281 // Metrics retrieves all the known system metric collected by the node. 282 func (api *PublicDebugAPI) Metrics(raw bool) (map[string]interface{}, error) { 283 // Create a rate formatter 284 units := []string{"", "K", "M", "G", "T", "E", "P"} 285 round := func(value float64, prec int) string { 286 unit := 0 287 for value >= 1000 { 288 unit, value, prec = unit+1, value/1000, 2 289 } 290 return fmt.Sprintf(fmt.Sprintf("%%.%df%s", prec, units[unit]), value) 291 } 292 format := func(total float64, rate float64) string { 293 return fmt.Sprintf("%s (%s/s)", round(total, 0), round(rate, 2)) 294 } 295 // Iterate over all the metrics, and just dump for now 296 counters := make(map[string]interface{}) 297 metrics.DefaultRegistry.Each(func(name string, metric interface{}) { 298 // Create or retrieve the counter hierarchy for this metric 299 root, parts := counters, strings.Split(name, "/") 300 for _, part := range parts[:len(parts)-1] { 301 if _, ok := root[part]; !ok { 302 root[part] = make(map[string]interface{}) 303 } 304 root = root[part].(map[string]interface{}) 305 } 306 name = parts[len(parts)-1] 307 308 // Fill the counter with the metric details, formatting if requested 309 if raw { 310 switch metric := metric.(type) { 311 case metrics.Meter: 312 root[name] = map[string]interface{}{ 313 "AvgRate01Min": metric.Rate1(), 314 "AvgRate05Min": metric.Rate5(), 315 "AvgRate15Min": metric.Rate15(), 316 "MeanRate": metric.RateMean(), 317 "Overall": float64(metric.Count()), 318 } 319 320 case metrics.Timer: 321 root[name] = map[string]interface{}{ 322 "AvgRate01Min": metric.Rate1(), 323 "AvgRate05Min": metric.Rate5(), 324 "AvgRate15Min": metric.Rate15(), 325 "MeanRate": metric.RateMean(), 326 "Overall": float64(metric.Count()), 327 "Percentiles": map[string]interface{}{ 328 "5": metric.Percentile(0.05), 329 "20": metric.Percentile(0.2), 330 "50": metric.Percentile(0.5), 331 "80": metric.Percentile(0.8), 332 "95": metric.Percentile(0.95), 333 }, 334 } 335 336 default: 337 root[name] = "Unknown metric type" 338 } 339 } else { 340 switch metric := metric.(type) { 341 case metrics.Meter: 342 root[name] = map[string]interface{}{ 343 "Avg01Min": format(metric.Rate1()*60, metric.Rate1()), 344 "Avg05Min": format(metric.Rate5()*300, metric.Rate5()), 345 "Avg15Min": format(metric.Rate15()*900, metric.Rate15()), 346 "Overall": format(float64(metric.Count()), metric.RateMean()), 347 } 348 349 case metrics.Timer: 350 root[name] = map[string]interface{}{ 351 "Avg01Min": format(metric.Rate1()*60, metric.Rate1()), 352 "Avg05Min": format(metric.Rate5()*300, metric.Rate5()), 353 "Avg15Min": format(metric.Rate15()*900, metric.Rate15()), 354 "Overall": format(float64(metric.Count()), metric.RateMean()), 355 "Maximum": time.Duration(metric.Max()).String(), 356 "Minimum": time.Duration(metric.Min()).String(), 357 "Percentiles": map[string]interface{}{ 358 "5": time.Duration(metric.Percentile(0.05)).String(), 359 "20": time.Duration(metric.Percentile(0.2)).String(), 360 "50": time.Duration(metric.Percentile(0.5)).String(), 361 "80": time.Duration(metric.Percentile(0.8)).String(), 362 "95": time.Duration(metric.Percentile(0.95)).String(), 363 }, 364 } 365 366 default: 367 root[name] = "Unknown metric type" 368 } 369 } 370 }) 371 return counters, nil 372 } 373 374 // PublicWeb3API offers helper utils 375 type PublicWeb3API struct { 376 stack *Node 377 } 378 379 // NewPublicWeb3API creates a new Web3Service instance 380 func NewPublicWeb3API(stack *Node) *PublicWeb3API { 381 return &PublicWeb3API{stack} 382 } 383 384 // ClientVersion returns the node name 385 func (s *PublicWeb3API) ClientVersion() string { 386 return s.stack.Server().Name 387 } 388 389 // Sha3 applies the ethereum sha3 implementation on the input. 390 // It assumes the input is hex encoded. 391 func (s *PublicWeb3API) Sha3(input hexutil.Bytes) hexutil.Bytes { 392 return crypto.Keccak256(input) 393 }