2015-01-06 11:13:57 +00:00
|
|
|
/*
|
|
|
|
This file is part of go-ethereum
|
2014-10-23 13:48:53 +00:00
|
|
|
|
2015-01-06 11:13:57 +00: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 11:20:59 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2014-08-06 07:53:12 +00:00
|
|
|
"fmt"
|
|
|
|
"os"
|
2014-07-29 23:05:40 +00:00
|
|
|
"runtime"
|
2015-03-06 02:00:41 +00:00
|
|
|
"strconv"
|
2014-12-23 17:35:36 +00:00
|
|
|
"time"
|
2014-07-29 23:05:40 +00:00
|
|
|
|
2015-03-06 02:00:41 +00:00
|
|
|
"github.com/codegangsta/cli"
|
2014-10-31 13:20:11 +00:00
|
|
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
2014-12-04 09:53:49 +00:00
|
|
|
"github.com/ethereum/go-ethereum/core/types"
|
2015-01-04 13:20:16 +00:00
|
|
|
"github.com/ethereum/go-ethereum/eth"
|
2014-10-23 13:01:27 +00:00
|
|
|
"github.com/ethereum/go-ethereum/ethutil"
|
2014-10-31 11:56:05 +00:00
|
|
|
"github.com/ethereum/go-ethereum/logger"
|
2015-01-07 12:17:48 +00:00
|
|
|
"github.com/ethereum/go-ethereum/state"
|
2014-06-23 11:20:59 +00:00
|
|
|
)
|
|
|
|
|
2014-07-03 16:36:24 +00:00
|
|
|
const (
|
|
|
|
ClientIdentifier = "Ethereum(G)"
|
2015-03-07 23:59:26 +00:00
|
|
|
Version = "0.9.0"
|
2014-07-03 16:36:24 +00:00
|
|
|
)
|
|
|
|
|
2015-03-06 02:00:41 +00:00
|
|
|
var (
|
|
|
|
clilogger = logger.NewLogger("CLI")
|
|
|
|
app = cli.NewApp()
|
|
|
|
)
|
2014-06-23 11:20:59 +00:00
|
|
|
|
2015-03-06 02:00:41 +00:00
|
|
|
func init() {
|
|
|
|
app.Version = Version
|
|
|
|
app.Usage = "the go-ethereum command-line client"
|
|
|
|
app.Action = run
|
|
|
|
app.HideVersion = true // we have a command to print the version
|
|
|
|
app.Commands = []cli.Command{
|
|
|
|
{
|
|
|
|
Action: version,
|
|
|
|
Name: "version",
|
|
|
|
Usage: "print ethereum version numbers",
|
|
|
|
Description: `
|
|
|
|
The output of this command is supposed to be machine-readable.
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Action: dump,
|
|
|
|
Name: "dump",
|
|
|
|
Usage: `dump a specific block from storage`,
|
|
|
|
Description: `
|
|
|
|
The arguments are interpreted as block numbers or hashes.
|
|
|
|
Use "ethereum dump 0" to dump the genesis block.
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Action: runjs,
|
|
|
|
Name: "js",
|
|
|
|
Usage: `interactive JavaScript console`,
|
|
|
|
Description: `
|
|
|
|
In the console, you can use the eth object to interact
|
|
|
|
with the running ethereum stack. The API does not match
|
|
|
|
ethereum.js.
|
|
|
|
|
|
|
|
A JavaScript file can be provided as the argument. The
|
|
|
|
runtime will execute the file and exit.
|
|
|
|
`,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Action: importchain,
|
|
|
|
Name: "import",
|
|
|
|
Usage: `import a blockchain file`,
|
|
|
|
},
|
2015-03-08 15:44:48 +00:00
|
|
|
{
|
|
|
|
Action: exportchain,
|
|
|
|
Name: "export",
|
|
|
|
Usage: `export blockchain into file`,
|
|
|
|
},
|
2015-03-06 02:00:41 +00:00
|
|
|
}
|
|
|
|
app.Author = ""
|
|
|
|
app.Email = ""
|
|
|
|
app.Flags = []cli.Flag{
|
|
|
|
utils.BootnodesFlag,
|
|
|
|
utils.DataDirFlag,
|
|
|
|
utils.KeyRingFlag,
|
|
|
|
utils.KeyStoreFlag,
|
|
|
|
utils.ListenPortFlag,
|
|
|
|
utils.LogFileFlag,
|
|
|
|
utils.LogFormatFlag,
|
|
|
|
utils.LogLevelFlag,
|
|
|
|
utils.MaxPeersFlag,
|
|
|
|
utils.MinerThreadsFlag,
|
|
|
|
utils.MiningEnabledFlag,
|
|
|
|
utils.NATFlag,
|
|
|
|
utils.NodeKeyFileFlag,
|
|
|
|
utils.NodeKeyHexFlag,
|
|
|
|
utils.RPCEnabledFlag,
|
|
|
|
utils.RPCListenAddrFlag,
|
|
|
|
utils.RPCPortFlag,
|
2015-03-06 15:58:52 +00:00
|
|
|
utils.VMDebugFlag,
|
|
|
|
//utils.VMTypeFlag,
|
2015-03-06 02:00:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// missing:
|
|
|
|
// flag.StringVar(&ConfigFile, "conf", defaultConfigFile, "config file")
|
|
|
|
// flag.BoolVar(&DiffTool, "difftool", false, "creates output for diff'ing. Sets LogLevel=0")
|
|
|
|
// flag.StringVar(&DiffType, "diff", "all", "sets the level of diff output [vm, all]. Has no effect if difftool=false")
|
2014-06-23 11:20:59 +00:00
|
|
|
|
2015-03-06 02:00:41 +00:00
|
|
|
// potential subcommands:
|
|
|
|
// flag.StringVar(&SecretFile, "import", "", "imports the file given (hex or mnemonic formats)")
|
|
|
|
// flag.StringVar(&ExportDir, "export", "", "exports the session keyring to files in the directory given")
|
|
|
|
// flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key")
|
|
|
|
}
|
2014-12-23 13:33:15 +00:00
|
|
|
|
2015-03-06 02:00:41 +00: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 09:47:45 +00:00
|
|
|
|
2015-03-06 02:00:41 +00:00
|
|
|
func run(ctx *cli.Context) {
|
|
|
|
fmt.Printf("Welcome to the FRONTIER\n")
|
2015-03-06 11:18:44 +00:00
|
|
|
utils.HandleInterrupt()
|
2015-03-06 02:00:41 +00:00
|
|
|
eth := utils.GetEthereum(ClientIdentifier, Version, ctx)
|
|
|
|
startEth(ctx, eth)
|
|
|
|
// this blocks the thread
|
|
|
|
eth.WaitForShutdown()
|
|
|
|
}
|
2014-07-11 14:04:27 +00:00
|
|
|
|
2015-03-06 02:00:41 +00:00
|
|
|
func runjs(ctx *cli.Context) {
|
|
|
|
eth := utils.GetEthereum(ClientIdentifier, Version, ctx)
|
|
|
|
startEth(ctx, eth)
|
|
|
|
if len(ctx.Args()) == 0 {
|
2015-03-06 11:18:44 +00:00
|
|
|
runREPL(eth)
|
|
|
|
eth.Stop()
|
2015-03-06 02:00:41 +00:00
|
|
|
eth.WaitForShutdown()
|
|
|
|
} else if len(ctx.Args()) == 1 {
|
|
|
|
execJsFile(eth, ctx.Args()[0])
|
|
|
|
} else {
|
|
|
|
utils.Fatalf("This command can handle at most one argument.")
|
2015-01-07 00:21:55 +00:00
|
|
|
}
|
2015-03-06 02:00:41 +00:00
|
|
|
}
|
2015-01-07 00:21:55 +00:00
|
|
|
|
2015-03-06 02:00:41 +00:00
|
|
|
func startEth(ctx *cli.Context, eth *eth.Ethereum) {
|
|
|
|
utils.StartEthereum(eth)
|
|
|
|
if ctx.GlobalBool(utils.RPCEnabledFlag.Name) {
|
|
|
|
addr := ctx.GlobalString(utils.RPCListenAddrFlag.Name)
|
|
|
|
port := ctx.GlobalInt(utils.RPCPortFlag.Name)
|
|
|
|
utils.StartRpc(eth, addr, port)
|
|
|
|
}
|
|
|
|
if ctx.GlobalBool(utils.MiningEnabledFlag.Name) {
|
|
|
|
eth.Miner().Start()
|
|
|
|
}
|
|
|
|
}
|
2015-01-05 16:10:42 +00:00
|
|
|
|
2015-03-06 02:00:41 +00:00
|
|
|
func importchain(ctx *cli.Context) {
|
|
|
|
if len(ctx.Args()) != 1 {
|
|
|
|
utils.Fatalf("This command requires an argument.")
|
|
|
|
}
|
2015-03-08 15:44:48 +00:00
|
|
|
chainmgr, _, _ := utils.GetChain(ctx)
|
2015-03-06 02:00:41 +00:00
|
|
|
start := time.Now()
|
2015-03-08 15:44:48 +00:00
|
|
|
err := utils.ImportChain(chainmgr, ctx.Args().First())
|
2014-08-22 10:14:37 +00:00
|
|
|
if err != nil {
|
2015-03-06 02:00:41 +00:00
|
|
|
utils.Fatalf("Import error: %v\n", err)
|
2014-08-22 10:14:37 +00:00
|
|
|
}
|
2015-03-08 15:44:48 +00:00
|
|
|
fmt.Printf("Import done in %v", time.Since(start))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func exportchain(ctx *cli.Context) {
|
|
|
|
if len(ctx.Args()) != 1 {
|
|
|
|
utils.Fatalf("This command requires an argument.")
|
|
|
|
}
|
|
|
|
chainmgr, _, _ := utils.GetChain(ctx)
|
|
|
|
start := time.Now()
|
|
|
|
err := utils.ExportChain(chainmgr, ctx.Args().First())
|
|
|
|
if err != nil {
|
|
|
|
utils.Fatalf("Export error: %v\n", err)
|
|
|
|
}
|
|
|
|
fmt.Printf("Export done in %v", time.Since(start))
|
2015-03-06 02:00:41 +00:00
|
|
|
return
|
|
|
|
}
|
2015-01-05 16:10:42 +00:00
|
|
|
|
2015-03-06 02:00:41 +00:00
|
|
|
func dump(ctx *cli.Context) {
|
2015-03-08 15:44:48 +00:00
|
|
|
chainmgr, _, stateDb := utils.GetChain(ctx)
|
2015-03-06 02:00:41 +00:00
|
|
|
for _, arg := range ctx.Args() {
|
2014-11-18 18:52:45 +00:00
|
|
|
var block *types.Block
|
2015-03-06 02:00:41 +00:00
|
|
|
if hashish(arg) {
|
2015-03-08 15:44:48 +00:00
|
|
|
block = chainmgr.GetBlock(ethutil.Hex2Bytes(arg))
|
2014-08-06 07:53:12 +00:00
|
|
|
} else {
|
2015-03-06 02:00:41 +00:00
|
|
|
num, _ := strconv.Atoi(arg)
|
2015-03-08 15:44:48 +00:00
|
|
|
block = chainmgr.GetBlockByNumber(uint64(num))
|
2014-08-06 07:53:12 +00:00
|
|
|
}
|
|
|
|
if block == nil {
|
|
|
|
fmt.Println("{}")
|
2015-03-06 02:00:41 +00:00
|
|
|
utils.Fatalf("block not found")
|
|
|
|
} else {
|
2015-03-06 17:26:16 +00:00
|
|
|
statedb := state.New(block.Root(), stateDb)
|
2015-03-06 02:00:41 +00:00
|
|
|
fmt.Printf("%s\n", statedb.Dump())
|
|
|
|
// fmt.Println(block)
|
2014-12-23 13:33:15 +00:00
|
|
|
}
|
2015-02-28 22:01:41 +00:00
|
|
|
}
|
2015-03-06 02:00:41 +00:00
|
|
|
}
|
2015-02-28 22:01:41 +00:00
|
|
|
|
2015-03-06 02:00:41 +00:00
|
|
|
// hashish returns true for strings that look like hashes.
|
|
|
|
func hashish(x string) bool {
|
|
|
|
_, err := strconv.Atoi(x)
|
|
|
|
return err != nil
|
2014-06-23 11:20:59 +00:00
|
|
|
}
|
2015-01-07 00:21:55 +00:00
|
|
|
|
2015-03-06 02:00:41 +00:00
|
|
|
func version(c *cli.Context) {
|
2015-01-07 00:21:55 +00:00
|
|
|
fmt.Printf(`%v %v
|
|
|
|
PV=%d
|
|
|
|
GOOS=%s
|
|
|
|
GO=%s
|
|
|
|
GOPATH=%s
|
|
|
|
GOROOT=%s
|
|
|
|
`, ClientIdentifier, Version, eth.ProtocolVersion, runtime.GOOS, runtime.Version(), os.Getenv("GOPATH"), runtime.GOROOT())
|
|
|
|
}
|