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