func importchain(ctx *cli.Context) { if len(ctx.Args()) != 1 { utils.Fatalf("This command requires an argument.") } cfg := utils.MakeEthConfig(ClientIdentifier, Version, ctx) cfg.SkipBcVersionCheck = true ethereum, err := eth.New(cfg) if err != nil { utils.Fatalf("%v\n", err) } chainmgr := ethereum.ChainManager() start := time.Now() err = utils.ImportChain(chainmgr, ctx.Args().First()) if err != nil { utils.Fatalf("Import error: %v\n", err) } // force database flush ethereum.BlockDb().Close() ethereum.StateDb().Close() ethereum.ExtraDb().Close() fmt.Printf("Import done in %v", time.Since(start)) return }
func getPassPhrase(ctx *cli.Context, desc string, confirmation bool) (passphrase string) { passfile := ctx.GlobalString(utils.PasswordFileFlag.Name) if len(passfile) == 0 { fmt.Println(desc) auth, err := utils.PromptPassword("Passphrase: ", true) if err != nil { utils.Fatalf("%v", err) } if confirmation { confirm, err := utils.PromptPassword("Repeat Passphrase: ", false) if err != nil { utils.Fatalf("%v", err) } if auth != confirm { utils.Fatalf("Passphrases did not match.") } } passphrase = auth } else { passbytes, err := ioutil.ReadFile(passfile) if err != nil { utils.Fatalf("Unable to read password file '%s': %v", passfile, err) } passphrase = string(passbytes) } return }
func makedag(ctx *cli.Context) { utils.CheckLegalese(ctx.GlobalString(utils.DataDirFlag.Name)) args := ctx.Args() wrongArgs := func() { utils.Fatalf(`Usage: geth makedag <block number> <outputdir>`) } switch { case len(args) == 2: blockNum, err := strconv.ParseUint(args[0], 0, 64) dir := args[1] if err != nil { wrongArgs() } else { dir = filepath.Clean(dir) // seems to require a trailing slash if !strings.HasSuffix(dir, "/") { dir = dir + "/" } _, err = ioutil.ReadDir(dir) if err != nil { utils.Fatalf("Can't find dir") } fmt.Println("making DAG, this could take awhile...") ethash.MakeDAG(blockNum, dir) } default: wrongArgs() } }
func exportChain(ctx *cli.Context) { if len(ctx.Args()) < 1 { utils.Fatalf("This command requires an argument.") } chain, _ := utils.MakeChain(ctx) start := time.Now() var err error fp := ctx.Args().First() if len(ctx.Args()) < 3 { err = utils.ExportChain(chain, fp) } else { // This can be improved to allow for numbers larger than 9223372036854775807 first, ferr := strconv.ParseInt(ctx.Args().Get(1), 10, 64) last, lerr := strconv.ParseInt(ctx.Args().Get(2), 10, 64) if ferr != nil || lerr != nil { utils.Fatalf("Export error in parsing parameters: block number not an integer\n") } if first < 0 || last < 0 { utils.Fatalf("Export error: block number must be greater than 0\n") } err = utils.ExportAppendChain(chain, fp, uint64(first), uint64(last)) } if err != nil { utils.Fatalf("Export error: %v\n", err) } fmt.Printf("Export done in %v", time.Since(start)) }
func NewEthereumApplication(ctx *cli.Context) *EthereumApplication { cfg := utils.MakeEthConfig(ClientIdentifier, nodeNameVersion, ctx) ethereum, err := eth.New(cfg) if err != nil { utils.Fatalf("%v", err) } stateDB, err := ethereum.BlockChain().State() if err != nil { utils.Fatalf("%v", err) } ethApp := &EthereumApplication{ ethereum: ethereum, stateDB: stateDB, client: client.NewClientURI(fmt.Sprintf("http://%s", ctx.String(TendermintCoreHostFlag.Name))), } // NOTE: RPC/IPC should only be enabled on local nodes if !ctx.GlobalBool(utils.IPCDisabledFlag.Name) { if err := ethApp.StartIPC(ctx); err != nil { utils.Fatalf("%v", err) } } if ctx.GlobalBool(utils.RPCEnabledFlag.Name) { if err := ethApp.StartRPC(ctx); err != nil { utils.Fatalf("%v", err) } } return ethApp }
// resolveMetrics takes a single of input metric pattern, and resolves it to one // or more canonical metric names. func resolveMetric(metrics map[string]interface{}, pattern string, path string) []string { results := []string{} // If a nested metric was requested, recurse optionally branching (via comma) parts := strings.SplitN(pattern, "/", 2) if len(parts) > 1 { for _, variation := range strings.Split(parts[0], ",") { if submetrics, ok := metrics[variation].(map[string]interface{}); !ok { utils.Fatalf("Failed to retrieve system metrics: %s", path+variation) return nil } else { results = append(results, resolveMetric(submetrics, parts[1], path+variation+"/")...) } } return results } // Depending what the last link is, return or expand for _, variation := range strings.Split(pattern, ",") { switch metric := metrics[variation].(type) { case float64: // Final metric value found, return as singleton results = append(results, path+variation) case map[string]interface{}: results = append(results, expandMetrics(metric, path+variation+"/")...) default: utils.Fatalf("Metric pattern resolved to unexpected type: %v", reflect.TypeOf(metric)) return nil } } return results }
func (js *jsre) newAccount(call otto.FunctionCall) otto.Value { arg := call.Argument(0) var passphrase string if arg.IsUndefined() { fmt.Println("The new account will be encrypted with a passphrase.") fmt.Println("Please enter a passphrase now.") auth, err := readPassword("Passphrase: ", true) if err != nil { utils.Fatalf("%v", err) } confirm, err := readPassword("Repeat Passphrase: ", false) if err != nil { utils.Fatalf("%v", err) } if auth != confirm { utils.Fatalf("Passphrases did not match.") } passphrase = auth } else { var err error passphrase, err = arg.ToString() if err != nil { fmt.Println(err) return otto.FalseValue() } } acct, err := js.ethereum.AccountManager().NewAccount(passphrase) if err != nil { fmt.Printf("Could not create the account: %v", err) return otto.UndefinedValue() } return js.re.ToVal("0x" + common.Bytes2Hex(acct.Address)) }
func startEth(ctx *cli.Context, eth *eth.Ethereum) { // Start Ethereum itself utils.StartEthereum(eth) am := eth.AccountManager() account := ctx.GlobalString(utils.UnlockedAccountFlag.Name) if len(account) > 0 { if account == "primary" { accbytes, err := am.Primary() if err != nil { utils.Fatalf("no primary account: %v", err) } account = common.ToHex(accbytes) } unlockAccount(ctx, am, account) } // Start auxiliary services if enabled. if ctx.GlobalBool(utils.RPCEnabledFlag.Name) { if err := utils.StartRPC(eth, ctx); err != nil { utils.Fatalf("Error starting RPC: %v", err) } } if ctx.GlobalBool(utils.MiningEnabledFlag.Name) { if err := eth.StartMining(); err != nil { utils.Fatalf("%v", err) } } }
// startNode boots up the system node and all registered protocols, after which // it unlocks any requested accounts, and starts the RPC/IPC interfaces and the // miner. func startNode(ctx *cli.Context, stack *node.Node) { // Start up the node itself utils.StartNode(stack) // Unlock any account specifically requested var ethereum *eth.Ethereum if err := stack.Service(ðereum); err != nil { utils.Fatalf("ethereum service not running: %v", err) } accman := ethereum.AccountManager() passwords := utils.MakePasswordList(ctx) accounts := strings.Split(ctx.GlobalString(utils.UnlockedAccountFlag.Name), ",") for i, account := range accounts { if trimmed := strings.TrimSpace(account); trimmed != "" { unlockAccount(ctx, accman, trimmed, i, passwords) } } // Start auxiliary services if enabled if ctx.GlobalBool(utils.MiningEnabledFlag.Name) { if err := ethereum.StartMining(ctx.GlobalInt(utils.MinerThreadsFlag.Name), ctx.GlobalString(utils.MiningGPUFlag.Name)); err != nil { utils.Fatalf("Failed to start mining: %v", err) } } }
func startEth(ctx *cli.Context, eth *eth.Ethereum) { // Start Ethereum itself utils.StartEthereum(eth) am := eth.AccountManager() account := ctx.GlobalString(utils.UnlockedAccountFlag.Name) accounts := strings.Split(account, " ") for i, account := range accounts { if len(account) > 0 { if account == "primary" { utils.Fatalf("the 'primary' keyword is deprecated. You can use integer indexes, but the indexes are not permanent, they can change if you add external keys, export your keys or copy your keystore to another node.") } unlockAccount(ctx, am, account, i) } } // Start auxiliary services if enabled. if !ctx.GlobalBool(utils.IPCDisabledFlag.Name) { if err := utils.StartIPC(eth, ctx); err != nil { utils.Fatalf("Error string IPC: %v", err) } } if ctx.GlobalBool(utils.RPCEnabledFlag.Name) { if err := utils.StartRPC(eth, ctx); err != nil { utils.Fatalf("Error starting RPC: %v", err) } } if ctx.GlobalBool(utils.MiningEnabledFlag.Name) { if err := eth.StartMining(ctx.GlobalInt(utils.MinerThreadsFlag.Name)); err != nil { utils.Fatalf("%v", err) } } }
// tries unlocking the specified account a few times. func unlockAccount(ctx *cli.Context, accman *accounts.Manager, address string, i int, passwords []string) (accounts.Account, string) { account, err := utils.MakeAddress(accman, address) if err != nil { utils.Fatalf("Could not list accounts: %v", err) } for trials := 0; trials < 3; trials++ { prompt := fmt.Sprintf("Unlocking account %s | Attempt %d/%d", address, trials+1, 3) password := getPassPhrase(prompt, false, i, passwords) err = accman.Unlock(account, password) if err == nil { glog.V(logger.Info).Infof("Unlocked account %x", account.Address) return account, password } if err, ok := err.(*accounts.AmbiguousAddrError); ok { glog.V(logger.Info).Infof("Unlocked account %x", account.Address) return ambiguousAddrRecovery(accman, err, password), password } if err != accounts.ErrDecrypt { // No need to prompt again if the error is not decryption-related. break } } // All trials expended to unlock account, bail out utils.Fatalf("Failed to unlock account %s (%v)", address, err) return accounts.Account{}, "" }
// getPassPhrase retrieves the passwor associated with an account, either fetched // from a list of preloaded passphrases, or requested interactively from the user. func getPassPhrase(prompt string, confirmation bool, i int, passwords []string) string { // If a list of passwords was supplied, retrieve from them if len(passwords) > 0 { if i < len(passwords) { return passwords[i] } return passwords[len(passwords)-1] } // Otherwise prompt the user for the password if prompt != "" { fmt.Println(prompt) } password, err := console.Stdin.PromptPassword("Passphrase: ") if err != nil { utils.Fatalf("Failed to read passphrase: %v", err) } if confirmation { confirm, err := console.Stdin.PromptPassword("Repeat passphrase: ") if err != nil { utils.Fatalf("Failed to read passphrase confirmation: %v", err) } if password != confirm { utils.Fatalf("Passphrases do not match") } } return password }
// console starts a new geth node, attaching a JavaScript console to it at the // same time. func console(ctx *cli.Context) { // Create and start the node based on the CLI flags node := utils.MakeSystemNode(clientIdentifier, verString, relConfig, makeDefaultExtra(), ctx) startNode(ctx, node) // Attach to the newly started node, and either execute script or become interactive client, err := node.Attach() if err != nil { utils.Fatalf("Failed to attach to the inproc geth: %v", err) } repl := newJSRE(node, ctx.GlobalString(utils.JSpathFlag.Name), ctx.GlobalString(utils.RPCCORSDomainFlag.Name), client, true) // preload user defined JS files into the console err = repl.preloadJSFiles(ctx) if err != nil { utils.Fatalf("%v", err) } // in case the exec flag holds a JS statement execute it and return if script := ctx.GlobalString(utils.ExecFlag.Name); script != "" { repl.batch(script) } else { repl.welcome() repl.interactive() } node.Stop() }
// execScripts starts a new geth node based on the CLI flags, and executes each // of the JavaScript files specified as command arguments. func execScripts(ctx *cli.Context) { // Create and start the node based on the CLI flags node := utils.MakeSystemNode(clientIdentifier, verString, relConfig, makeDefaultExtra(), ctx) startNode(ctx, node) defer node.Stop() // Attach to the newly started node and execute the given scripts client, err := node.Attach() if err != nil { utils.Fatalf("Failed to attach to the inproc geth: %v", err) } repl := newJSRE(node, ctx.GlobalString(utils.JSpathFlag.Name), ctx.GlobalString(utils.RPCCORSDomainFlag.Name), client, false) // Run all given files. for _, file := range ctx.Args() { if err = repl.re.Exec(file); err != nil { break } } if err != nil { utils.Fatalf("JavaScript Error: %v", jsErrorString(err)) } // JS files loaded successfully. // Wait for pending callbacks, but stop for Ctrl-C. abort := make(chan os.Signal, 1) signal.Notify(abort, os.Interrupt) go func() { <-abort repl.re.Stop(false) }() repl.re.Stop(true) }
// attach will connect to a running geth instance attaching a JavaScript console and to it. func attach(ctx *cli.Context) { // attach to a running geth instance client, err := utils.NewRemoteRPCClient(ctx) if err != nil { utils.Fatalf("Unable to attach to geth: %v", err) } repl := newLightweightJSRE( ctx.GlobalString(utils.JSpathFlag.Name), client, ctx.GlobalString(utils.DataDirFlag.Name), true, ) // preload user defined JS files into the console err = repl.preloadJSFiles(ctx) if err != nil { utils.Fatalf("unable to preload JS file %v", err) } // in case the exec flag holds a JS statement execute it and return if ctx.GlobalString(utils.ExecFlag.Name) != "" { repl.batch(ctx.GlobalString(utils.ExecFlag.Name)) } else { repl.welcome() repl.interactive() } }
// remoteConsole will connect to a remote geth instance, attaching a JavaScript // console to it. func remoteConsole(ctx *cli.Context) error { // Attach to a remotely running geth instance and start the JavaScript console client, err := utils.NewRemoteRPCClient(ctx) if err != nil { utils.Fatalf("Unable to attach to remote geth: %v", err) } config := console.Config{ DataDir: utils.MustMakeDataDir(ctx), DocRoot: ctx.GlobalString(utils.JSpathFlag.Name), Client: client, Preload: utils.MakeConsolePreloads(ctx), } console, err := console.New(config) if err != nil { utils.Fatalf("Failed to start the JavaScript console: %v", err) } defer console.Stop(false) // If only a short execution was requested, evaluate and return if script := ctx.GlobalString(utils.ExecFlag.Name); script != "" { console.Evaluate(script) return nil } // Otherwise print the welcome screen and enter interactive mode console.Welcome() console.Interactive() return nil }
// localConsole starts a new geth node, attaching a JavaScript console to it at the // same time. func localConsole(ctx *cli.Context) error { // Create and start the node based on the CLI flags node := utils.MakeSystemNode(clientIdentifier, verString, relConfig, makeDefaultExtra(), ctx) startNode(ctx, node) defer node.Stop() // Attach to the newly started node and start the JavaScript console client, err := node.Attach() if err != nil { utils.Fatalf("Failed to attach to the inproc geth: %v", err) } config := console.Config{ DataDir: node.DataDir(), DocRoot: ctx.GlobalString(utils.JSpathFlag.Name), Client: client, Preload: utils.MakeConsolePreloads(ctx), } console, err := console.New(config) if err != nil { utils.Fatalf("Failed to start the JavaScript console: %v", err) } defer console.Stop(false) // If only a short execution was requested, evaluate and return if script := ctx.GlobalString(utils.ExecFlag.Name); script != "" { console.Evaluate(script) return nil } // Otherwise print the welcome screen and enter interactive mode console.Welcome() console.Interactive() return nil }
func upgradeDB(ctx *cli.Context) { glog.Infoln("Upgrading blockchain database") chain, chainDb := utils.MakeChain(ctx) v, _ := chainDb.Get([]byte("BlockchainVersion")) bcVersion := int(common.NewValue(v).Uint()) if bcVersion == 0 { bcVersion = core.BlockChainVersion } // Export the current chain. filename := fmt.Sprintf("blockchain_%d_%s.chain", bcVersion, time.Now().Format("20060102_150405")) exportFile := filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), filename) if err := utils.ExportChain(chain, exportFile); err != nil { utils.Fatalf("Unable to export chain for reimport %s", err) } chainDb.Close() os.RemoveAll(filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), "chaindata")) // Import the chain file. chain, chainDb = utils.MakeChain(ctx) chainDb.Put([]byte("BlockchainVersion"), common.NewValue(core.BlockChainVersion).Bytes()) err := utils.ImportChain(chain, exportFile) chainDb.Close() if err != nil { utils.Fatalf("Import error %v (a backup is made in %s, use the import command to import it)", err, exportFile) } else { os.Remove(exportFile) glog.Infoln("Import finished") } }
func runBlockTest(ctx *cli.Context) { var ( file, testname string rpc bool ) args := ctx.Args() switch { case len(args) == 1: file = args[0] case len(args) == 2: file, testname = args[0], args[1] case len(args) == 3: file, testname = args[0], args[1] rpc = true default: utils.Fatalf(`Usage: ethereum blocktest <path-to-test-file> [ <test-name> [ "rpc" ] ]`) } bt, err := tests.LoadBlockTests(file) if err != nil { utils.Fatalf("%v", err) } // run all tests if no test name is specified if testname == "" { ecode := 0 for name, test := range bt { fmt.Printf("----------------- Running Block Test %q\n", name) ethereum, err := runOneBlockTest(ctx, test) if err != nil { fmt.Println(err) fmt.Println("FAIL") ecode = 1 } if ethereum != nil { ethereum.Stop() ethereum.WaitForShutdown() } } os.Exit(ecode) return } // otherwise, run the given test test, ok := bt[testname] if !ok { utils.Fatalf("Test file does not contain test named %q", testname) } ethereum, err := runOneBlockTest(ctx, test) if err != nil { utils.Fatalf("%v", err) } defer ethereum.Stop() if rpc { fmt.Println("Block Test post state validated, starting RPC interface.") startEth(ctx, ethereum) utils.StartRPC(ethereum, ctx) ethereum.WaitForShutdown() } }
// accountUpdate transitions an account from a previous format to the current // one, also providing the possibility to change the pass-phrase. func accountUpdate(ctx *cli.Context) { if len(ctx.Args()) == 0 { utils.Fatalf("No accounts specified to update") } accman := utils.MakeAccountManager(ctx) account, oldPassword := unlockAccount(ctx, accman, ctx.Args().First(), 0, nil) newPassword := getPassPhrase("Please give a new password. Do not forget this password.", true, 0, nil) if err := accman.Update(account, oldPassword, newPassword); err != nil { utils.Fatalf("Could not update the account: %v", err) } }
func upgradeDb(ctx *cli.Context) { fmt.Println("Upgrade blockchain DB") cfg := utils.MakeEthConfig(ClientIdentifier, Version, ctx) cfg.SkipBcVersionCheck = true ethereum, err := eth.New(cfg) if err != nil { utils.Fatalf("%v\n", err) } v, _ := ethereum.BlockDb().Get([]byte("BlockchainVersion")) bcVersion := int(common.NewValue(v).Uint()) if bcVersion == 0 { bcVersion = core.BlockChainVersion } filename := fmt.Sprintf("blockchain_%d_%s.chain", bcVersion, time.Now().Format("2006-01-02_15:04:05")) exportFile := path.Join(ctx.GlobalString(utils.DataDirFlag.Name), filename) err = utils.ExportChain(ethereum.ChainManager(), exportFile) if err != nil { utils.Fatalf("Unable to export chain for reimport %s\n", err) } ethereum.BlockDb().Close() ethereum.StateDb().Close() ethereum.ExtraDb().Close() os.RemoveAll(path.Join(ctx.GlobalString(utils.DataDirFlag.Name), "blockchain")) ethereum, err = eth.New(cfg) if err != nil { utils.Fatalf("%v\n", err) } ethereum.BlockDb().Put([]byte("BlockchainVersion"), common.NewValue(core.BlockChainVersion).Bytes()) err = utils.ImportChain(ethereum.ChainManager(), exportFile) if err != nil { utils.Fatalf("Import error %v (a backup is made in %s, use the import command to import it)\n", err, exportFile) } // force database flush ethereum.BlockDb().Close() ethereum.StateDb().Close() ethereum.ExtraDb().Close() os.Remove(exportFile) fmt.Println("Import finished") }
func importChain(ctx *cli.Context) { if len(ctx.Args()) != 1 { utils.Fatalf("This command requires an argument.") } chain, chainDb := utils.MakeChain(ctx) start := time.Now() err := utils.ImportChain(chain, ctx.Args().First()) chainDb.Close() if err != nil { utils.Fatalf("Import error: %v", err) } fmt.Printf("Import done in %v", time.Since(start)) }
func accountImport(ctx *cli.Context) { keyfile := ctx.Args().First() if len(keyfile) == 0 { utils.Fatalf("keyfile must be given as argument") } am := utils.MakeAccountManager(ctx) passphrase := getPassPhrase(ctx, "Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0) acct, err := am.Import(keyfile, passphrase) if err != nil { utils.Fatalf("Could not create the account: %v", err) } fmt.Printf("Address: %x\n", acct) }
func accountUpdate(ctx *cli.Context) { am := utils.MakeAccountManager(ctx) arg := ctx.Args().First() if len(arg) == 0 { utils.Fatalf("account address or index must be given as argument") } addr, authFrom := unlockAccount(ctx, am, arg, 0) authTo := getPassPhrase(ctx, "Please give a new password. Do not forget this password.", true, 0) err := am.Update(common.HexToAddress(addr), authFrom, authTo) if err != nil { utils.Fatalf("Could not update the account: %v", err) } }
func unlockAccount(ctx *cli.Context, am *accounts.Manager, account string) (passphrase string) { var err error // Load startup keys. XXX we are going to need a different format // Attempt to unlock the account passphrase = getPassPhrase(ctx, "") accbytes := common.FromHex(account) if len(accbytes) == 0 { utils.Fatalf("Invalid account address '%s'", account) } err = am.Unlock(accbytes, passphrase) if err != nil { utils.Fatalf("Unlock account failed '%v'", err) } return }
func (js *jsre) unlock(call otto.FunctionCall) otto.Value { addr, err := call.Argument(0).ToString() if err != nil { fmt.Println(err) return otto.FalseValue() } seconds, err := call.Argument(2).ToInteger() if err != nil { fmt.Println(err) return otto.FalseValue() } arg := call.Argument(1) var passphrase string if arg.IsUndefined() { fmt.Println("Please enter a passphrase now.") passphrase, err = readPassword("Passphrase: ", true) if err != nil { utils.Fatalf("%v", err) } } else { passphrase, err = arg.ToString() if err != nil { fmt.Println(err) return otto.FalseValue() } } am := js.ethereum.AccountManager() err = am.TimedUnlock(common.FromHex(addr), passphrase, time.Duration(seconds)*time.Second) if err != nil { fmt.Printf("Unlock account failed '%v'\n", err) return otto.FalseValue() } return otto.TrueValue() }
func execJSFiles(ctx *cli.Context) { utils.CheckLegalese(ctx.GlobalString(utils.DataDirFlag.Name)) cfg := utils.MakeEthConfig(ClientIdentifier, nodeNameVersion, ctx) ethereum, err := eth.New(cfg) if err != nil { utils.Fatalf("%v", err) } client := comms.NewInProcClient(codec.JSON) startEth(ctx, ethereum) repl := newJSRE( ethereum, ctx.GlobalString(utils.JSpathFlag.Name), ctx.GlobalString(utils.RPCCORSDomainFlag.Name), client, false, nil, ) for _, file := range ctx.Args() { repl.exec(file) } ethereum.Stop() ethereum.WaitForShutdown() }
func console(ctx *cli.Context) { utils.CheckLegalese(ctx.GlobalString(utils.DataDirFlag.Name)) cfg := utils.MakeEthConfig(ClientIdentifier, nodeNameVersion, ctx) ethereum, err := eth.New(cfg) if err != nil { utils.Fatalf("%v", err) } client := comms.NewInProcClient(codec.JSON) startEth(ctx, ethereum) repl := newJSRE( ethereum, ctx.GlobalString(utils.JSpathFlag.Name), ctx.GlobalString(utils.RPCCORSDomainFlag.Name), client, true, nil, ) if ctx.GlobalString(utils.ExecFlag.Name) != "" { repl.batch(ctx.GlobalString(utils.ExecFlag.Name)) } else { repl.welcome() repl.interactive() } ethereum.Stop() ethereum.WaitForShutdown() }
func attach(ctx *cli.Context) { utils.CheckLegalese(ctx.GlobalString(utils.DataDirFlag.Name)) var client comms.EthereumClient var err error if ctx.Args().Present() { client, err = comms.ClientFromEndpoint(ctx.Args().First(), codec.JSON) } else { cfg := comms.IpcConfig{ Endpoint: ctx.GlobalString(utils.IPCPathFlag.Name), } client, err = comms.NewIpcClient(cfg, codec.JSON) } if err != nil { utils.Fatalf("Unable to attach to geth node - %v", err) } repl := newLightweightJSRE( ctx.GlobalString(utils.JSpathFlag.Name), client, true, ) if ctx.GlobalString(utils.ExecFlag.Name) != "" { repl.batch(ctx.GlobalString(utils.ExecFlag.Name)) } else { repl.welcome() repl.interactive() } }
func newLightweightJSRE(libPath string, client comms.EthereumClient, interactive bool, f xeth.Frontend) *jsre { js := &jsre{ps1: "> "} js.wait = make(chan *big.Int) js.client = client js.ds = docserver.New("/") if f == nil { f = js } // update state in separare forever blocks js.re = re.New(libPath) if err := js.apiBindings(f); err != nil { utils.Fatalf("Unable to initialize console - %v", err) } if !liner.TerminalSupported() || !interactive { js.prompter = dumbterm{bufio.NewReader(os.Stdin)} } else { lr := liner.NewLiner() js.withHistory(func(hist *os.File) { lr.ReadHistory(hist) }) lr.SetCtrlCAborts(true) js.loadAutoCompletion() lr.SetWordCompleter(apiWordCompleter) lr.SetTabCompletionStyle(liner.TabPrints) js.prompter = lr js.atexit = func() { js.withHistory(func(hist *os.File) { hist.Truncate(0); lr.WriteHistory(hist) }) lr.Close() close(js.wait) } } return js }