main.go 14.6 KB
Newer Older
F
Felix Lange 已提交
1 2 3 4 5 6 7 8 9 10
// Copyright 2014 The go-ethereum Authors
// 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
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
F
Felix Lange 已提交
12 13 14
// GNU General Public License for more details.
//
// 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/>.
F
Felix Lange 已提交
16

17
// geth is the official command-line client for Ethereum.
18 19 20
package main

import (
21
	"encoding/hex"
O
obscuren 已提交
22
	"fmt"
23
	"io/ioutil"
O
obscuren 已提交
24
	"os"
25
	"os/signal"
26
	"path/filepath"
O
obscuren 已提交
27
	"runtime"
28
	"strconv"
29
	"strings"
30
	"time"
O
obscuren 已提交
31

32
	"github.com/codegangsta/cli"
33
	"github.com/ethereum/ethash"
O
obscuren 已提交
34
	"github.com/ethereum/go-ethereum/cmd/utils"
Z
zelig 已提交
35
	"github.com/ethereum/go-ethereum/common"
36
	"github.com/ethereum/go-ethereum/core"
O
obscuren 已提交
37
	"github.com/ethereum/go-ethereum/eth"
38
	"github.com/ethereum/go-ethereum/ethdb"
39
	"github.com/ethereum/go-ethereum/internal/debug"
O
obscuren 已提交
40
	"github.com/ethereum/go-ethereum/logger"
41
	"github.com/ethereum/go-ethereum/logger/glog"
42
	"github.com/ethereum/go-ethereum/metrics"
43
	"github.com/ethereum/go-ethereum/node"
44
	"github.com/ethereum/go-ethereum/params"
45
	"github.com/ethereum/go-ethereum/release"
46
	"github.com/ethereum/go-ethereum/rlp"
47 48
)

Z
zelig 已提交
49
const (
50 51 52 53 54 55 56
	clientIdentifier = "Geth"     // Client identifier to advertise over the network
	versionMajor     = 1          // Major version component of the current release
	versionMinor     = 5          // Minor version component of the current release
	versionPatch     = 0          // Patch version component of the current release
	versionMeta      = "unstable" // Version metadata to append to the version string

	versionOracle = "0x48a117313039b73ab02fb9f73e04a66defe123ec" // Ethereum address of the Geth release oracle
Z
zelig 已提交
57 58
)

59
var (
60 61 62 63
	gitCommit string         // Git SHA1 commit hash of the release (set via linker flags)
	verString string         // Combined textual representation of all the version components
	relConfig release.Config // Structured version information and release oracle config
	app       *cli.App
64
)
65

66
func init() {
67 68 69 70 71 72 73
	// Construct the textual version string from the individual components
	verString = fmt.Sprintf("%d.%d.%d", versionMajor, versionMinor, versionPatch)
	if versionMeta != "" {
		verString += "-" + versionMeta
	}
	if gitCommit != "" {
		verString += "-" + gitCommit[:8]
74
	}
75 76
	// Construct the version release oracle configuration
	relConfig.Oracle = common.HexToAddress(versionOracle)
77

78 79 80 81 82 83 84 85 86
	relConfig.Major = uint32(versionMajor)
	relConfig.Minor = uint32(versionMinor)
	relConfig.Patch = uint32(versionPatch)

	commit, _ := hex.DecodeString(gitCommit)
	copy(relConfig.Commit[:], commit)

	// Initialize the CLI app and start Geth
	app = utils.NewApp(verString, "the go-ethereum command line interface")
87
	app.Action = geth
88 89
	app.HideVersion = true // we have a command to print the version
	app.Commands = []cli.Command{
90 91 92 93 94
		importCommand,
		exportCommand,
		upgradedbCommand,
		removedbCommand,
		dumpCommand,
95
		monitorCommand,
96 97
		accountCommand,
		walletCommand,
98 99 100 101 102 103 104 105 106
		{
			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.
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
`,
		},
		{
			Action: gpuinfo,
			Name:   "gpuinfo",
			Usage:  "gpuinfo",
			Description: `
Prints OpenCL device info for all found GPUs.
`,
		},
		{
			Action: gpubench,
			Name:   "gpubench",
			Usage:  "benchmark GPU",
			Description: `
Runs quick benchmark on first GPU found.
123 124
`,
		},
125 126 127 128 129 130 131 132
		{
			Action: version,
			Name:   "version",
			Usage:  "print ethereum version numbers",
			Description: `
The output of this command is supposed to be machine-readable.
`,
		},
133 134 135 136 137 138 139 140 141 142
		{
			Action: initGenesis,
			Name:   "init",
			Usage:  "bootstraps and initialises a new genesis block (JSON)",
			Description: `
The init command initialises a new genesis block and definition for the network.
This is a destructive action and changes the network in which you will be
participating.
`,
		},
143
		{
Z
CLI:  
zelig 已提交
144 145
			Action: console,
			Name:   "console",
O
obscuren 已提交
146
			Usage:  `Geth Console: interactive JavaScript environment`,
Z
CLI:  
zelig 已提交
147
			Description: `
O
obscuren 已提交
148
The Geth console is an interactive shell for the JavaScript runtime environment
149 150
which exposes a node admin interface as well as the Ðapp JavaScript API.
See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console
151 152
`,
		},
B
Bas van Kervel 已提交
153 154 155
		{
			Action: attach,
			Name:   "attach",
B
Bas van Kervel 已提交
156
			Usage:  `Geth Console: interactive JavaScript environment (connect to node)`,
B
Bas van Kervel 已提交
157
			Description: `
158 159 160 161 162
		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.
		`,
Z
CLI:  
zelig 已提交
163 164
		},
		{
165
			Action: execScripts,
166
			Name:   "js",
O
obscuren 已提交
167
			Usage:  `executes the given JavaScript files in the Geth JavaScript VM`,
168
			Description: `
169
The JavaScript VM exposes a node admin interface as well as the Ðapp
Z
zelig 已提交
170
JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console
171 172 173
`,
		},
	}
174

175
	app.Flags = []cli.Flag{
176
		utils.IdentityFlag,
177
		utils.UnlockedAccountFlag,
Z
zelig 已提交
178
		utils.PasswordFileFlag,
179
		utils.GenesisFileFlag,
180 181
		utils.BootnodesFlag,
		utils.DataDirFlag,
K
Kobi Gurkan 已提交
182
		utils.KeyStoreDirFlag,
183
		utils.BlockchainVersionFlag,
184
		utils.OlympicFlag,
185
		utils.FastSyncFlag,
186
		utils.CacheFlag,
187
		utils.LightKDFFlag,
Z
CLI:  
zelig 已提交
188
		utils.JSpathFlag,
189 190
		utils.ListenPortFlag,
		utils.MaxPeersFlag,
191
		utils.MaxPendingPeersFlag,
Z
zelig 已提交
192
		utils.EtherbaseFlag,
193
		utils.GasPriceFlag,
194 195
		utils.MinerThreadsFlag,
		utils.MiningEnabledFlag,
196
		utils.MiningGPUFlag,
197
		utils.AutoDAGFlag,
198
		utils.TargetGasLimitFlag,
199
		utils.NATFlag,
200
		utils.NatspecEnabledFlag,
201
		utils.NoDiscoverFlag,
202 203 204 205 206
		utils.NodeKeyFileFlag,
		utils.NodeKeyHexFlag,
		utils.RPCEnabledFlag,
		utils.RPCListenAddrFlag,
		utils.RPCPortFlag,
207 208 209 210 211
		utils.RPCApiFlag,
		utils.WSEnabledFlag,
		utils.WSListenAddrFlag,
		utils.WSPortFlag,
		utils.WSApiFlag,
B
Bas van Kervel 已提交
212
		utils.WSAllowedOriginsFlag,
B
Bas van Kervel 已提交
213 214 215
		utils.IPCDisabledFlag,
		utils.IPCApiFlag,
		utils.IPCPathFlag,
216
		utils.ExecFlag,
217
		utils.PreLoadJSFlag,
218
		utils.WhisperEnabledFlag,
219
		utils.DevModeFlag,
220
		utils.TestNetFlag,
221 222 223
		utils.VMForceJitFlag,
		utils.VMJitCacheFlag,
		utils.VMEnableJitFlag,
Z
zelig 已提交
224
		utils.NetworkIdFlag,
225
		utils.RPCCORSDomainFlag,
226
		utils.MetricsEnabledFlag,
227
		utils.FakePoWFlag,
228
		utils.SolcPathFlag,
Z
zsfelfoldi 已提交
229 230 231 232 233 234
		utils.GpoMinGasPriceFlag,
		utils.GpoMaxGasPriceFlag,
		utils.GpoFullBlockRatioFlag,
		utils.GpobaseStepDownFlag,
		utils.GpobaseStepUpFlag,
		utils.GpobaseCorrectionFactorFlag,
Z
zelig 已提交
235
		utils.ExtraDataFlag,
236
	}
237 238
	app.Flags = append(app.Flags, debug.Flags...)

239
	app.Before = func(ctx *cli.Context) error {
240
		runtime.GOMAXPROCS(runtime.NumCPU())
241 242 243 244 245
		if err := debug.Setup(ctx); err != nil {
			return err
		}
		// Start system runtime metrics collection
		go metrics.CollectProcessMetrics(3 * time.Second)
246

247
		utils.SetupNetwork(ctx)
248 249 250 251 252 253

		// Deprecation warning.
		if ctx.GlobalIsSet(utils.GenesisFileFlag.Name) {
			common.PrintDepricationWarning("--genesis is deprecated. Switch to use 'geth init /path/to/file'")
		}

254
		return nil
255
	}
256 257 258 259

	app.After = func(ctx *cli.Context) error {
		logger.Flush()
		debug.Exit()
260
		utils.Stdin.Close() // Resets terminal mode.
261 262
		return nil
	}
263
}
O
obscuren 已提交
264

265 266 267 268 269 270
func main() {
	if err := app.Run(os.Args); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
Z
zelig 已提交
271

272 273 274 275 276 277
func makeDefaultExtra() []byte {
	var clientInfo = struct {
		Version   uint
		Name      string
		GoVersion string
		Os        string
278
	}{uint(versionMajor<<16 | versionMinor<<8 | versionPatch), clientIdentifier, runtime.Version(), runtime.GOOS}
279 280 281 282 283 284 285 286 287 288 289 290 291
	extra, err := rlp.EncodeToBytes(clientInfo)
	if err != nil {
		glog.V(logger.Warn).Infoln("error setting canonical miner information:", err)
	}

	if uint64(len(extra)) > params.MaximumExtraDataSize.Uint64() {
		glog.V(logger.Warn).Infoln("error setting canonical miner information: extra exceeds", params.MaximumExtraDataSize)
		glog.V(logger.Debug).Infof("extra: %x\n", extra)
		return nil
	}
	return extra
}

292 293 294 295
// geth is the main entry point into the system if no special subcommand is ran.
// It creates a default node based on the command line arguments and runs it in
// blocking mode, waiting for it to be shut down.
func geth(ctx *cli.Context) {
296
	node := utils.MakeSystemNode(clientIdentifier, verString, relConfig, makeDefaultExtra(), ctx)
297 298
	startNode(ctx, node)
	node.Wait()
299
}
300

301
// attach will connect to a running geth instance attaching a JavaScript console and to it.
B
Bas van Kervel 已提交
302
func attach(ctx *cli.Context) {
303 304
	// attach to a running geth instance
	client, err := utils.NewRemoteRPCClient(ctx)
B
Bas van Kervel 已提交
305
	if err != nil {
306
		utils.Fatalf("Unable to attach to geth: %v", err)
B
Bas van Kervel 已提交
307 308 309
	}

	repl := newLightweightJSRE(
310
		ctx.GlobalString(utils.JSpathFlag.Name),
B
Bas van Kervel 已提交
311
		client,
B
Bas van Kervel 已提交
312
		ctx.GlobalString(utils.DataDirFlag.Name),
B
Bas van Kervel 已提交
313
		true,
B
Bas van Kervel 已提交
314
	)
B
Bas van Kervel 已提交
315

316 317 318 319 320 321 322
	// 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
323 324 325 326 327 328
	if ctx.GlobalString(utils.ExecFlag.Name) != "" {
		repl.batch(ctx.GlobalString(utils.ExecFlag.Name))
	} else {
		repl.welcome()
		repl.interactive()
	}
B
Bas van Kervel 已提交
329 330
}

331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
// initGenesis will initialise the given JSON format genesis file and writes it as
// the zero'd block (i.e. genesis) or will fail hard if it can't succeed.
func initGenesis(ctx *cli.Context) {
	genesisPath := ctx.Args().First()
	if len(genesisPath) == 0 {
		utils.Fatalf("must supply path to genesis JSON file")
	}

	chainDb, err := ethdb.NewLDBDatabase(filepath.Join(utils.MustMakeDataDir(ctx), "chaindata"), 0, 0)
	if err != nil {
		utils.Fatalf("could not open database: %v", err)
	}

	genesisFile, err := os.Open(genesisPath)
	if err != nil {
		utils.Fatalf("failed to read genesis file: %v", err)
	}

	block, err := core.WriteGenesisBlock(chainDb, genesisFile)
	if err != nil {
		utils.Fatalf("failed to write genesis block: %v", err)
	}
	glog.V(logger.Info).Infof("successfully wrote genesis block and/or chain rule set: %x", block.Hash())
}

356 357
// console starts a new geth node, attaching a JavaScript console to it at the
// same time.
Z
CLI:  
zelig 已提交
358
func console(ctx *cli.Context) {
359
	// Create and start the node based on the CLI flags
360
	node := utils.MakeSystemNode(clientIdentifier, verString, relConfig, makeDefaultExtra(), ctx)
361
	startNode(ctx, node)
362

363
	// Attach to the newly started node, and either execute script or become interactive
364
	client, err := node.Attach()
365 366 367
	if err != nil {
		utils.Fatalf("Failed to attach to the inproc geth: %v", err)
	}
368
	repl := newJSRE(node,
369
		ctx.GlobalString(utils.JSpathFlag.Name),
370
		ctx.GlobalString(utils.RPCCORSDomainFlag.Name),
371
		client, true)
B
Bas van Kervel 已提交
372

373 374 375
	// preload user defined JS files into the console
	err = repl.preloadJSFiles(ctx)
	if err != nil {
376
		utils.Fatalf("%v", err)
377 378 379
	}

	// in case the exec flag holds a JS statement execute it and return
380 381
	if script := ctx.GlobalString(utils.ExecFlag.Name); script != "" {
		repl.batch(script)
382 383 384 385
	} else {
		repl.welcome()
		repl.interactive()
	}
386
	node.Stop()
Z
CLI:  
zelig 已提交
387 388
}

389 390 391 392
// 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
393
	node := utils.MakeSystemNode(clientIdentifier, verString, relConfig, makeDefaultExtra(), ctx)
394
	startNode(ctx, node)
395
	defer node.Stop()
Z
CLI:  
zelig 已提交
396

397
	// Attach to the newly started node and execute the given scripts
398
	client, err := node.Attach()
399 400 401
	if err != nil {
		utils.Fatalf("Failed to attach to the inproc geth: %v", err)
	}
402
	repl := newJSRE(node,
403
		ctx.GlobalString(utils.JSpathFlag.Name),
404
		ctx.GlobalString(utils.RPCCORSDomainFlag.Name),
405
		client, false)
406

407
	// Run all given files.
Z
CLI:  
zelig 已提交
408
	for _, file := range ctx.Args() {
409 410 411
		if err = repl.re.Exec(file); err != nil {
			break
		}
Z
CLI:  
zelig 已提交
412
	}
413 414 415 416 417 418 419 420 421 422 423 424
	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)
425
}
O
obscuren 已提交
426

427 428 429 430 431 432
// 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)
433

434 435
	// Unlock any account specifically requested
	var ethereum *eth.Ethereum
436
	if err := stack.Service(&ethereum); err != nil {
437
		utils.Fatalf("ethereum service not running: %v", err)
438
	}
439 440
	accman := ethereum.AccountManager()
	passwords := utils.MakePasswordList(ctx)
Z
zelig 已提交
441

442
	accounts := strings.Split(ctx.GlobalString(utils.UnlockedAccountFlag.Name), ",")
443
	for i, account := range accounts {
444 445
		if trimmed := strings.TrimSpace(account); trimmed != "" {
			unlockAccount(ctx, accman, trimmed, i, passwords)
Z
zelig 已提交
446
		}
Z
zelig 已提交
447
	}
448
	// Start auxiliary services if enabled
449
	if ctx.GlobalBool(utils.MiningEnabledFlag.Name) {
450 451
		if err := ethereum.StartMining(ctx.GlobalInt(utils.MinerThreadsFlag.Name), ctx.GlobalString(utils.MiningGPUFlag.Name)); err != nil {
			utils.Fatalf("Failed to start mining: %v", err)
452
		}
453 454
	}
}
O
Merge  
obscuren 已提交
455

456
func makedag(ctx *cli.Context) {
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482
	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()
	}
483 484
}

485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507
func gpuinfo(ctx *cli.Context) {
	eth.PrintOpenCLDevices()
}

func gpubench(ctx *cli.Context) {
	args := ctx.Args()
	wrongArgs := func() {
		utils.Fatalf(`Usage: geth gpubench <gpu number>`)
	}
	switch {
	case len(args) == 1:
		n, err := strconv.ParseUint(args[0], 0, 64)
		if err != nil {
			wrongArgs()
		}
		eth.GPUBench(n)
	case len(args) == 0:
		eth.GPUBench(0)
	default:
		wrongArgs()
	}
}

508
func version(c *cli.Context) {
509 510
	fmt.Println(clientIdentifier)
	fmt.Println("Version:", version)
511
	fmt.Println("Protocol Versions:", eth.ProtocolVersions)
512 513 514 515 516
	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())
O
obscuren 已提交
517
}