api.go 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  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. package node
  17. import (
  18. "context"
  19. "fmt"
  20. "strings"
  21. "github.com/ethereum/go-ethereum/common/gopool"
  22. "github.com/ethereum/go-ethereum/common/hexutil"
  23. "github.com/ethereum/go-ethereum/crypto"
  24. "github.com/ethereum/go-ethereum/internal/debug"
  25. "github.com/ethereum/go-ethereum/log"
  26. "github.com/ethereum/go-ethereum/p2p"
  27. "github.com/ethereum/go-ethereum/p2p/enode"
  28. "github.com/ethereum/go-ethereum/rpc"
  29. )
  30. // apis returns the collection of built-in RPC APIs.
  31. func (n *Node) apis() []rpc.API {
  32. return []rpc.API{
  33. {
  34. Namespace: "admin",
  35. Version: "1.0",
  36. Service: &privateAdminAPI{n},
  37. }, {
  38. Namespace: "admin",
  39. Version: "1.0",
  40. Service: &publicAdminAPI{n},
  41. Public: true,
  42. }, {
  43. Namespace: "debug",
  44. Version: "1.0",
  45. Service: debug.Handler,
  46. }, {
  47. Namespace: "web3",
  48. Version: "1.0",
  49. Service: &publicWeb3API{n},
  50. Public: true,
  51. },
  52. }
  53. }
  54. // privateAdminAPI is the collection of administrative API methods exposed only
  55. // over a secure RPC channel.
  56. type privateAdminAPI struct {
  57. node *Node // Node interfaced by this API
  58. }
  59. // AddPeer requests connecting to a remote node, and also maintaining the new
  60. // connection at all times, even reconnecting if it is lost.
  61. func (api *privateAdminAPI) AddPeer(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 add the url as a static peer and return
  68. node, err := enode.Parse(enode.ValidSchemes, url)
  69. if err != nil {
  70. return false, fmt.Errorf("invalid enode: %v", err)
  71. }
  72. server.AddPeer(node)
  73. return true, nil
  74. }
  75. // RemovePeer disconnects from a remote node if the connection exists
  76. func (api *privateAdminAPI) RemovePeer(url string) (bool, error) {
  77. // Make sure the server is running, fail otherwise
  78. server := api.node.Server()
  79. if server == nil {
  80. return false, ErrNodeStopped
  81. }
  82. // Try to remove the url as a static peer and return
  83. node, err := enode.Parse(enode.ValidSchemes, url)
  84. if err != nil {
  85. return false, fmt.Errorf("invalid enode: %v", err)
  86. }
  87. server.RemovePeer(node)
  88. return true, nil
  89. }
  90. // AddTrustedPeer allows a remote node to always connect, even if slots are full
  91. func (api *privateAdminAPI) AddTrustedPeer(url string) (bool, error) {
  92. // Make sure the server is running, fail otherwise
  93. server := api.node.Server()
  94. if server == nil {
  95. return false, ErrNodeStopped
  96. }
  97. node, err := enode.Parse(enode.ValidSchemes, url)
  98. if err != nil {
  99. return false, fmt.Errorf("invalid enode: %v", err)
  100. }
  101. server.AddTrustedPeer(node)
  102. return true, nil
  103. }
  104. // RemoveTrustedPeer removes a remote node from the trusted peer set, but it
  105. // does not disconnect it automatically.
  106. func (api *privateAdminAPI) RemoveTrustedPeer(url string) (bool, error) {
  107. // Make sure the server is running, fail otherwise
  108. server := api.node.Server()
  109. if server == nil {
  110. return false, ErrNodeStopped
  111. }
  112. node, err := enode.Parse(enode.ValidSchemes, url)
  113. if err != nil {
  114. return false, fmt.Errorf("invalid enode: %v", err)
  115. }
  116. server.RemoveTrustedPeer(node)
  117. return true, nil
  118. }
  119. // PeerEvents creates an RPC subscription which receives peer events from the
  120. // node's p2p.Server
  121. func (api *privateAdminAPI) PeerEvents(ctx context.Context) (*rpc.Subscription, error) {
  122. // Make sure the server is running, fail otherwise
  123. server := api.node.Server()
  124. if server == nil {
  125. return nil, ErrNodeStopped
  126. }
  127. // Create the subscription
  128. notifier, supported := rpc.NotifierFromContext(ctx)
  129. if !supported {
  130. return nil, rpc.ErrNotificationsUnsupported
  131. }
  132. rpcSub := notifier.CreateSubscription()
  133. gopool.Submit(func() {
  134. events := make(chan *p2p.PeerEvent)
  135. sub := server.SubscribeEvents(events)
  136. defer sub.Unsubscribe()
  137. for {
  138. select {
  139. case event := <-events:
  140. notifier.Notify(rpcSub.ID, event)
  141. case <-sub.Err():
  142. return
  143. case <-rpcSub.Err():
  144. return
  145. case <-notifier.Closed():
  146. return
  147. }
  148. }
  149. })
  150. return rpcSub, nil
  151. }
  152. // StartHTTP starts the HTTP RPC API server.
  153. func (api *privateAdminAPI) StartHTTP(host *string, port *int, cors *string, apis *string, vhosts *string) (bool, error) {
  154. api.node.lock.Lock()
  155. defer api.node.lock.Unlock()
  156. // Determine host and port.
  157. if host == nil {
  158. h := DefaultHTTPHost
  159. if api.node.config.HTTPHost != "" {
  160. h = api.node.config.HTTPHost
  161. }
  162. host = &h
  163. }
  164. if port == nil {
  165. port = &api.node.config.HTTPPort
  166. }
  167. // Determine config.
  168. config := httpConfig{
  169. CorsAllowedOrigins: api.node.config.HTTPCors,
  170. Vhosts: api.node.config.HTTPVirtualHosts,
  171. Modules: api.node.config.HTTPModules,
  172. }
  173. if cors != nil {
  174. config.CorsAllowedOrigins = nil
  175. for _, origin := range strings.Split(*cors, ",") {
  176. config.CorsAllowedOrigins = append(config.CorsAllowedOrigins, strings.TrimSpace(origin))
  177. }
  178. }
  179. if vhosts != nil {
  180. config.Vhosts = nil
  181. for _, vhost := range strings.Split(*host, ",") {
  182. config.Vhosts = append(config.Vhosts, strings.TrimSpace(vhost))
  183. }
  184. }
  185. if apis != nil {
  186. config.Modules = nil
  187. for _, m := range strings.Split(*apis, ",") {
  188. config.Modules = append(config.Modules, strings.TrimSpace(m))
  189. }
  190. }
  191. if err := api.node.http.setListenAddr(*host, *port); err != nil {
  192. return false, err
  193. }
  194. if err := api.node.http.enableRPC(api.node.rpcAPIs, config); err != nil {
  195. return false, err
  196. }
  197. if err := api.node.http.start(); err != nil {
  198. return false, err
  199. }
  200. return true, nil
  201. }
  202. // StartRPC starts the HTTP RPC API server.
  203. // This method is deprecated. Use StartHTTP instead.
  204. func (api *privateAdminAPI) StartRPC(host *string, port *int, cors *string, apis *string, vhosts *string) (bool, error) {
  205. log.Warn("Deprecation warning", "method", "admin.StartRPC", "use-instead", "admin.StartHTTP")
  206. return api.StartHTTP(host, port, cors, apis, vhosts)
  207. }
  208. // StopHTTP shuts down the HTTP server.
  209. func (api *privateAdminAPI) StopHTTP() (bool, error) {
  210. api.node.http.stop()
  211. return true, nil
  212. }
  213. // StopRPC shuts down the HTTP server.
  214. // This method is deprecated. Use StopHTTP instead.
  215. func (api *privateAdminAPI) StopRPC() (bool, error) {
  216. log.Warn("Deprecation warning", "method", "admin.StopRPC", "use-instead", "admin.StopHTTP")
  217. return api.StopHTTP()
  218. }
  219. // StartWS starts the websocket RPC API server.
  220. func (api *privateAdminAPI) StartWS(host *string, port *int, allowedOrigins *string, apis *string) (bool, error) {
  221. api.node.lock.Lock()
  222. defer api.node.lock.Unlock()
  223. // Determine host and port.
  224. if host == nil {
  225. h := DefaultWSHost
  226. if api.node.config.WSHost != "" {
  227. h = api.node.config.WSHost
  228. }
  229. host = &h
  230. }
  231. if port == nil {
  232. port = &api.node.config.WSPort
  233. }
  234. // Determine config.
  235. config := wsConfig{
  236. Modules: api.node.config.WSModules,
  237. Origins: api.node.config.WSOrigins,
  238. // ExposeAll: api.node.config.WSExposeAll,
  239. }
  240. if apis != nil {
  241. config.Modules = nil
  242. for _, m := range strings.Split(*apis, ",") {
  243. config.Modules = append(config.Modules, strings.TrimSpace(m))
  244. }
  245. }
  246. if allowedOrigins != nil {
  247. config.Origins = nil
  248. for _, origin := range strings.Split(*allowedOrigins, ",") {
  249. config.Origins = append(config.Origins, strings.TrimSpace(origin))
  250. }
  251. }
  252. // Enable WebSocket on the server.
  253. server := api.node.wsServerForPort(*port)
  254. if err := server.setListenAddr(*host, *port); err != nil {
  255. return false, err
  256. }
  257. if err := server.enableWS(api.node.rpcAPIs, config); err != nil {
  258. return false, err
  259. }
  260. if err := server.start(); err != nil {
  261. return false, err
  262. }
  263. api.node.http.log.Info("WebSocket endpoint opened", "url", api.node.WSEndpoint())
  264. return true, nil
  265. }
  266. // StopWS terminates all WebSocket servers.
  267. func (api *privateAdminAPI) StopWS() (bool, error) {
  268. api.node.http.stopWS()
  269. api.node.ws.stop()
  270. return true, nil
  271. }
  272. // publicAdminAPI is the collection of administrative API methods exposed over
  273. // both secure and unsecure RPC channels.
  274. type publicAdminAPI struct {
  275. node *Node // Node interfaced by this API
  276. }
  277. // Peers retrieves all the information we know about each individual peer at the
  278. // protocol granularity.
  279. func (api *publicAdminAPI) Peers() ([]*p2p.PeerInfo, error) {
  280. server := api.node.Server()
  281. if server == nil {
  282. return nil, ErrNodeStopped
  283. }
  284. return server.PeersInfo(), nil
  285. }
  286. // NodeInfo retrieves all the information we know about the host node at the
  287. // protocol granularity.
  288. func (api *publicAdminAPI) NodeInfo() (*p2p.NodeInfo, error) {
  289. server := api.node.Server()
  290. if server == nil {
  291. return nil, ErrNodeStopped
  292. }
  293. return server.NodeInfo(), nil
  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. // publicWeb3API offers helper utils
  300. type publicWeb3API struct {
  301. stack *Node
  302. }
  303. // ClientVersion returns the node name
  304. func (s *publicWeb3API) ClientVersion() string {
  305. return s.stack.Server().Name
  306. }
  307. // Sha3 applies the ethereum sha3 implementation on the input.
  308. // It assumes the input is hex encoded.
  309. func (s *publicWeb3API) Sha3(input hexutil.Bytes) hexutil.Bytes {
  310. return crypto.Keccak256(input)
  311. }