consolecmd.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. // Copyright 2016 The go-ethereum Authors
  2. // This file is part of go-ethereum.
  3. //
  4. // go-ethereum is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU 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. // go-ethereum 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 General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
  16. package main
  17. import (
  18. "fmt"
  19. "strings"
  20. "github.com/ethereum/go-ethereum/cmd/utils"
  21. "github.com/ethereum/go-ethereum/console"
  22. "github.com/ethereum/go-ethereum/internal/flags"
  23. "github.com/ethereum/go-ethereum/node"
  24. "github.com/ethereum/go-ethereum/rpc"
  25. "github.com/urfave/cli/v2"
  26. )
  27. var (
  28. consoleFlags = []cli.Flag{utils.JSpathFlag, utils.ExecFlag, utils.PreloadJSFlag}
  29. consoleCommand = &cli.Command{
  30. Action: localConsole,
  31. Name: "console",
  32. Usage: "Start an interactive JavaScript environment",
  33. Flags: flags.Merge(nodeFlags, rpcFlags, consoleFlags),
  34. Description: `
  35. The Geth console is an interactive shell for the JavaScript runtime environment
  36. which exposes a node admin interface as well as the Ðapp JavaScript API.
  37. See https://geth.ethereum.org/docs/interface/javascript-console.`,
  38. }
  39. attachCommand = &cli.Command{
  40. Action: remoteConsole,
  41. Name: "attach",
  42. Usage: "Start an interactive JavaScript environment (connect to node)",
  43. ArgsUsage: "[endpoint]",
  44. Flags: flags.Merge([]cli.Flag{utils.DataDirFlag}, consoleFlags),
  45. Description: `
  46. The Geth console is an interactive shell for the JavaScript runtime environment
  47. which exposes a node admin interface as well as the Ðapp JavaScript API.
  48. See https://geth.ethereum.org/docs/interface/javascript-console.
  49. This command allows to open a console on a running geth node.`,
  50. }
  51. javascriptCommand = &cli.Command{
  52. Action: ephemeralConsole,
  53. Name: "js",
  54. Usage: "(DEPRECATED) Execute the specified JavaScript files",
  55. ArgsUsage: "<jsfile> [jsfile...]",
  56. Flags: flags.Merge(nodeFlags, consoleFlags),
  57. Description: `
  58. The JavaScript VM exposes a node admin interface as well as the Ðapp
  59. JavaScript API. See https://geth.ethereum.org/docs/interface/javascript-console`,
  60. }
  61. )
  62. // localConsole starts a new geth node, attaching a JavaScript console to it at the
  63. // same time.
  64. func localConsole(ctx *cli.Context) error {
  65. // Create and start the node based on the CLI flags
  66. prepare(ctx)
  67. stack, backend := makeFullNode(ctx)
  68. startNode(ctx, stack, backend, true)
  69. defer stack.Close()
  70. // Attach to the newly started node and create the JavaScript console.
  71. client, err := stack.Attach()
  72. if err != nil {
  73. return fmt.Errorf("Failed to attach to the inproc geth: %v", err)
  74. }
  75. config := console.Config{
  76. DataDir: utils.MakeDataDir(ctx),
  77. DocRoot: ctx.String(utils.JSpathFlag.Name),
  78. Client: client,
  79. Preload: utils.MakeConsolePreloads(ctx),
  80. }
  81. console, err := console.New(config)
  82. if err != nil {
  83. return fmt.Errorf("Failed to start the JavaScript console: %v", err)
  84. }
  85. defer console.Stop(false)
  86. // If only a short execution was requested, evaluate and return.
  87. if script := ctx.String(utils.ExecFlag.Name); script != "" {
  88. console.Evaluate(script)
  89. return nil
  90. }
  91. // Track node shutdown and stop the console when it goes down.
  92. // This happens when SIGTERM is sent to the process.
  93. go func() {
  94. stack.Wait()
  95. console.StopInteractive()
  96. }()
  97. // Print the welcome screen and enter interactive mode.
  98. console.Welcome()
  99. console.Interactive()
  100. return nil
  101. }
  102. // remoteConsole will connect to a remote geth instance, attaching a JavaScript
  103. // console to it.
  104. func remoteConsole(ctx *cli.Context) error {
  105. if ctx.Args().Len() > 1 {
  106. utils.Fatalf("invalid command-line: too many arguments")
  107. }
  108. endpoint := ctx.Args().First()
  109. if endpoint == "" {
  110. cfg := defaultNodeConfig()
  111. utils.SetDataDir(ctx, &cfg)
  112. endpoint = cfg.IPCEndpoint()
  113. }
  114. client, err := dialRPC(endpoint)
  115. if err != nil {
  116. utils.Fatalf("Unable to attach to remote geth: %v", err)
  117. }
  118. config := console.Config{
  119. DataDir: utils.MakeDataDir(ctx),
  120. DocRoot: ctx.String(utils.JSpathFlag.Name),
  121. Client: client,
  122. Preload: utils.MakeConsolePreloads(ctx),
  123. }
  124. console, err := console.New(config)
  125. if err != nil {
  126. utils.Fatalf("Failed to start the JavaScript console: %v", err)
  127. }
  128. defer console.Stop(false)
  129. if script := ctx.String(utils.ExecFlag.Name); script != "" {
  130. console.Evaluate(script)
  131. return nil
  132. }
  133. // Otherwise print the welcome screen and enter interactive mode
  134. console.Welcome()
  135. console.Interactive()
  136. return nil
  137. }
  138. // ephemeralConsole starts a new geth node, attaches an ephemeral JavaScript
  139. // console to it, executes each of the files specified as arguments and tears
  140. // everything down.
  141. func ephemeralConsole(ctx *cli.Context) error {
  142. var b strings.Builder
  143. for _, file := range ctx.Args().Slice() {
  144. b.Write([]byte(fmt.Sprintf("loadScript('%s');", file)))
  145. }
  146. utils.Fatalf(`The "js" command is deprecated. Please use the following instead:
  147. geth --exec "%s" console`, b.String())
  148. return nil
  149. }
  150. // dialRPC returns a RPC client which connects to the given endpoint.
  151. // The check for empty endpoint implements the defaulting logic
  152. // for "geth attach" with no argument.
  153. func dialRPC(endpoint string) (*rpc.Client, error) {
  154. if endpoint == "" {
  155. endpoint = node.DefaultIPCEndpoint(clientIdentifier)
  156. } else if strings.HasPrefix(endpoint, "rpc:") || strings.HasPrefix(endpoint, "ipc:") {
  157. // Backwards compatibility with geth < 1.5 which required
  158. // these prefixes.
  159. endpoint = endpoint[4:]
  160. }
  161. return rpc.Dial(endpoint)
  162. }