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