github.com/ylsGit/go-ethereum@v1.6.5/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 "fmt" 21 "strings" 22 "time" 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/discover" 28 "github.com/rcrowley/go-metrics" 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 := discover.ParseNode(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 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 := discover.ParseNode(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 // StartRPC starts the HTTP RPC API server. 77 func (api *PrivateAdminAPI) StartRPC(host *string, port *int, cors *string, apis *string) (bool, error) { 78 api.node.lock.Lock() 79 defer api.node.lock.Unlock() 80 81 if api.node.httpHandler != nil { 82 return false, fmt.Errorf("HTTP RPC already running on %s", api.node.httpEndpoint) 83 } 84 85 if host == nil { 86 h := DefaultHTTPHost 87 if api.node.config.HTTPHost != "" { 88 h = api.node.config.HTTPHost 89 } 90 host = &h 91 } 92 if port == nil { 93 port = &api.node.config.HTTPPort 94 } 95 96 allowedOrigins := api.node.config.HTTPCors 97 if cors != nil { 98 allowedOrigins = nil 99 for _, origin := range strings.Split(*cors, ",") { 100 allowedOrigins = append(allowedOrigins, strings.TrimSpace(origin)) 101 } 102 } 103 104 modules := api.node.httpWhitelist 105 if apis != nil { 106 modules = nil 107 for _, m := range strings.Split(*apis, ",") { 108 modules = append(modules, strings.TrimSpace(m)) 109 } 110 } 111 112 if err := api.node.startHTTP(fmt.Sprintf("%s:%d", *host, *port), api.node.rpcAPIs, modules, allowedOrigins); err != nil { 113 return false, err 114 } 115 return true, nil 116 } 117 118 // StopRPC terminates an already running HTTP RPC API endpoint. 119 func (api *PrivateAdminAPI) StopRPC() (bool, error) { 120 api.node.lock.Lock() 121 defer api.node.lock.Unlock() 122 123 if api.node.httpHandler == nil { 124 return false, fmt.Errorf("HTTP RPC not running") 125 } 126 api.node.stopHTTP() 127 return true, nil 128 } 129 130 // StartWS starts the websocket RPC API server. 131 func (api *PrivateAdminAPI) StartWS(host *string, port *int, allowedOrigins *string, apis *string) (bool, error) { 132 api.node.lock.Lock() 133 defer api.node.lock.Unlock() 134 135 if api.node.wsHandler != nil { 136 return false, fmt.Errorf("WebSocket RPC already running on %s", api.node.wsEndpoint) 137 } 138 139 if host == nil { 140 h := DefaultWSHost 141 if api.node.config.WSHost != "" { 142 h = api.node.config.WSHost 143 } 144 host = &h 145 } 146 if port == nil { 147 port = &api.node.config.WSPort 148 } 149 150 origins := api.node.config.WSOrigins 151 if allowedOrigins != nil { 152 origins = nil 153 for _, origin := range strings.Split(*allowedOrigins, ",") { 154 origins = append(origins, strings.TrimSpace(origin)) 155 } 156 } 157 158 modules := api.node.config.WSModules 159 if apis != nil { 160 modules = nil 161 for _, m := range strings.Split(*apis, ",") { 162 modules = append(modules, strings.TrimSpace(m)) 163 } 164 } 165 166 if err := api.node.startWS(fmt.Sprintf("%s:%d", *host, *port), api.node.rpcAPIs, modules, origins); err != nil { 167 return false, err 168 } 169 return true, nil 170 } 171 172 // StopRPC terminates an already running websocket RPC API endpoint. 173 func (api *PrivateAdminAPI) StopWS() (bool, error) { 174 api.node.lock.Lock() 175 defer api.node.lock.Unlock() 176 177 if api.node.wsHandler == nil { 178 return false, fmt.Errorf("WebSocket RPC not running") 179 } 180 api.node.stopWS() 181 return true, nil 182 } 183 184 // PublicAdminAPI is the collection of administrative API methods exposed over 185 // both secure and unsecure RPC channels. 186 type PublicAdminAPI struct { 187 node *Node // Node interfaced by this API 188 } 189 190 // NewPublicAdminAPI creates a new API definition for the public admin methods 191 // of the node itself. 192 func NewPublicAdminAPI(node *Node) *PublicAdminAPI { 193 return &PublicAdminAPI{node: node} 194 } 195 196 // Peers retrieves all the information we know about each individual peer at the 197 // protocol granularity. 198 func (api *PublicAdminAPI) Peers() ([]*p2p.PeerInfo, error) { 199 server := api.node.Server() 200 if server == nil { 201 return nil, ErrNodeStopped 202 } 203 return server.PeersInfo(), nil 204 } 205 206 // NodeInfo retrieves all the information we know about the host node at the 207 // protocol granularity. 208 func (api *PublicAdminAPI) NodeInfo() (*p2p.NodeInfo, error) { 209 server := api.node.Server() 210 if server == nil { 211 return nil, ErrNodeStopped 212 } 213 return server.NodeInfo(), nil 214 } 215 216 // Datadir retrieves the current data directory the node is using. 217 func (api *PublicAdminAPI) Datadir() string { 218 return api.node.DataDir() 219 } 220 221 // PublicDebugAPI is the collection of debugging related API methods exposed over 222 // both secure and unsecure RPC channels. 223 type PublicDebugAPI struct { 224 node *Node // Node interfaced by this API 225 } 226 227 // NewPublicDebugAPI creates a new API definition for the public debug methods 228 // of the node itself. 229 func NewPublicDebugAPI(node *Node) *PublicDebugAPI { 230 return &PublicDebugAPI{node: node} 231 } 232 233 // Metrics retrieves all the known system metric collected by the node. 234 func (api *PublicDebugAPI) Metrics(raw bool) (map[string]interface{}, error) { 235 // Create a rate formatter 236 units := []string{"", "K", "M", "G", "T", "E", "P"} 237 round := func(value float64, prec int) string { 238 unit := 0 239 for value >= 1000 { 240 unit, value, prec = unit+1, value/1000, 2 241 } 242 return fmt.Sprintf(fmt.Sprintf("%%.%df%s", prec, units[unit]), value) 243 } 244 format := func(total float64, rate float64) string { 245 return fmt.Sprintf("%s (%s/s)", round(total, 0), round(rate, 2)) 246 } 247 // Iterate over all the metrics, and just dump for now 248 counters := make(map[string]interface{}) 249 metrics.DefaultRegistry.Each(func(name string, metric interface{}) { 250 // Create or retrieve the counter hierarchy for this metric 251 root, parts := counters, strings.Split(name, "/") 252 for _, part := range parts[:len(parts)-1] { 253 if _, ok := root[part]; !ok { 254 root[part] = make(map[string]interface{}) 255 } 256 root = root[part].(map[string]interface{}) 257 } 258 name = parts[len(parts)-1] 259 260 // Fill the counter with the metric details, formatting if requested 261 if raw { 262 switch metric := metric.(type) { 263 case metrics.Meter: 264 root[name] = map[string]interface{}{ 265 "AvgRate01Min": metric.Rate1(), 266 "AvgRate05Min": metric.Rate5(), 267 "AvgRate15Min": metric.Rate15(), 268 "MeanRate": metric.RateMean(), 269 "Overall": float64(metric.Count()), 270 } 271 272 case metrics.Timer: 273 root[name] = map[string]interface{}{ 274 "AvgRate01Min": metric.Rate1(), 275 "AvgRate05Min": metric.Rate5(), 276 "AvgRate15Min": metric.Rate15(), 277 "MeanRate": metric.RateMean(), 278 "Overall": float64(metric.Count()), 279 "Percentiles": map[string]interface{}{ 280 "5": metric.Percentile(0.05), 281 "20": metric.Percentile(0.2), 282 "50": metric.Percentile(0.5), 283 "80": metric.Percentile(0.8), 284 "95": metric.Percentile(0.95), 285 }, 286 } 287 288 default: 289 root[name] = "Unknown metric type" 290 } 291 } else { 292 switch metric := metric.(type) { 293 case metrics.Meter: 294 root[name] = map[string]interface{}{ 295 "Avg01Min": format(metric.Rate1()*60, metric.Rate1()), 296 "Avg05Min": format(metric.Rate5()*300, metric.Rate5()), 297 "Avg15Min": format(metric.Rate15()*900, metric.Rate15()), 298 "Overall": format(float64(metric.Count()), metric.RateMean()), 299 } 300 301 case metrics.Timer: 302 root[name] = map[string]interface{}{ 303 "Avg01Min": format(metric.Rate1()*60, metric.Rate1()), 304 "Avg05Min": format(metric.Rate5()*300, metric.Rate5()), 305 "Avg15Min": format(metric.Rate15()*900, metric.Rate15()), 306 "Overall": format(float64(metric.Count()), metric.RateMean()), 307 "Maximum": time.Duration(metric.Max()).String(), 308 "Minimum": time.Duration(metric.Min()).String(), 309 "Percentiles": map[string]interface{}{ 310 "5": time.Duration(metric.Percentile(0.05)).String(), 311 "20": time.Duration(metric.Percentile(0.2)).String(), 312 "50": time.Duration(metric.Percentile(0.5)).String(), 313 "80": time.Duration(metric.Percentile(0.8)).String(), 314 "95": time.Duration(metric.Percentile(0.95)).String(), 315 }, 316 } 317 318 default: 319 root[name] = "Unknown metric type" 320 } 321 } 322 }) 323 return counters, nil 324 } 325 326 // PublicWeb3API offers helper utils 327 type PublicWeb3API struct { 328 stack *Node 329 } 330 331 // NewPublicWeb3API creates a new Web3Service instance 332 func NewPublicWeb3API(stack *Node) *PublicWeb3API { 333 return &PublicWeb3API{stack} 334 } 335 336 // ClientVersion returns the node name 337 func (s *PublicWeb3API) ClientVersion() string { 338 return s.stack.Server().Name 339 } 340 341 // Sha3 applies the ethereum sha3 implementation on the input. 342 // It assumes the input is hex encoded. 343 func (s *PublicWeb3API) Sha3(input hexutil.Bytes) hexutil.Bytes { 344 return crypto.Keccak256(input) 345 }