2015-01-06 13:13:57 +02:00
|
|
|
/*
|
|
|
|
This file is part of go-ethereum
|
2014-10-23 16:48:53 +03:00
|
|
|
|
2015-01-06 13:13:57 +02:00
|
|
|
go-ethereum is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
go-ethereum is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
/**
|
|
|
|
* @authors
|
|
|
|
* Jeffrey Wilcke <i@jev.io>
|
|
|
|
*/
|
2014-06-23 14:20:59 +03:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2014-08-06 10:53:12 +03:00
|
|
|
"fmt"
|
2015-05-05 13:24:15 +03:00
|
|
|
"io"
|
2015-03-24 18:19:11 +02:00
|
|
|
"io/ioutil"
|
2015-05-27 14:43:49 +03:00
|
|
|
_ "net/http/pprof"
|
2014-08-06 10:53:12 +03:00
|
|
|
"os"
|
2015-05-05 09:24:15 +03:00
|
|
|
"path/filepath"
|
2014-07-30 02:05:40 +03:00
|
|
|
"runtime"
|
2015-03-06 04:00:41 +02:00
|
|
|
"strconv"
|
2015-05-05 09:24:15 +03:00
|
|
|
"strings"
|
2015-06-25 13:47:06 +03:00
|
|
|
"time"
|
2014-07-30 02:05:40 +03:00
|
|
|
|
2015-03-06 04:00:41 +02:00
|
|
|
"github.com/codegangsta/cli"
|
2015-03-17 15:12:34 +02:00
|
|
|
"github.com/ethereum/ethash"
|
2015-03-23 15:00:06 +02:00
|
|
|
"github.com/ethereum/go-ethereum/accounts"
|
2014-10-31 15:20:11 +02:00
|
|
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
2015-03-16 17:49:39 +02:00
|
|
|
"github.com/ethereum/go-ethereum/common"
|
2015-07-01 17:15:02 +03:00
|
|
|
"github.com/ethereum/go-ethereum/core"
|
|
|
|
"github.com/ethereum/go-ethereum/core/types"
|
2015-01-04 15:20:16 +02:00
|
|
|
"github.com/ethereum/go-ethereum/eth"
|
2015-07-01 17:15:02 +03:00
|
|
|
"github.com/ethereum/go-ethereum/ethdb"
|
2014-10-31 13:56:05 +02:00
|
|
|
"github.com/ethereum/go-ethereum/logger"
|
2015-07-01 01:52:44 +03:00
|
|
|
"github.com/ethereum/go-ethereum/logger/glog"
|
2015-06-27 18:12:58 +03:00
|
|
|
"github.com/ethereum/go-ethereum/metrics"
|
2015-06-17 17:22:35 +03:00
|
|
|
"github.com/ethereum/go-ethereum/rpc/codec"
|
|
|
|
"github.com/ethereum/go-ethereum/rpc/comms"
|
2015-05-07 00:10:46 +03:00
|
|
|
"github.com/mattn/go-colorable"
|
|
|
|
"github.com/mattn/go-isatty"
|
2014-06-23 14:20:59 +03:00
|
|
|
)
|
|
|
|
|
2014-07-03 19:36:24 +03:00
|
|
|
const (
|
2015-03-26 22:27:52 +02:00
|
|
|
ClientIdentifier = "Geth"
|
2015-06-30 03:30:26 +03:00
|
|
|
Version = "0.9.35"
|
2014-07-03 19:36:24 +03:00
|
|
|
)
|
|
|
|
|
2015-04-28 14:14:53 +03:00
|
|
|
var (
|
|
|
|
gitCommit string // set via linker flag
|
|
|
|
nodeNameVersion string
|
|
|
|
app *cli.App
|
|
|
|
)
|
2014-06-23 14:20:59 +03:00
|
|
|
|
2015-03-06 04:00:41 +02:00
|
|
|
func init() {
|
2015-04-28 14:14:53 +03:00
|
|
|
if gitCommit == "" {
|
|
|
|
nodeNameVersion = Version
|
|
|
|
} else {
|
|
|
|
nodeNameVersion = Version + "-" + gitCommit[:8]
|
|
|
|
}
|
|
|
|
|
|
|
|
app = utils.NewApp(Version, "the go-ethereum command line interface")
|
2015-03-06 04:00:41 +02:00
|
|
|
app.Action = run
|
|
|
|
app.HideVersion = true // we have a command to print the version
|
|
|
|
app.Commands = []cli.Command{
|
2015-07-01 01:52:44 +03:00
|
|
|
{
|
|
|
|
Action: blockRecovery,
|
|
|
|
Name: "recover",
|
2015-07-01 17:15:02 +03:00
|
|
|
Usage: "attempts to recover a corrupted database by setting a new block by number or hash. See help recover.",
|
2015-07-01 01:52:44 +03:00
|
|
|
Description: `
|
|
|
|
The recover commands will attempt to read out the last
|
|
|
|
block based on that.
|
2015-07-01 17:15:02 +03:00
|
|
|
|
|
|
|
recover #number recovers by number
|
|
|
|
recover <hex> recovers by hash
|
2015-07-01 01:52:44 +03:00
|
|
|
`,
|
|
|
|
},
|
2015-05-27 14:43:49 +03:00
|
|
|
blocktestCommand,
|
|
|
|
importCommand,
|
|
|
|
exportCommand,
|
|
|
|
upgradedbCommand,
|
|
|
|
removedbCommand,
|
|
|
|
dumpCommand,
|
2015-06-25 10:36:47 +03:00
|
|
|
monitorCommand,
|
2015-03-17 15:12:34 +02:00
|
|
|
{
|
|
|
|
Action: makedag,
|
|
|
|
Name: "makedag",
|
|
|
|
Usage: "generate ethash dag (for testing)",
|
|
|
|
Description: `
|
|
|
|
The makedag command generates an ethash DAG in /tmp/dag.
|
|
|
|
|
|
|
|
This command exists to support the system testing project.
|
|
|
|
Regular users do not need to execute it.
|
|
|
|
`,
|
|
|
|
},
|
2015-03-06 04:00:41 +02:00
|
|
|
{
|
|
|
|
Action: version,
|
|
|
|
Name: "version",
|
|
|
|
Usage: "print ethereum version numbers",
|
|
|
|
Description: `
|
|
|
|
The output of this command is supposed to be machine-readable.
|
|
|
|
`,
|
|
|
|
},
|
2015-03-24 18:19:11 +02:00
|
|
|
|
|
|
|
{
|
2015-03-26 20:55:39 +02:00
|
|
|
Name: "wallet",
|
|
|
|
Usage: "ethereum presale wallet",
|
2015-03-24 18:19:11 +02:00
|
|
|
Subcommands: []cli.Command{
|
|
|
|
{
|
|
|
|
Action: importWallet,
|
|
|
|
Name: "import",
|
|
|
|
Usage: "import ethereum presale wallet",
|
|
|
|
},
|
|
|
|
},
|
2015-05-20 04:42:10 +03:00
|
|
|
Description: `
|
|
|
|
|
|
|
|
get wallet import /path/to/my/presale.wallet
|
|
|
|
|
|
|
|
will prompt for your password and imports your ether presale account.
|
|
|
|
It can be used non-interactively with the --password option taking a
|
|
|
|
passwordfile as argument containing the wallet password in plaintext.
|
|
|
|
|
|
|
|
`},
|
2015-03-07 13:39:52 +02:00
|
|
|
{
|
|
|
|
Action: accountList,
|
|
|
|
Name: "account",
|
|
|
|
Usage: "manage accounts",
|
2015-03-26 20:55:39 +02:00
|
|
|
Description: `
|
|
|
|
|
|
|
|
Manage accounts lets you create new accounts, list all existing accounts,
|
|
|
|
import a private key into a new account.
|
|
|
|
|
2015-05-20 18:56:17 +03:00
|
|
|
' help' shows a list of subcommands or help for one subcommand.
|
2015-04-22 02:41:34 +03:00
|
|
|
|
2015-03-26 20:55:39 +02:00
|
|
|
It supports interactive mode, when you are prompted for password as well as
|
|
|
|
non-interactive mode where passwords are supplied via a given password file.
|
|
|
|
Non-interactive mode is only meant for scripted use on test networks or known
|
|
|
|
safe environments.
|
|
|
|
|
|
|
|
Make sure you remember the password you gave when creating a new account (with
|
|
|
|
either new or import). Without it you are not able to unlock your account.
|
|
|
|
|
|
|
|
Note that exporting your key in unencrypted format is NOT supported.
|
|
|
|
|
|
|
|
Keys are stored under <DATADIR>/keys.
|
|
|
|
It is safe to transfer the entire directory or the individual keys therein
|
|
|
|
between ethereum nodes.
|
|
|
|
Make sure you backup your keys regularly.
|
|
|
|
|
|
|
|
And finally. DO NOT FORGET YOUR PASSWORD.
|
|
|
|
`,
|
2015-03-07 13:39:52 +02:00
|
|
|
Subcommands: []cli.Command{
|
|
|
|
{
|
|
|
|
Action: accountList,
|
|
|
|
Name: "list",
|
|
|
|
Usage: "print account addresses",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Action: accountCreate,
|
|
|
|
Name: "new",
|
|
|
|
Usage: "create a new account",
|
2015-03-23 15:00:06 +02:00
|
|
|
Description: `
|
|
|
|
|
|
|
|
ethereum account new
|
|
|
|
|
2015-03-26 20:55:39 +02:00
|
|
|
Creates a new account. Prints the address.
|
|
|
|
|
|
|
|
The account is saved in encrypted format, you are prompted for a passphrase.
|
|
|
|
|
|
|
|
You must remember this passphrase to unlock your account in the future.
|
|
|
|
|
2015-03-23 15:00:06 +02:00
|
|
|
For non-interactive use the passphrase can be specified with the --password flag:
|
|
|
|
|
|
|
|
ethereum --password <passwordfile> account new
|
|
|
|
|
2015-03-26 20:55:39 +02:00
|
|
|
Note, this is meant to be used for testing only, it is a bad idea to save your
|
|
|
|
password to file or expose in any other way.
|
2015-03-23 15:00:06 +02:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Action: accountImport,
|
|
|
|
Name: "import",
|
|
|
|
Usage: "import a private key into a new account",
|
|
|
|
Description: `
|
|
|
|
|
|
|
|
ethereum account import <keyfile>
|
|
|
|
|
2015-03-26 20:55:39 +02:00
|
|
|
Imports an unencrypted private key from <keyfile> and creates a new account.
|
|
|
|
Prints the address.
|
|
|
|
|
2015-04-09 00:03:47 +03:00
|
|
|
The keyfile is assumed to contain an unencrypted private key in hexadecimal format.
|
2015-03-23 15:00:06 +02:00
|
|
|
|
|
|
|
The account is saved in encrypted format, you are prompted for a passphrase.
|
|
|
|
|
2015-03-26 20:55:39 +02:00
|
|
|
You must remember this passphrase to unlock your account in the future.
|
2015-03-23 15:00:06 +02:00
|
|
|
|
2015-03-26 20:55:39 +02:00
|
|
|
For non-interactive use the passphrase can be specified with the -password flag:
|
2015-03-23 15:00:06 +02:00
|
|
|
|
2015-03-26 20:55:39 +02:00
|
|
|
ethereum --password <passwordfile> account import <keyfile>
|
2015-03-23 15:00:06 +02:00
|
|
|
|
|
|
|
Note:
|
2015-03-24 18:05:27 +02:00
|
|
|
As you can directly copy your encrypted accounts to another ethereum instance,
|
2015-03-26 20:55:39 +02:00
|
|
|
this import mechanism is not needed when you transfer an account between
|
2015-03-24 18:05:27 +02:00
|
|
|
nodes.
|
2015-03-23 15:00:06 +02:00
|
|
|
`,
|
2015-03-07 13:39:52 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2015-03-06 04:00:41 +02:00
|
|
|
{
|
2015-03-15 08:31:40 +02:00
|
|
|
Action: console,
|
|
|
|
Name: "console",
|
2015-03-26 22:27:52 +02:00
|
|
|
Usage: `Geth Console: interactive JavaScript environment`,
|
2015-03-15 08:31:40 +02:00
|
|
|
Description: `
|
2015-03-26 22:27:52 +02:00
|
|
|
The Geth console is an interactive shell for the JavaScript runtime environment
|
2015-04-22 02:41:34 +03:00
|
|
|
which exposes a node admin interface as well as the Ðapp JavaScript API.
|
|
|
|
See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console
|
2015-06-18 19:23:13 +03:00
|
|
|
`},
|
|
|
|
{
|
|
|
|
Action: attach,
|
|
|
|
Name: "attach",
|
2015-06-23 10:11:57 +03:00
|
|
|
Usage: `Geth Console: interactive JavaScript environment (connect to node)`,
|
2015-06-18 19:23:13 +03:00
|
|
|
Description: `
|
|
|
|
The Geth console is an interactive shell for the JavaScript runtime environment
|
|
|
|
which exposes a node admin interface as well as the Ðapp JavaScript API.
|
|
|
|
See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console.
|
|
|
|
This command allows to open a console on a running geth node.
|
2015-03-15 08:31:40 +02:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Action: execJSFiles,
|
2015-03-06 04:00:41 +02:00
|
|
|
Name: "js",
|
2015-03-26 22:27:52 +02:00
|
|
|
Usage: `executes the given JavaScript files in the Geth JavaScript VM`,
|
2015-03-06 04:00:41 +02:00
|
|
|
Description: `
|
2015-04-22 02:41:34 +03:00
|
|
|
The JavaScript VM exposes a node admin interface as well as the Ðapp
|
2015-03-24 18:05:27 +02:00
|
|
|
JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console
|
2015-03-06 04:00:41 +02:00
|
|
|
`,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
app.Flags = []cli.Flag{
|
2015-04-19 00:53:30 +03:00
|
|
|
utils.IdentityFlag,
|
2015-03-11 02:08:42 +02:00
|
|
|
utils.UnlockedAccountFlag,
|
2015-03-23 15:00:06 +02:00
|
|
|
utils.PasswordFileFlag,
|
2015-06-08 13:12:13 +03:00
|
|
|
utils.GenesisNonceFlag,
|
2015-03-06 04:00:41 +02:00
|
|
|
utils.BootnodesFlag,
|
|
|
|
utils.DataDirFlag,
|
2015-04-13 11:13:52 +03:00
|
|
|
utils.BlockchainVersionFlag,
|
2015-03-15 08:31:40 +02:00
|
|
|
utils.JSpathFlag,
|
2015-03-06 04:00:41 +02:00
|
|
|
utils.ListenPortFlag,
|
|
|
|
utils.MaxPeersFlag,
|
2015-05-04 17:35:49 +03:00
|
|
|
utils.MaxPendingPeersFlag,
|
2015-03-26 23:49:22 +02:00
|
|
|
utils.EtherbaseFlag,
|
2015-05-09 13:00:51 +03:00
|
|
|
utils.GasPriceFlag,
|
2015-03-06 04:00:41 +02:00
|
|
|
utils.MinerThreadsFlag,
|
|
|
|
utils.MiningEnabledFlag,
|
2015-05-20 18:56:17 +03:00
|
|
|
utils.AutoDAGFlag,
|
2015-03-06 04:00:41 +02:00
|
|
|
utils.NATFlag,
|
2015-04-08 14:22:31 +03:00
|
|
|
utils.NatspecEnabledFlag,
|
2015-05-26 19:07:24 +03:00
|
|
|
utils.NoDiscoverFlag,
|
2015-03-06 04:00:41 +02:00
|
|
|
utils.NodeKeyFileFlag,
|
|
|
|
utils.NodeKeyHexFlag,
|
|
|
|
utils.RPCEnabledFlag,
|
|
|
|
utils.RPCListenAddrFlag,
|
|
|
|
utils.RPCPortFlag,
|
2015-06-16 14:30:53 +03:00
|
|
|
utils.RpcApiFlag,
|
2015-06-08 12:01:02 +03:00
|
|
|
utils.IPCDisabledFlag,
|
|
|
|
utils.IPCApiFlag,
|
|
|
|
utils.IPCPathFlag,
|
2015-06-19 15:04:18 +03:00
|
|
|
utils.ExecFlag,
|
2015-04-20 18:45:37 +03:00
|
|
|
utils.WhisperEnabledFlag,
|
2015-03-06 17:58:52 +02:00
|
|
|
utils.VMDebugFlag,
|
2015-03-18 09:44:58 +02:00
|
|
|
utils.NetworkIdFlag,
|
2015-03-29 22:21:14 +03:00
|
|
|
utils.RPCCORSDomainFlag,
|
2015-05-09 13:00:51 +03:00
|
|
|
utils.VerbosityFlag,
|
2015-04-03 18:09:01 +03:00
|
|
|
utils.BacktraceAtFlag,
|
|
|
|
utils.LogToStdErrFlag,
|
2015-04-07 15:57:16 +03:00
|
|
|
utils.LogVModuleFlag,
|
|
|
|
utils.LogFileFlag,
|
|
|
|
utils.LogJSONFlag,
|
2015-04-20 19:14:49 +03:00
|
|
|
utils.PProfEanbledFlag,
|
2015-04-20 18:45:37 +03:00
|
|
|
utils.PProfPortFlag,
|
2015-06-29 16:11:01 +03:00
|
|
|
utils.MetricsEnabledFlag,
|
2015-04-23 01:11:11 +03:00
|
|
|
utils.SolcPathFlag,
|
2015-05-26 15:17:43 +03:00
|
|
|
utils.GpoMinGasPriceFlag,
|
|
|
|
utils.GpoMaxGasPriceFlag,
|
|
|
|
utils.GpoFullBlockRatioFlag,
|
|
|
|
utils.GpobaseStepDownFlag,
|
|
|
|
utils.GpobaseStepUpFlag,
|
|
|
|
utils.GpobaseCorrectionFactorFlag,
|
2015-03-06 04:00:41 +02:00
|
|
|
}
|
2015-04-20 18:59:41 +03:00
|
|
|
app.Before = func(ctx *cli.Context) error {
|
2015-05-27 14:29:34 +03:00
|
|
|
utils.SetupLogger(ctx)
|
2015-04-20 19:14:49 +03:00
|
|
|
if ctx.GlobalBool(utils.PProfEanbledFlag.Name) {
|
2015-04-20 18:59:41 +03:00
|
|
|
utils.StartPProf(ctx)
|
|
|
|
}
|
|
|
|
return nil
|
2015-03-06 04:00:41 +02:00
|
|
|
}
|
2015-06-25 13:47:06 +03:00
|
|
|
// Start system runtime metrics collection
|
2015-06-27 18:12:58 +03:00
|
|
|
go metrics.CollectProcessMetrics(3 * time.Second)
|
2015-03-06 04:00:41 +02:00
|
|
|
}
|
2014-12-23 15:33:15 +02:00
|
|
|
|
2015-03-06 04:00:41 +02:00
|
|
|
func main() {
|
|
|
|
runtime.GOMAXPROCS(runtime.NumCPU())
|
|
|
|
defer logger.Flush()
|
|
|
|
if err := app.Run(os.Args); err != nil {
|
|
|
|
fmt.Fprintln(os.Stderr, err)
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
}
|
2014-06-26 12:47:45 +03:00
|
|
|
|
2015-03-06 04:00:41 +02:00
|
|
|
func run(ctx *cli.Context) {
|
2015-03-06 13:18:44 +02:00
|
|
|
utils.HandleInterrupt()
|
2015-04-28 14:14:53 +03:00
|
|
|
cfg := utils.MakeEthConfig(ClientIdentifier, nodeNameVersion, ctx)
|
2015-03-13 19:30:45 +02:00
|
|
|
ethereum, err := eth.New(cfg)
|
2015-03-12 00:41:51 +02:00
|
|
|
if err != nil {
|
2015-03-10 16:44:05 +02:00
|
|
|
utils.Fatalf("%v", err)
|
|
|
|
}
|
|
|
|
|
2015-03-13 19:30:45 +02:00
|
|
|
startEth(ctx, ethereum)
|
2015-03-06 04:00:41 +02:00
|
|
|
// this blocks the thread
|
2015-03-13 19:30:45 +02:00
|
|
|
ethereum.WaitForShutdown()
|
2015-03-06 04:00:41 +02:00
|
|
|
}
|
2014-07-11 17:04:27 +03:00
|
|
|
|
2015-06-18 19:23:13 +03:00
|
|
|
func attach(ctx *cli.Context) {
|
|
|
|
// Wrap the standard output with a colorified stream (windows)
|
|
|
|
if isatty.IsTerminal(os.Stdout.Fd()) {
|
|
|
|
if pr, pw, err := os.Pipe(); err == nil {
|
|
|
|
go io.Copy(colorable.NewColorableStdout(), pr)
|
|
|
|
os.Stdout = pw
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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(
|
2015-06-23 10:38:30 +03:00
|
|
|
ctx.GlobalString(utils.JSpathFlag.Name),
|
2015-06-18 19:23:13 +03:00
|
|
|
client,
|
|
|
|
true,
|
|
|
|
nil)
|
|
|
|
|
2015-06-19 15:04:18 +03:00
|
|
|
if ctx.GlobalString(utils.ExecFlag.Name) != "" {
|
|
|
|
repl.batch(ctx.GlobalString(utils.ExecFlag.Name))
|
|
|
|
} else {
|
|
|
|
repl.welcome()
|
|
|
|
repl.interactive()
|
|
|
|
}
|
2015-06-18 19:23:13 +03:00
|
|
|
}
|
|
|
|
|
2015-03-15 08:31:40 +02:00
|
|
|
func console(ctx *cli.Context) {
|
2015-05-05 13:24:15 +03:00
|
|
|
// Wrap the standard output with a colorified stream (windows)
|
|
|
|
if isatty.IsTerminal(os.Stdout.Fd()) {
|
|
|
|
if pr, pw, err := os.Pipe(); err == nil {
|
|
|
|
go io.Copy(colorable.NewColorableStdout(), pr)
|
|
|
|
os.Stdout = pw
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-28 14:14:53 +03:00
|
|
|
cfg := utils.MakeEthConfig(ClientIdentifier, nodeNameVersion, ctx)
|
2015-03-13 19:30:45 +02:00
|
|
|
ethereum, err := eth.New(cfg)
|
2015-03-12 00:41:51 +02:00
|
|
|
if err != nil {
|
2015-03-10 16:44:05 +02:00
|
|
|
utils.Fatalf("%v", err)
|
|
|
|
}
|
|
|
|
|
2015-06-17 17:22:35 +03:00
|
|
|
client := comms.NewInProcClient(codec.JSON)
|
|
|
|
|
2015-03-13 19:30:45 +02:00
|
|
|
startEth(ctx, ethereum)
|
2015-04-23 01:11:11 +03:00
|
|
|
repl := newJSRE(
|
|
|
|
ethereum,
|
2015-06-23 10:38:30 +03:00
|
|
|
ctx.GlobalString(utils.JSpathFlag.Name),
|
2015-04-23 01:11:11 +03:00
|
|
|
ctx.GlobalString(utils.RPCCORSDomainFlag.Name),
|
2015-06-17 17:22:35 +03:00
|
|
|
client,
|
2015-04-23 01:11:11 +03:00
|
|
|
true,
|
|
|
|
nil,
|
|
|
|
)
|
2015-06-18 19:23:13 +03:00
|
|
|
|
2015-06-19 15:04:18 +03:00
|
|
|
if ctx.GlobalString(utils.ExecFlag.Name) != "" {
|
|
|
|
repl.batch(ctx.GlobalString(utils.ExecFlag.Name))
|
|
|
|
} else {
|
|
|
|
repl.welcome()
|
|
|
|
repl.interactive()
|
|
|
|
}
|
2015-03-15 08:31:40 +02:00
|
|
|
|
|
|
|
ethereum.Stop()
|
|
|
|
ethereum.WaitForShutdown()
|
|
|
|
}
|
|
|
|
|
|
|
|
func execJSFiles(ctx *cli.Context) {
|
2015-04-28 14:14:53 +03:00
|
|
|
cfg := utils.MakeEthConfig(ClientIdentifier, nodeNameVersion, ctx)
|
2015-03-15 08:31:40 +02:00
|
|
|
ethereum, err := eth.New(cfg)
|
|
|
|
if err != nil {
|
|
|
|
utils.Fatalf("%v", err)
|
2015-01-07 02:21:55 +02:00
|
|
|
}
|
2015-03-15 08:31:40 +02:00
|
|
|
|
2015-06-17 17:22:35 +03:00
|
|
|
client := comms.NewInProcClient(codec.JSON)
|
2015-03-15 08:31:40 +02:00
|
|
|
startEth(ctx, ethereum)
|
2015-04-23 01:11:11 +03:00
|
|
|
repl := newJSRE(
|
|
|
|
ethereum,
|
2015-06-23 10:38:30 +03:00
|
|
|
ctx.GlobalString(utils.JSpathFlag.Name),
|
2015-04-23 01:11:11 +03:00
|
|
|
ctx.GlobalString(utils.RPCCORSDomainFlag.Name),
|
2015-06-17 17:22:35 +03:00
|
|
|
client,
|
2015-04-23 01:11:11 +03:00
|
|
|
false,
|
|
|
|
nil,
|
|
|
|
)
|
2015-03-15 08:31:40 +02:00
|
|
|
for _, file := range ctx.Args() {
|
|
|
|
repl.exec(file)
|
|
|
|
}
|
|
|
|
|
2015-03-13 19:30:45 +02:00
|
|
|
ethereum.Stop()
|
|
|
|
ethereum.WaitForShutdown()
|
2015-03-06 04:00:41 +02:00
|
|
|
}
|
2015-01-07 02:21:55 +02:00
|
|
|
|
2015-03-23 15:00:06 +02:00
|
|
|
func unlockAccount(ctx *cli.Context, am *accounts.Manager, account string) (passphrase string) {
|
2015-03-26 20:55:39 +02:00
|
|
|
var err error
|
|
|
|
// Load startup keys. XXX we are going to need a different format
|
2015-05-19 21:40:41 +03:00
|
|
|
|
2015-05-28 16:20:05 +03:00
|
|
|
if !((len(account) == 40) || (len(account) == 42)) { // with or without 0x
|
2015-03-26 20:55:39 +02:00
|
|
|
utils.Fatalf("Invalid account address '%s'", account)
|
|
|
|
}
|
2015-05-19 22:46:32 +03:00
|
|
|
// Attempt to unlock the account 3 times
|
|
|
|
attempts := 3
|
|
|
|
for tries := 0; tries < attempts; tries++ {
|
2015-05-28 16:20:05 +03:00
|
|
|
msg := fmt.Sprintf("Unlocking account %s | Attempt %d/%d", account, tries+1, attempts)
|
2015-05-19 22:46:32 +03:00
|
|
|
passphrase = getPassPhrase(ctx, msg, false)
|
|
|
|
err = am.Unlock(common.HexToAddress(account), passphrase)
|
|
|
|
if err == nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2015-03-26 20:55:39 +02:00
|
|
|
if err != nil {
|
|
|
|
utils.Fatalf("Unlock account failed '%v'", err)
|
2015-03-11 02:08:42 +02:00
|
|
|
}
|
2015-05-13 02:11:17 +03:00
|
|
|
fmt.Printf("Account '%s' unlocked.\n", account)
|
2015-03-23 15:00:06 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-07-01 01:52:44 +03:00
|
|
|
func blockRecovery(ctx *cli.Context) {
|
2015-07-01 17:15:02 +03:00
|
|
|
arg := ctx.Args().First()
|
|
|
|
if len(ctx.Args()) < 1 && len(arg) > 0 {
|
|
|
|
glog.Fatal("recover requires block number or hash")
|
2015-07-01 01:52:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
cfg := utils.MakeEthConfig(ClientIdentifier, nodeNameVersion, ctx)
|
2015-07-01 17:15:02 +03:00
|
|
|
blockDb, err := ethdb.NewLDBDatabase(filepath.Join(cfg.DataDir, "blockchain"))
|
2015-07-01 01:52:44 +03:00
|
|
|
if err != nil {
|
2015-07-01 17:15:02 +03:00
|
|
|
glog.Fatalln("could not open db:", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var block *types.Block
|
|
|
|
if arg[0] == '#' {
|
|
|
|
block = core.GetBlockByNumber(blockDb, common.String2Big(arg[1:]).Uint64())
|
|
|
|
} else {
|
|
|
|
block = core.GetBlockByHash(blockDb, common.HexToHash(arg))
|
|
|
|
}
|
|
|
|
|
|
|
|
if block == nil {
|
|
|
|
glog.Fatalln("block not found. Recovery failed")
|
|
|
|
}
|
|
|
|
|
|
|
|
err = core.WriteHead(blockDb, block)
|
|
|
|
if err != nil {
|
|
|
|
glog.Fatalln("block write err", err)
|
2015-07-01 01:52:44 +03:00
|
|
|
}
|
2015-07-01 17:15:02 +03:00
|
|
|
glog.Infof("Recovery succesful. New HEAD %x\n", block.Hash())
|
2015-07-01 01:52:44 +03:00
|
|
|
}
|
|
|
|
|
2015-03-23 15:00:06 +02:00
|
|
|
func startEth(ctx *cli.Context, eth *eth.Ethereum) {
|
2015-04-20 18:45:37 +03:00
|
|
|
// Start Ethereum itself
|
2015-04-23 01:11:11 +03:00
|
|
|
|
2015-03-23 15:00:06 +02:00
|
|
|
utils.StartEthereum(eth)
|
|
|
|
am := eth.AccountManager()
|
|
|
|
|
|
|
|
account := ctx.GlobalString(utils.UnlockedAccountFlag.Name)
|
2015-05-19 21:40:41 +03:00
|
|
|
accounts := strings.Split(account, " ")
|
|
|
|
for _, account := range accounts {
|
|
|
|
if len(account) > 0 {
|
|
|
|
if account == "primary" {
|
|
|
|
primaryAcc, err := am.Primary()
|
|
|
|
if err != nil {
|
|
|
|
utils.Fatalf("no primary account: %v", err)
|
|
|
|
}
|
|
|
|
account = primaryAcc.Hex()
|
2015-03-25 17:45:56 +02:00
|
|
|
}
|
2015-05-19 21:40:41 +03:00
|
|
|
unlockAccount(ctx, am, account)
|
2015-03-24 14:37:00 +02:00
|
|
|
}
|
2015-03-23 15:00:06 +02:00
|
|
|
}
|
2015-03-10 17:44:22 +02:00
|
|
|
// Start auxiliary services if enabled.
|
2015-06-08 12:01:02 +03:00
|
|
|
if !ctx.GlobalBool(utils.IPCDisabledFlag.Name) {
|
|
|
|
if err := utils.StartIPC(eth, ctx); err != nil {
|
|
|
|
utils.Fatalf("Error string IPC: %v", err)
|
|
|
|
}
|
|
|
|
}
|
2015-03-06 04:00:41 +02:00
|
|
|
if ctx.GlobalBool(utils.RPCEnabledFlag.Name) {
|
2015-04-22 02:47:17 +03:00
|
|
|
if err := utils.StartRPC(eth, ctx); err != nil {
|
|
|
|
utils.Fatalf("Error starting RPC: %v", err)
|
|
|
|
}
|
2015-03-06 04:00:41 +02:00
|
|
|
}
|
|
|
|
if ctx.GlobalBool(utils.MiningEnabledFlag.Name) {
|
2015-05-11 16:43:14 +03:00
|
|
|
if err := eth.StartMining(ctx.GlobalInt(utils.MinerThreadsFlag.Name)); err != nil {
|
2015-04-22 03:36:28 +03:00
|
|
|
utils.Fatalf("%v", err)
|
|
|
|
}
|
2015-03-06 04:00:41 +02:00
|
|
|
}
|
|
|
|
}
|
2015-01-05 18:10:42 +02:00
|
|
|
|
2015-03-07 13:39:52 +02:00
|
|
|
func accountList(ctx *cli.Context) {
|
2015-05-27 15:50:31 +03:00
|
|
|
am := utils.MakeAccountManager(ctx)
|
2015-03-07 13:39:52 +02:00
|
|
|
accts, err := am.Accounts()
|
|
|
|
if err != nil {
|
|
|
|
utils.Fatalf("Could not list accounts: %v", err)
|
|
|
|
}
|
2015-04-22 02:41:34 +03:00
|
|
|
name := "Primary"
|
|
|
|
for i, acct := range accts {
|
|
|
|
fmt.Printf("%s #%d: %x\n", name, i, acct)
|
|
|
|
name = "Account"
|
2015-03-07 13:39:52 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-24 18:19:11 +02:00
|
|
|
func getPassPhrase(ctx *cli.Context, desc string, confirmation bool) (passphrase string) {
|
2015-03-26 20:55:39 +02:00
|
|
|
passfile := ctx.GlobalString(utils.PasswordFileFlag.Name)
|
|
|
|
if len(passfile) == 0 {
|
|
|
|
fmt.Println(desc)
|
2015-05-18 20:24:30 +03:00
|
|
|
auth, err := utils.PromptPassword("Passphrase: ", true)
|
2015-03-26 20:55:39 +02:00
|
|
|
if err != nil {
|
|
|
|
utils.Fatalf("%v", err)
|
|
|
|
}
|
|
|
|
if confirmation {
|
2015-05-18 20:24:30 +03:00
|
|
|
confirm, err := utils.PromptPassword("Repeat Passphrase: ", false)
|
2015-03-23 15:00:06 +02:00
|
|
|
if err != nil {
|
|
|
|
utils.Fatalf("%v", err)
|
|
|
|
}
|
2015-03-26 20:55:39 +02:00
|
|
|
if auth != confirm {
|
|
|
|
utils.Fatalf("Passphrases did not match.")
|
2015-03-23 15:00:06 +02:00
|
|
|
}
|
2015-03-26 20:55:39 +02:00
|
|
|
}
|
|
|
|
passphrase = auth
|
2015-03-23 15:00:06 +02:00
|
|
|
|
2015-03-26 20:55:39 +02:00
|
|
|
} else {
|
|
|
|
passbytes, err := ioutil.ReadFile(passfile)
|
|
|
|
if err != nil {
|
|
|
|
utils.Fatalf("Unable to read password file '%s': %v", passfile, err)
|
2015-03-11 14:56:02 +02:00
|
|
|
}
|
2015-03-26 20:55:39 +02:00
|
|
|
passphrase = string(passbytes)
|
2015-03-07 13:39:52 +02:00
|
|
|
}
|
2015-03-23 15:00:06 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func accountCreate(ctx *cli.Context) {
|
2015-05-27 15:50:31 +03:00
|
|
|
am := utils.MakeAccountManager(ctx)
|
2015-03-24 18:19:11 +02:00
|
|
|
passphrase := getPassPhrase(ctx, "Your new account is locked with a password. Please give a password. Do not forget this password.", true)
|
2015-03-11 14:56:02 +02:00
|
|
|
acct, err := am.NewAccount(passphrase)
|
2015-03-07 13:39:52 +02:00
|
|
|
if err != nil {
|
|
|
|
utils.Fatalf("Could not create the account: %v", err)
|
|
|
|
}
|
2015-03-23 15:00:06 +02:00
|
|
|
fmt.Printf("Address: %x\n", acct)
|
|
|
|
}
|
|
|
|
|
2015-03-24 18:19:11 +02:00
|
|
|
func importWallet(ctx *cli.Context) {
|
|
|
|
keyfile := ctx.Args().First()
|
|
|
|
if len(keyfile) == 0 {
|
|
|
|
utils.Fatalf("keyfile must be given as argument")
|
|
|
|
}
|
|
|
|
keyJson, err := ioutil.ReadFile(keyfile)
|
|
|
|
if err != nil {
|
|
|
|
utils.Fatalf("Could not read wallet file: %v", err)
|
|
|
|
}
|
|
|
|
|
2015-05-27 15:50:31 +03:00
|
|
|
am := utils.MakeAccountManager(ctx)
|
2015-03-24 18:19:11 +02:00
|
|
|
passphrase := getPassPhrase(ctx, "", false)
|
|
|
|
|
|
|
|
acct, err := am.ImportPreSaleKey(keyJson, passphrase)
|
|
|
|
if err != nil {
|
|
|
|
utils.Fatalf("Could not create the account: %v", err)
|
|
|
|
}
|
|
|
|
fmt.Printf("Address: %x\n", acct)
|
|
|
|
}
|
|
|
|
|
2015-03-23 15:00:06 +02:00
|
|
|
func accountImport(ctx *cli.Context) {
|
|
|
|
keyfile := ctx.Args().First()
|
|
|
|
if len(keyfile) == 0 {
|
|
|
|
utils.Fatalf("keyfile must be given as argument")
|
|
|
|
}
|
2015-05-27 15:50:31 +03:00
|
|
|
am := utils.MakeAccountManager(ctx)
|
2015-03-24 18:19:11 +02:00
|
|
|
passphrase := getPassPhrase(ctx, "Your new account is locked with a password. Please give a password. Do not forget this password.", true)
|
2015-03-23 15:00:06 +02:00
|
|
|
acct, err := am.Import(keyfile, passphrase)
|
|
|
|
if err != nil {
|
|
|
|
utils.Fatalf("Could not create the account: %v", err)
|
|
|
|
}
|
|
|
|
fmt.Printf("Address: %x\n", acct)
|
|
|
|
}
|
|
|
|
|
2015-03-17 15:12:34 +02:00
|
|
|
func makedag(ctx *cli.Context) {
|
2015-05-05 09:24:15 +03:00
|
|
|
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()
|
|
|
|
}
|
2015-03-17 15:12:34 +02:00
|
|
|
}
|
|
|
|
|
2015-03-06 04:00:41 +02:00
|
|
|
func version(c *cli.Context) {
|
2015-04-28 14:14:53 +03:00
|
|
|
fmt.Println(ClientIdentifier)
|
|
|
|
fmt.Println("Version:", Version)
|
|
|
|
if gitCommit != "" {
|
|
|
|
fmt.Println("Git Commit:", gitCommit)
|
|
|
|
}
|
2015-06-26 16:54:27 +03:00
|
|
|
fmt.Println("Protocol Versions:", eth.ProtocolVersions)
|
2015-04-28 14:14:53 +03:00
|
|
|
fmt.Println("Network Id:", c.GlobalInt(utils.NetworkIdFlag.Name))
|
|
|
|
fmt.Println("Go Version:", runtime.Version())
|
|
|
|
fmt.Println("OS:", runtime.GOOS)
|
|
|
|
fmt.Printf("GOPATH=%s\n", os.Getenv("GOPATH"))
|
|
|
|
fmt.Printf("GOROOT=%s\n", runtime.GOROOT())
|
2015-01-07 02:21:55 +02:00
|
|
|
}
|