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