github.com/electroneum/electroneum-sc@v0.0.0-20230105223411-3bc1d078281e/cmd/etn-sc/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 "path/filepath" 22 "strings" 23 24 "github.com/electroneum/electroneum-sc/cmd/utils" 25 "github.com/electroneum/electroneum-sc/console" 26 "github.com/electroneum/electroneum-sc/node" 27 "github.com/electroneum/electroneum-sc/rpc" 28 "gopkg.in/urfave/cli.v1" 29 ) 30 31 var ( 32 consoleFlags = []cli.Flag{utils.JSpathFlag, utils.ExecFlag, utils.PreloadJSFlag} 33 34 consoleCommand = cli.Command{ 35 Action: utils.MigrateFlags(localConsole), 36 Name: "console", 37 Usage: "Start an interactive JavaScript environment", 38 Flags: utils.GroupFlags(nodeFlags, rpcFlags, consoleFlags), 39 Category: "CONSOLE COMMANDS", 40 Description: ` 41 The ETN-SC console is an interactive shell for the JavaScript runtime environment 42 which exposes a node admin interface as well as the Ðapp JavaScript API. 43 See https://geth.ethereum.org/docs/interface/javascript-console.`, 44 } 45 46 attachCommand = cli.Command{ 47 Action: utils.MigrateFlags(remoteConsole), 48 Name: "attach", 49 Usage: "Start an interactive JavaScript environment (connect to node)", 50 ArgsUsage: "[endpoint]", 51 Flags: utils.GroupFlags([]cli.Flag{utils.DataDirFlag}, consoleFlags), 52 Category: "CONSOLE COMMANDS", 53 Description: ` 54 The Geth console is an interactive shell for the JavaScript runtime environment 55 which exposes a node admin interface as well as the Ðapp JavaScript API. 56 See https://geth.ethereum.org/docs/interface/javascript-console. 57 This command allows to open a console on a running geth node.`, 58 } 59 60 javascriptCommand = cli.Command{ 61 Action: utils.MigrateFlags(ephemeralConsole), 62 Name: "js", 63 Usage: "Execute the specified JavaScript files", 64 ArgsUsage: "<jsfile> [jsfile...]", 65 Flags: utils.GroupFlags(nodeFlags, consoleFlags), 66 Category: "CONSOLE COMMANDS", 67 Description: ` 68 The JavaScript VM exposes a node admin interface as well as the Ðapp 69 JavaScript API. See https://geth.ethereum.org/docs/interface/javascript-console`, 70 } 71 ) 72 73 // localConsole starts a new geth node, attaching a JavaScript console to it at the 74 // same time. 75 func localConsole(ctx *cli.Context) error { 76 // Create and start the node based on the CLI flags 77 prepare(ctx) 78 stack, backend := makeFullNode(ctx) 79 startNode(ctx, stack, backend, true) 80 defer stack.Close() 81 82 // Attach to the newly started node and create the JavaScript console. 83 client, err := stack.Attach() 84 if err != nil { 85 return fmt.Errorf("Failed to attach to the inproc geth: %v", err) 86 } 87 config := console.Config{ 88 DataDir: utils.MakeDataDir(ctx), 89 DocRoot: ctx.GlobalString(utils.JSpathFlag.Name), 90 Client: client, 91 Preload: utils.MakeConsolePreloads(ctx), 92 } 93 console, err := console.New(config) 94 if err != nil { 95 return fmt.Errorf("Failed to start the JavaScript console: %v", err) 96 } 97 defer console.Stop(false) 98 99 // If only a short execution was requested, evaluate and return. 100 if script := ctx.GlobalString(utils.ExecFlag.Name); script != "" { 101 console.Evaluate(script) 102 return nil 103 } 104 105 // Track node shutdown and stop the console when it goes down. 106 // This happens when SIGTERM is sent to the process. 107 go func() { 108 stack.Wait() 109 console.StopInteractive() 110 }() 111 112 // Print the welcome screen and enter interactive mode. 113 console.Welcome() 114 console.Interactive() 115 return nil 116 } 117 118 // remoteConsole will connect to a remote geth instance, attaching a JavaScript 119 // console to it. 120 func remoteConsole(ctx *cli.Context) error { 121 endpoint := ctx.Args().First() 122 if endpoint == "" { 123 path := node.DefaultDataDir() 124 if ctx.GlobalIsSet(utils.DataDirFlag.Name) { 125 path = ctx.GlobalString(utils.DataDirFlag.Name) 126 } 127 if path != "" { 128 if ctx.GlobalBool(utils.StagenetFlag.Name) { 129 path = filepath.Join(path, "stagenet") 130 } else if ctx.GlobalBool(utils.TestnetFlag.Name) { 131 path = filepath.Join(path, "testnet") 132 } 133 } 134 endpoint = fmt.Sprintf("%s/etn-sc.ipc", path) 135 } 136 client, err := dialRPC(endpoint) 137 if err != nil { 138 utils.Fatalf("Unable to attach to remote etn-sc: %v", err) 139 } 140 config := console.Config{ 141 DataDir: utils.MakeDataDir(ctx), 142 DocRoot: ctx.GlobalString(utils.JSpathFlag.Name), 143 Client: client, 144 Preload: utils.MakeConsolePreloads(ctx), 145 } 146 console, err := console.New(config) 147 if err != nil { 148 utils.Fatalf("Failed to start the JavaScript console: %v", err) 149 } 150 defer console.Stop(false) 151 152 if script := ctx.GlobalString(utils.ExecFlag.Name); script != "" { 153 console.Evaluate(script) 154 return nil 155 } 156 157 // Otherwise print the welcome screen and enter interactive mode 158 console.Welcome() 159 console.Interactive() 160 return nil 161 } 162 163 // dialRPC returns a RPC client which connects to the given endpoint. 164 // The check for empty endpoint implements the defaulting logic 165 // for "geth attach" with no argument. 166 func dialRPC(endpoint string) (*rpc.Client, error) { 167 if endpoint == "" { 168 endpoint = node.DefaultIPCEndpoint(clientIdentifier) 169 } else if strings.HasPrefix(endpoint, "rpc:") || strings.HasPrefix(endpoint, "ipc:") { 170 // Backwards compatibility with geth < 1.5 which required 171 // these prefixes. 172 endpoint = endpoint[4:] 173 } 174 return rpc.Dial(endpoint) 175 } 176 177 // ephemeralConsole starts a new geth node, attaches an ephemeral JavaScript 178 // console to it, executes each of the files specified as arguments and tears 179 // everything down. 180 func ephemeralConsole(ctx *cli.Context) error { 181 // Create and start the node based on the CLI flags 182 stack, backend := makeFullNode(ctx) 183 startNode(ctx, stack, backend, false) 184 defer stack.Close() 185 186 // Attach to the newly started node and start the JavaScript console 187 client, err := stack.Attach() 188 if err != nil { 189 return fmt.Errorf("Failed to attach to the inproc geth: %v", err) 190 } 191 config := console.Config{ 192 DataDir: utils.MakeDataDir(ctx), 193 DocRoot: ctx.GlobalString(utils.JSpathFlag.Name), 194 Client: client, 195 Preload: utils.MakeConsolePreloads(ctx), 196 } 197 198 console, err := console.New(config) 199 if err != nil { 200 return fmt.Errorf("Failed to start the JavaScript console: %v", err) 201 } 202 defer console.Stop(false) 203 204 // Interrupt the JS interpreter when node is stopped. 205 go func() { 206 stack.Wait() 207 console.Stop(false) 208 }() 209 210 // Evaluate each of the specified JavaScript files. 211 for _, file := range ctx.Args() { 212 if err = console.Execute(file); err != nil { 213 return fmt.Errorf("Failed to execute %s: %v", file, err) 214 } 215 } 216 217 // The main script is now done, but keep running timers/callbacks. 218 console.Stop(true) 219 return nil 220 }