aboutsummaryrefslogtreecommitdiffstats
path: root/cmd/utils
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/utils')
-rw-r--r--cmd/utils/cmd.go230
-rw-r--r--cmd/utils/flags.go190
2 files changed, 420 insertions, 0 deletions
diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go
new file mode 100644
index 000000000..99e60ff9e
--- /dev/null
+++ b/cmd/utils/cmd.go
@@ -0,0 +1,230 @@
+/*
+ This file is part of go-ethereum
+
+ 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>
+ * Viktor Tron <viktor@ethdev.com>
+ */
+package utils
+
+import (
+ "fmt"
+ "os"
+ "os/signal"
+ "regexp"
+
+ "github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/eth"
+ "github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/logger"
+ "github.com/ethereum/go-ethereum/rlp"
+ rpchttp "github.com/ethereum/go-ethereum/rpc/http"
+ "github.com/ethereum/go-ethereum/state"
+ "github.com/ethereum/go-ethereum/xeth"
+)
+
+var clilogger = logger.NewLogger("CLI")
+var interruptCallbacks = []func(os.Signal){}
+
+// Register interrupt handlers callbacks
+func RegisterInterrupt(cb func(os.Signal)) {
+ interruptCallbacks = append(interruptCallbacks, cb)
+}
+
+// go routine that call interrupt handlers in order of registering
+func HandleInterrupt() {
+ c := make(chan os.Signal, 1)
+ go func() {
+ signal.Notify(c, os.Interrupt)
+ for sig := range c {
+ clilogger.Errorf("Shutting down (%v) ... \n", sig)
+ RunInterruptCallbacks(sig)
+ }
+ }()
+}
+
+func RunInterruptCallbacks(sig os.Signal) {
+ for _, cb := range interruptCallbacks {
+ cb(sig)
+ }
+}
+
+func openLogFile(Datadir string, filename string) *os.File {
+ path := ethutil.AbsolutePath(Datadir, filename)
+ file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
+ if err != nil {
+ panic(fmt.Sprintf("error opening log file '%s': %v", filename, err))
+ }
+ return file
+}
+
+func confirm(message string) bool {
+ fmt.Println(message, "Are you sure? (y/n)")
+ var r string
+ fmt.Scanln(&r)
+ for ; ; fmt.Scanln(&r) {
+ if r == "n" || r == "y" {
+ break
+ } else {
+ fmt.Printf("Yes or no? (%s)", r)
+ }
+ }
+ return r == "y"
+}
+
+func initDataDir(Datadir string) {
+ _, err := os.Stat(Datadir)
+ if err != nil {
+ if os.IsNotExist(err) {
+ fmt.Printf("Data directory '%s' doesn't exist, creating it\n", Datadir)
+ os.Mkdir(Datadir, 0777)
+ }
+ }
+}
+
+func InitConfig(vmType int, ConfigFile string, Datadir string, EnvPrefix string) *ethutil.ConfigManager {
+ initDataDir(Datadir)
+ cfg := ethutil.ReadConfig(ConfigFile, Datadir, EnvPrefix)
+ cfg.VmType = vmType
+
+ return cfg
+}
+
+func exit(err error) {
+ status := 0
+ if err != nil {
+ fmt.Fprintln(os.Stderr, "Fatal: ", err)
+ status = 1
+ }
+ logger.Flush()
+ os.Exit(status)
+}
+
+// Fatalf formats a message to standard output and exits the program.
+func Fatalf(format string, args ...interface{}) {
+ fmt.Fprintf(os.Stderr, "Fatal: "+format+"\n", args...)
+ logger.Flush()
+ os.Exit(1)
+}
+
+func StartEthereum(ethereum *eth.Ethereum) {
+ clilogger.Infoln("Starting ", ethereum.Name())
+ if err := ethereum.Start(); err != nil {
+ exit(err)
+ }
+ RegisterInterrupt(func(sig os.Signal) {
+ ethereum.Stop()
+ logger.Flush()
+ })
+}
+
+func KeyTasks(keyManager *crypto.KeyManager, KeyRing string, GenAddr bool, SecretFile string, ExportDir string, NonInteractive bool) {
+ var err error
+ switch {
+ case GenAddr:
+ if NonInteractive || confirm("This action overwrites your old private key.") {
+ err = keyManager.Init(KeyRing, 0, true)
+ }
+ exit(err)
+ case len(SecretFile) > 0:
+ SecretFile = ethutil.ExpandHomePath(SecretFile)
+
+ if NonInteractive || confirm("This action overwrites your old private key.") {
+ err = keyManager.InitFromSecretsFile(KeyRing, 0, SecretFile)
+ }
+ exit(err)
+ case len(ExportDir) > 0:
+ err = keyManager.Init(KeyRing, 0, false)
+ if err == nil {
+ err = keyManager.Export(ExportDir)
+ }
+ exit(err)
+ default:
+ // Creates a keypair if none exists
+ err = keyManager.Init(KeyRing, 0, false)
+ if err != nil {
+ exit(err)
+ }
+ }
+ clilogger.Infof("Main address %x\n", keyManager.Address())
+}
+
+func StartRpc(ethereum *eth.Ethereum, RpcListenAddress string, RpcPort int) {
+ var err error
+ ethereum.RpcServer, err = rpchttp.NewRpcHttpServer(xeth.New(ethereum), RpcListenAddress, RpcPort)
+ if err != nil {
+ clilogger.Errorf("Could not start RPC interface (port %v): %v", RpcPort, err)
+ } else {
+ go ethereum.RpcServer.Start()
+ }
+}
+
+func FormatTransactionData(data string) []byte {
+ d := ethutil.StringToByteFunc(data, func(s string) (ret []byte) {
+ slice := regexp.MustCompile("\\n|\\s").Split(s, 1000000000)
+ for _, dataItem := range slice {
+ d := ethutil.FormatData(dataItem)
+ ret = append(ret, d...)
+ }
+ return
+ })
+
+ return d
+}
+
+// Replay block
+func BlockDo(ethereum *eth.Ethereum, hash []byte) error {
+ block := ethereum.ChainManager().GetBlock(hash)
+ if block == nil {
+ return fmt.Errorf("unknown block %x", hash)
+ }
+
+ parent := ethereum.ChainManager().GetBlock(block.ParentHash())
+
+ statedb := state.New(parent.Root(), ethereum.StateDb())
+ _, err := ethereum.BlockProcessor().TransitionState(statedb, parent, block, true)
+ if err != nil {
+ return err
+ }
+
+ return nil
+
+}
+
+func ImportChain(chain *core.ChainManager, fn string) error {
+ fmt.Printf("importing chain '%s'\n", fn)
+ fh, err := os.OpenFile(fn, os.O_RDONLY, os.ModePerm)
+ if err != nil {
+ return err
+ }
+ defer fh.Close()
+
+ var blocks types.Blocks
+ if err := rlp.Decode(fh, &blocks); err != nil {
+ return err
+ }
+
+ chain.Reset()
+ if err := chain.InsertChain(blocks); err != nil {
+ return err
+ }
+ fmt.Printf("imported %d blocks\n", len(blocks))
+
+ return nil
+}
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
new file mode 100644
index 000000000..88ff3558d
--- /dev/null
+++ b/cmd/utils/flags.go
@@ -0,0 +1,190 @@
+package utils
+
+import (
+ "crypto/ecdsa"
+ "path"
+ "runtime"
+
+ "github.com/codegangsta/cli"
+ "github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/eth"
+ "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/ethereum/go-ethereum/logger"
+ "github.com/ethereum/go-ethereum/p2p"
+ "github.com/ethereum/go-ethereum/p2p/nat"
+)
+
+// These are all the command line flags we support.
+// If you add to this list, please remember to include the
+// flag in the appropriate command definition.
+//
+// The flags are defined here so their names and help texts
+// are the same for all commands.
+
+var (
+ // General settings
+ /*
+ VMTypeFlag = cli.IntFlag{
+ Name: "vm",
+ Usage: "Virtual Machine type: 0 is standard VM, 1 is debug VM",
+ }
+ */
+ VMDebugFlag = cli.BoolFlag{
+ Name: "vmdebug",
+ Usage: "Virtual Machine debug output",
+ }
+ KeyRingFlag = cli.StringFlag{
+ Name: "keyring",
+ Usage: "Name of keyring to be used",
+ Value: "",
+ }
+ KeyStoreFlag = cli.StringFlag{
+ Name: "keystore",
+ Usage: `Where to store keyrings: "db" or "file"`,
+ Value: "db",
+ }
+ DataDirFlag = cli.StringFlag{
+ Name: "datadir",
+ Usage: "Data directory to be used",
+ Value: ethutil.DefaultDataDir(),
+ }
+ MinerThreadsFlag = cli.IntFlag{
+ Name: "minerthreads",
+ Usage: "Number of miner threads",
+ Value: runtime.NumCPU(),
+ }
+ MiningEnabledFlag = cli.BoolFlag{
+ Name: "mine",
+ Usage: "Enable mining",
+ }
+
+ LogFileFlag = cli.StringFlag{
+ Name: "logfile",
+ Usage: "Send log output to a file",
+ }
+ LogLevelFlag = cli.IntFlag{
+ Name: "loglevel",
+ Usage: "0-5 (silent, error, warn, info, debug, debug detail)",
+ Value: int(logger.InfoLevel),
+ }
+ LogFormatFlag = cli.StringFlag{
+ Name: "logformat",
+ Usage: `"std" or "raw"`,
+ Value: "std",
+ }
+
+ // RPC settings
+ RPCEnabledFlag = cli.BoolFlag{
+ Name: "rpc",
+ Usage: "Whether RPC server is enabled",
+ }
+ RPCListenAddrFlag = cli.StringFlag{
+ Name: "rpcaddr",
+ Usage: "Listening address for the JSON-RPC server",
+ Value: "127.0.0.1",
+ }
+ RPCPortFlag = cli.IntFlag{
+ Name: "rpcport",
+ Usage: "Port on which the JSON-RPC server should listen",
+ Value: 8545,
+ }
+
+ // Network Settings
+ MaxPeersFlag = cli.IntFlag{
+ Name: "maxpeers",
+ Usage: "Maximum number of network peers",
+ Value: 16,
+ }
+ ListenPortFlag = cli.IntFlag{
+ Name: "port",
+ Usage: "Network listening port",
+ Value: 30303,
+ }
+ BootnodesFlag = cli.StringFlag{
+ Name: "bootnodes",
+ Usage: "Space-separated enode URLs for discovery bootstrap",
+ Value: "",
+ }
+ NodeKeyFileFlag = cli.StringFlag{
+ Name: "nodekey",
+ Usage: "P2P node key file",
+ }
+ NodeKeyHexFlag = cli.StringFlag{
+ Name: "nodekeyhex",
+ Usage: "P2P node key as hex (for testing)",
+ }
+ NATFlag = cli.StringFlag{
+ Name: "nat",
+ Usage: "Port mapping mechanism (any|none|upnp|pmp|extip:<IP>)",
+ Value: "any",
+ }
+)
+
+func GetNAT(ctx *cli.Context) nat.Interface {
+ natif, err := nat.Parse(ctx.GlobalString(NATFlag.Name))
+ if err != nil {
+ Fatalf("Option %s: %v", NATFlag.Name, err)
+ }
+ return natif
+}
+
+func GetNodeKey(ctx *cli.Context) (key *ecdsa.PrivateKey) {
+ hex, file := ctx.GlobalString(NodeKeyHexFlag.Name), ctx.GlobalString(NodeKeyFileFlag.Name)
+ var err error
+ switch {
+ case file != "" && hex != "":
+ Fatalf("Options %q and %q are mutually exclusive", NodeKeyFileFlag.Name, NodeKeyHexFlag.Name)
+ case file != "":
+ if key, err = crypto.LoadECDSA(file); err != nil {
+ Fatalf("Option %q: %v", NodeKeyFileFlag.Name, err)
+ }
+ case hex != "":
+ if key, err = crypto.HexToECDSA(hex); err != nil {
+ Fatalf("Option %q: %v", NodeKeyHexFlag.Name, err)
+ }
+ }
+ return key
+}
+
+func GetEthereum(clientID, version string, ctx *cli.Context) *eth.Ethereum {
+ ethereum, err := eth.New(&eth.Config{
+ Name: p2p.MakeName(clientID, version),
+ KeyStore: ctx.GlobalString(KeyStoreFlag.Name),
+ DataDir: ctx.GlobalString(DataDirFlag.Name),
+ LogFile: ctx.GlobalString(LogFileFlag.Name),
+ LogLevel: ctx.GlobalInt(LogLevelFlag.Name),
+ LogFormat: ctx.GlobalString(LogFormatFlag.Name),
+ MinerThreads: ctx.GlobalInt(MinerThreadsFlag.Name),
+ VmDebug: ctx.GlobalBool(VMDebugFlag.Name),
+
+ MaxPeers: ctx.GlobalInt(MaxPeersFlag.Name),
+ Port: ctx.GlobalString(ListenPortFlag.Name),
+ NAT: GetNAT(ctx),
+ NodeKey: GetNodeKey(ctx),
+ KeyRing: ctx.GlobalString(KeyRingFlag.Name),
+ Shh: true,
+ Dial: true,
+ BootNodes: ctx.GlobalString(BootnodesFlag.Name),
+ })
+ if err != nil {
+ exit(err)
+ }
+ return ethereum
+}
+
+func GetChain(ctx *cli.Context) (*core.ChainManager, ethutil.Database, ethutil.Database) {
+ dataDir := ctx.GlobalString(DataDirFlag.Name)
+ blockDb, err := ethdb.NewLDBDatabase(path.Join(dataDir, "blockchain"))
+ if err != nil {
+ Fatalf("Could not open database: %v", err)
+ }
+
+ stateDb, err := ethdb.NewLDBDatabase(path.Join(dataDir, "state"))
+ if err != nil {
+ Fatalf("Could not open database: %v", err)
+ }
+ return core.NewChainManager(blockDb, stateDb, new(event.TypeMux)), blockDb, stateDb
+}