github.com/luckypickle/go-ethereum-vet@v1.14.2/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/luckypickle/go-ethereum-vet/common/hexutil" 26 "github.com/luckypickle/go-ethereum-vet/crypto" 27 "github.com/luckypickle/go-ethereum-vet/metrics" 28 "github.com/luckypickle/go-ethereum-vet/p2p" 29 "github.com/luckypickle/go-ethereum-vet/p2p/discover" 30 "github.com/luckypickle/go-ethereum-vet/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 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 // AddTrustedPeer allows a remote node to always connect, even if slots are full 79 func (api *PrivateAdminAPI) AddTrustedPeer(url string) (bool, error) { 80 // Make sure the server is running, fail otherwise 81 server := api.node.Server() 82 if server == nil { 83 return false, ErrNodeStopped 84 } 85 node, err := discover.ParseNode(url) 86 if err != nil { 87 return false, fmt.Errorf("invalid enode: %v", err) 88 } 89 server.AddTrustedPeer(node) 90 return true, nil 91 } 92 93 // RemoveTrustedPeer removes a remote node from the trusted peer set, but it 94 // does not disconnect it automatically. 95 func (api *PrivateAdminAPI) RemoveTrustedPeer(url string) (bool, error) { 96 // Make sure the server is running, fail otherwise 97 server := api.node.Server() 98 if server == nil { 99 return false, ErrNodeStopped 100 } 101 node, err := discover.ParseNode(url) 102 if err != nil { 103 return false, fmt.Errorf("invalid enode: %v", err) 104 } 105 server.RemoveTrustedPeer(node) 106 return true, nil 107 } 108 109 // PeerEvents creates an RPC subscription which receives peer events from the 110 // node's p2p.Server 111 func (api *PrivateAdminAPI) PeerEvents(ctx context.Context) (*rpc.Subscription, error) { 112 // Make sure the server is running, fail otherwise 113 server := api.node.Server() 114 if server == nil { 115 return nil, ErrNodeStopped 116 } 117 118 // Create the subscription 119 notifier, supported := rpc.NotifierFromContext(ctx) 120 if !supported { 121 return nil, rpc.ErrNotificationsUnsupported 122 } 123 rpcSub := notifier.CreateSubscription() 124 125 go func() { 126 events := make(chan *p2p.PeerEvent) 127 sub := server.SubscribeEvents(events) 128 defer sub.Unsubscribe() 129 130 for { 131 select { 132 case event := <-events: 133 notifier.Notify(rpcSub.ID, event) 134 case <-sub.Err(): 135 return 136 case <-rpcSub.Err(): 137 return 138 case <-notifier.Closed(): 139 return 140 } 141 } 142 }() 143 144 return rpcSub, nil 145 } 146 147 // StartRPC starts the HTTP RPC API server. 148 func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis *string, vhosts *string) (bool, error) { 149 api.node.lock.Lock() 150 defer api.node.lock.Unlock() 151 152 if api.node.httpHandler != nil { 153 return false, fmt.Errorf("HTTP RPC already running on %s", api.node.httpEndpoint) 154 } 155 156 if host == nil { 157 h := DefaultHTTPHost 158 if api.node.config.HTTPHost != "" { 159 h = api.node.config.HTTPHost 160 } 161 host = &h 162 } 163 if port == nil { 164 port = &api.node.config.HTTPPort 165 } 166 167 allowedOrigins := api.node.config.HTTPCors 168 if cors != nil { 169 allowedOrigins = nil 170 for _, origin := range strings.Split(*cors, ",") { 171 allowedOrigins = append(allowedOrigins, strings.TrimSpace(origin)) 172 } 173 } 174 175 allowedVHosts := api.node.config.HTTPVirtualHosts 176 if vhosts != nil { 177 allowedVHosts = nil 178 for _, vhost := range strings.Split(*host, ",") { 179 allowedVHosts = append(allowedVHosts, strings.TrimSpace(vhost)) 180 } 181 } 182 183 modules := api.node.httpWhitelist 184 if apis != nil { 185 modules = nil 186 for _, m := range strings.Split(*apis, ",") { 187 modules = append(modules, strings.TrimSpace(m)) 188 } 189 } 190 191 if err := api.node.startHTTP(fmt.Sprintf("%s:%d", *host, *port), api.node.rpcAPIs, modules, allowedOrigins, allowedVHosts, api.node.config.HTTPTimeouts); err != nil { 192 return false, err 193 } 194 return true, nil 195 } 196 197 // StopRPC terminates an already running HTTP RPC API endpoint. 198 func (api *PrivateAdminAPI) StopRPC() (bool, error) { 199 api.node.lock.Lock() 200 defer api.node.lock.Unlock() 201 202 if api.node.httpHandler == nil { 203 return false, fmt.Errorf("HTTP RPC not running") 204 } 205 api.node.stopHTTP() 206 return true, nil 207 } 208 209 // StartWS starts the websocket RPC API server. 210 func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *string, apis *string) (bool, error) { 211 api.node.lock.Lock() 212 defer api.node.lock.Unlock() 213 214 if api.node.wsHandler != nil { 215 return false, fmt.Errorf("WebSocket RPC already running on %s", api.node.wsEndpoint) 216 } 217 218 if host == nil { 219 h := DefaultWSHost 220 if api.node.config.WSHost != "" { 221 h = api.node.config.WSHost 222 } 223 host = &h 224 } 225 if port == nil { 226 port = &api.node.config.WSPort 227 } 228 229 origins := api.node.config.WSOrigins 230 if allowedOrigins != nil { 231 origins = nil 232 for _, origin := range strings.Split(*allowedOrigins, ",") { 233 origins = append(origins, strings.TrimSpace(origin)) 234 } 235 } 236 237 modules := api.node.config.WSModules 238 if apis != nil { 239 modules = nil 240 for _, m := range strings.Split(*apis, ",") { 241 modules = append(modules, strings.TrimSpace(m)) 242 } 243 } 244 245 if err := api.node.startWS(fmt.Sprintf("%s:%d", *host, *port), api.node.rpcAPIs, modules, origins, api.node.config.WSExposeAll); err != nil { 246 return false, err 247 } 248 return true, nil 249 } 250 251 // StopWS terminates an already running websocket RPC API endpoint. 252 func (api *PrivateAdminAPI) StopWS() (bool, error) { 253 api.node.lock.Lock() 254 defer api.node.lock.Unlock() 255 256 if api.node.wsHandler == nil { 257 return false, fmt.Errorf("WebSocket RPC not running") 258 } 259 api.node.stopWS() 260 return true, nil 261 } 262 263 // PublicAdminAPI is the collection of administrative API methods exposed over 264 // both secure and unsecure RPC channels. 265 type PublicAdminAPI struct { 266 node *Node // Node interfaced by this API 267 } 268 269 // NewPublicAdminAPI creates a new API definition for the public admin methods 270 // of the node itself. 271 func NewPublicAdminAPI(node *Node) *PublicAdminAPI { 272 return &PublicAdminAPI{node: node} 273 } 274 275 // Peers retrieves all the information we know about each individual peer at the 276 // protocol granularity. 277 func (api *PublicAdminAPI) Peers() ([]*p2p.PeerInfo, error) { 278 server := api.node.Server() 279 if server == nil { 280 return nil, ErrNodeStopped 281 } 282 return server.PeersInfo(), nil 283 } 284 285 // NodeInfo retrieves all the information we know about the host node at the 286 // protocol granularity. 287 func (api *PublicAdminAPI) NodeInfo() (*p2p.NodeInfo, error) { 288 server := api.node.Server() 289 if server == nil { 290 return nil, ErrNodeStopped 291 } 292 return server.NodeInfo(), nil 293 } 294 295 // Datadir retrieves the current data directory the node is using. 296 func (api *PublicAdminAPI) Datadir() string { 297 return api.node.DataDir() 298 } 299 300 // PublicDebugAPI is the collection of debugging related API methods exposed over 301 // both secure and unsecure RPC channels. 302 type PublicDebugAPI struct { 303 node *Node // Node interfaced by this API 304 } 305 306 // NewPublicDebugAPI creates a new API definition for the public debug methods 307 // of the node itself. 308 func NewPublicDebugAPI(node *Node) *PublicDebugAPI { 309 return &PublicDebugAPI{node: node} 310 } 311 312 // Metrics retrieves all the known system metric collected by the node. 313 func (api *PublicDebugAPI) Metrics(raw bool) (map[string]interface{}, error) { 314 // Create a rate formatter 315 units := []string{"", "K", "M", "G", "T", "E", "P"} 316 round := func(value float64, prec int) string { 317 unit := 0 318 for value >= 1000 { 319 unit, value, prec = unit+1, value/1000, 2 320 } 321 return fmt.Sprintf(fmt.Sprintf("%%.%df%s", prec, units[unit]), value) 322 } 323 format := func(total float64, rate float64) string { 324 return fmt.Sprintf("%s (%s/s)", round(total, 0), round(rate, 2)) 325 } 326 // Iterate over all the metrics, and just dump for now 327 counters := make(map[string]interface{}) 328 metrics.DefaultRegistry.Each(func(name string, metric interface{}) { 329 // Create or retrieve the counter hierarchy for this metric 330 root, parts := counters, strings.Split(name, "/") 331 for _, part := range parts[:len(parts)-1] { 332 if _, ok := root[part]; !ok { 333 root[part] = make(map[string]interface{}) 334 } 335 root = root[part].(map[string]interface{}) 336 } 337 name = parts[len(parts)-1] 338 339 // Fill the counter with the metric details, formatting if requested 340 if raw { 341 switch metric := metric.(type) { 342 case metrics.Counter: 343 root[name] = map[string]interface{}{ 344 "Overall": float64(metric.Count()), 345 } 346 347 case metrics.Meter: 348 root[name] = map[string]interface{}{ 349 "AvgRate01Min": metric.Rate1(), 350 "AvgRate05Min": metric.Rate5(), 351 "AvgRate15Min": metric.Rate15(), 352 "MeanRate": metric.RateMean(), 353 "Overall": float64(metric.Count()), 354 } 355 356 case metrics.Timer: 357 root[name] = map[string]interface{}{ 358 "AvgRate01Min": metric.Rate1(), 359 "AvgRate05Min": metric.Rate5(), 360 "AvgRate15Min": metric.Rate15(), 361 "MeanRate": metric.RateMean(), 362 "Overall": float64(metric.Count()), 363 "Percentiles": map[string]interface{}{ 364 "5": metric.Percentile(0.05), 365 "20": metric.Percentile(0.2), 366 "50": metric.Percentile(0.5), 367 "80": metric.Percentile(0.8), 368 "95": metric.Percentile(0.95), 369 }, 370 } 371 372 case metrics.ResettingTimer: 373 t := metric.Snapshot() 374 ps := t.Percentiles([]float64{5, 20, 50, 80, 95}) 375 root[name] = map[string]interface{}{ 376 "Measurements": len(t.Values()), 377 "Mean": t.Mean(), 378 "Percentiles": map[string]interface{}{ 379 "5": ps[0], 380 "20": ps[1], 381 "50": ps[2], 382 "80": ps[3], 383 "95": ps[4], 384 }, 385 } 386 387 default: 388 root[name] = "Unknown metric type" 389 } 390 } else { 391 switch metric := metric.(type) { 392 case metrics.Counter: 393 root[name] = map[string]interface{}{ 394 "Overall": float64(metric.Count()), 395 } 396 397 case metrics.Meter: 398 root[name] = map[string]interface{}{ 399 "Avg01Min": format(metric.Rate1()*60, metric.Rate1()), 400 "Avg05Min": format(metric.Rate5()*300, metric.Rate5()), 401 "Avg15Min": format(metric.Rate15()*900, metric.Rate15()), 402 "Overall": format(float64(metric.Count()), metric.RateMean()), 403 } 404 405 case metrics.Timer: 406 root[name] = map[string]interface{}{ 407 "Avg01Min": format(metric.Rate1()*60, metric.Rate1()), 408 "Avg05Min": format(metric.Rate5()*300, metric.Rate5()), 409 "Avg15Min": format(metric.Rate15()*900, metric.Rate15()), 410 "Overall": format(float64(metric.Count()), metric.RateMean()), 411 "Maximum": time.Duration(metric.Max()).String(), 412 "Minimum": time.Duration(metric.Min()).String(), 413 "Percentiles": map[string]interface{}{ 414 "5": time.Duration(metric.Percentile(0.05)).String(), 415 "20": time.Duration(metric.Percentile(0.2)).String(), 416 "50": time.Duration(metric.Percentile(0.5)).String(), 417 "80": time.Duration(metric.Percentile(0.8)).String(), 418 "95": time.Duration(metric.Percentile(0.95)).String(), 419 }, 420 } 421 422 case metrics.ResettingTimer: 423 t := metric.Snapshot() 424 ps := t.Percentiles([]float64{5, 20, 50, 80, 95}) 425 root[name] = map[string]interface{}{ 426 "Measurements": len(t.Values()), 427 "Mean": time.Duration(t.Mean()).String(), 428 "Percentiles": map[string]interface{}{ 429 "5": time.Duration(ps[0]).String(), 430 "20": time.Duration(ps[1]).String(), 431 "50": time.Duration(ps[2]).String(), 432 "80": time.Duration(ps[3]).String(), 433 "95": time.Duration(ps[4]).String(), 434 }, 435 } 436 437 default: 438 root[name] = "Unknown metric type" 439 } 440 } 441 }) 442 return counters, nil 443 } 444 445 // PublicWeb3API offers helper utils 446 type PublicWeb3API struct { 447 stack *Node 448 } 449 450 // NewPublicWeb3API creates a new Web3Service instance 451 func NewPublicWeb3API(stack *Node) *PublicWeb3API { 452 return &PublicWeb3API{stack} 453 } 454 455 // ClientVersion returns the node name 456 func (s *PublicWeb3API) ClientVersion() string { 457 return s.stack.Server().Name 458 } 459 460 // Sha3 applies the ethereum sha3 implementation on the input. 461 // It assumes the input is hex encoded. 462 func (s *PublicWeb3API) Sha3(input hexutil.Bytes) hexutil.Bytes { 463 return crypto.Keccak256(input) 464 }