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