github.com/gobitfly/go-ethereum@v1.8.12/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 // StopWS 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.Counter: 312 root[name] = map[string]interface{}{ 313 "Overall": float64(metric.Count()), 314 } 315 316 case metrics.Meter: 317 root[name] = map[string]interface{}{ 318 "AvgRate01Min": metric.Rate1(), 319 "AvgRate05Min": metric.Rate5(), 320 "AvgRate15Min": metric.Rate15(), 321 "MeanRate": metric.RateMean(), 322 "Overall": float64(metric.Count()), 323 } 324 325 case metrics.Timer: 326 root[name] = map[string]interface{}{ 327 "AvgRate01Min": metric.Rate1(), 328 "AvgRate05Min": metric.Rate5(), 329 "AvgRate15Min": metric.Rate15(), 330 "MeanRate": metric.RateMean(), 331 "Overall": float64(metric.Count()), 332 "Percentiles": map[string]interface{}{ 333 "5": metric.Percentile(0.05), 334 "20": metric.Percentile(0.2), 335 "50": metric.Percentile(0.5), 336 "80": metric.Percentile(0.8), 337 "95": metric.Percentile(0.95), 338 }, 339 } 340 341 case metrics.ResettingTimer: 342 t := metric.Snapshot() 343 ps := t.Percentiles([]float64{5, 20, 50, 80, 95}) 344 root[name] = map[string]interface{}{ 345 "Measurements": len(t.Values()), 346 "Mean": t.Mean(), 347 "Percentiles": map[string]interface{}{ 348 "5": ps[0], 349 "20": ps[1], 350 "50": ps[2], 351 "80": ps[3], 352 "95": ps[4], 353 }, 354 } 355 356 default: 357 root[name] = "Unknown metric type" 358 } 359 } else { 360 switch metric := metric.(type) { 361 case metrics.Counter: 362 root[name] = map[string]interface{}{ 363 "Overall": float64(metric.Count()), 364 } 365 366 case metrics.Meter: 367 root[name] = map[string]interface{}{ 368 "Avg01Min": format(metric.Rate1()*60, metric.Rate1()), 369 "Avg05Min": format(metric.Rate5()*300, metric.Rate5()), 370 "Avg15Min": format(metric.Rate15()*900, metric.Rate15()), 371 "Overall": format(float64(metric.Count()), metric.RateMean()), 372 } 373 374 case metrics.Timer: 375 root[name] = map[string]interface{}{ 376 "Avg01Min": format(metric.Rate1()*60, metric.Rate1()), 377 "Avg05Min": format(metric.Rate5()*300, metric.Rate5()), 378 "Avg15Min": format(metric.Rate15()*900, metric.Rate15()), 379 "Overall": format(float64(metric.Count()), metric.RateMean()), 380 "Maximum": time.Duration(metric.Max()).String(), 381 "Minimum": time.Duration(metric.Min()).String(), 382 "Percentiles": map[string]interface{}{ 383 "5": time.Duration(metric.Percentile(0.05)).String(), 384 "20": time.Duration(metric.Percentile(0.2)).String(), 385 "50": time.Duration(metric.Percentile(0.5)).String(), 386 "80": time.Duration(metric.Percentile(0.8)).String(), 387 "95": time.Duration(metric.Percentile(0.95)).String(), 388 }, 389 } 390 391 case metrics.ResettingTimer: 392 t := metric.Snapshot() 393 ps := t.Percentiles([]float64{5, 20, 50, 80, 95}) 394 root[name] = map[string]interface{}{ 395 "Measurements": len(t.Values()), 396 "Mean": time.Duration(t.Mean()).String(), 397 "Percentiles": map[string]interface{}{ 398 "5": time.Duration(ps[0]).String(), 399 "20": time.Duration(ps[1]).String(), 400 "50": time.Duration(ps[2]).String(), 401 "80": time.Duration(ps[3]).String(), 402 "95": time.Duration(ps[4]).String(), 403 }, 404 } 405 406 default: 407 root[name] = "Unknown metric type" 408 } 409 } 410 }) 411 return counters, nil 412 } 413 414 // PublicWeb3API offers helper utils 415 type PublicWeb3API struct { 416 stack *Node 417 } 418 419 // NewPublicWeb3API creates a new Web3Service instance 420 func NewPublicWeb3API(stack *Node) *PublicWeb3API { 421 return &PublicWeb3API{stack} 422 } 423 424 // ClientVersion returns the node name 425 func (s *PublicWeb3API) ClientVersion() string { 426 return s.stack.Server().Name 427 } 428 429 // Sha3 applies the ethereum sha3 implementation on the input. 430 // It assumes the input is hex encoded. 431 func (s *PublicWeb3API) Sha3(input hexutil.Bytes) hexutil.Bytes { 432 return crypto.Keccak256(input) 433 }