main.go 8.78 KB
Newer Older
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
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/>.
Felix Lange's avatar
Felix Lange committed
16

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

import (
obscuren's avatar
obscuren committed
21 22
	"fmt"
	"os"
obscuren's avatar
obscuren committed
23
	"runtime"
24
	"sort"
25
	"strings"
26
	"time"
obscuren's avatar
obscuren committed
27

28
	"github.com/ethereum/go-ethereum/accounts"
29
	"github.com/ethereum/go-ethereum/accounts/keystore"
obscuren's avatar
obscuren committed
30
	"github.com/ethereum/go-ethereum/cmd/utils"
31
	"github.com/ethereum/go-ethereum/common"
32
	"github.com/ethereum/go-ethereum/console"
obscuren's avatar
obscuren committed
33
	"github.com/ethereum/go-ethereum/eth"
34
	"github.com/ethereum/go-ethereum/ethclient"
35
	"github.com/ethereum/go-ethereum/internal/debug"
36
	"github.com/ethereum/go-ethereum/log"
37
	"github.com/ethereum/go-ethereum/metrics"
38
	"github.com/ethereum/go-ethereum/node"
39
	"gopkg.in/urfave/cli.v1"
40 41
)

zelig's avatar
zelig committed
42
const (
43
	clientIdentifier = "geth" // Client identifier to advertise over the network
zelig's avatar
zelig committed
44 45
)

46
var (
47 48 49 50 51 52
	// Git SHA1 commit hash of the release (set via linker flags)
	gitCommit = ""
	// Ethereum address of the Geth release oracle.
	relOracle = common.HexToAddress("0xfa7b9770ca4cb04296cac84f37736d4041251cdf")
	// The app that holds all commands and flags.
	app = utils.NewApp(gitCommit, "the go-ethereum command line interface")
53 54
	// flags that configure the node
	nodeFlags = []cli.Flag{
55
		utils.IdentityFlag,
56
		utils.UnlockedAccountFlag,
zelig's avatar
zelig committed
57
		utils.PasswordFileFlag,
58
		utils.BootnodesFlag,
59 60
		utils.BootnodesV4Flag,
		utils.BootnodesV5Flag,
61
		utils.DataDirFlag,
62
		utils.KeyStoreDirFlag,
63
		utils.NoUSBFlag,
64 65 66 67 68
		utils.DashboardEnabledFlag,
		utils.DashboardAddrFlag,
		utils.DashboardPortFlag,
		utils.DashboardRefreshFlag,
		utils.DashboardAssetsFlag,
69 70 71 72
		utils.EthashCacheDirFlag,
		utils.EthashCachesInMemoryFlag,
		utils.EthashCachesOnDiskFlag,
		utils.EthashDatasetDirFlag,
73
		utils.EthashDatasetsInMemoryFlag,
74
		utils.EthashDatasetsOnDiskFlag,
75
		utils.TxPoolNoLocalsFlag,
76 77
		utils.TxPoolJournalFlag,
		utils.TxPoolRejournalFlag,
78 79 80 81 82 83 84
		utils.TxPoolPriceLimitFlag,
		utils.TxPoolPriceBumpFlag,
		utils.TxPoolAccountSlotsFlag,
		utils.TxPoolGlobalSlotsFlag,
		utils.TxPoolAccountQueueFlag,
		utils.TxPoolGlobalQueueFlag,
		utils.TxPoolLifetimeFlag,
85
		utils.FastSyncFlag,
86
		utils.LightModeFlag,
87
		utils.SyncModeFlag,
88
		utils.GCModeFlag,
89 90
		utils.LightServFlag,
		utils.LightPeersFlag,
91
		utils.LightKDFFlag,
92
		utils.CacheFlag,
93 94
		utils.CacheDatabaseFlag,
		utils.CacheGCFlag,
95
		utils.TrieCacheGenFlag,
96 97
		utils.ListenPortFlag,
		utils.MaxPeersFlag,
98
		utils.MaxPendingPeersFlag,
zelig's avatar
zelig committed
99
		utils.EtherbaseFlag,
100
		utils.GasPriceFlag,
101 102
		utils.MinerThreadsFlag,
		utils.MiningEnabledFlag,
103
		utils.TargetGasLimitFlag,
104
		utils.NATFlag,
105
		utils.NoDiscoverFlag,
106
		utils.DiscoveryV5Flag,
107
		utils.NetrestrictFlag,
108 109
		utils.NodeKeyFileFlag,
		utils.NodeKeyHexFlag,
110 111
		utils.DeveloperFlag,
		utils.DeveloperPeriodFlag,
112 113
		utils.TestnetFlag,
		utils.RinkebyFlag,
114
		utils.VMEnableDebugFlag,
zelig's avatar
zelig committed
115
		utils.NetworkIdFlag,
116
		utils.RPCCORSDomainFlag,
117
		utils.EthStatsURLFlag,
118
		utils.MetricsEnabledFlag,
119
		utils.FakePoWFlag,
120
		utils.NoCompactionFlag,
121 122
		utils.GpoBlocksFlag,
		utils.GpoPercentileFlag,
zelig's avatar
zelig committed
123
		utils.ExtraDataFlag,
124
		configFileFlag,
125
	}
126 127 128 129 130 131 132 133 134 135 136 137 138 139

	rpcFlags = []cli.Flag{
		utils.RPCEnabledFlag,
		utils.RPCListenAddrFlag,
		utils.RPCPortFlag,
		utils.RPCApiFlag,
		utils.WSEnabledFlag,
		utils.WSListenAddrFlag,
		utils.WSPortFlag,
		utils.WSApiFlag,
		utils.WSAllowedOriginsFlag,
		utils.IPCDisabledFlag,
		utils.IPCPathFlag,
	}
140 141 142 143 144 145

	whisperFlags = []cli.Flag{
		utils.WhisperEnabledFlag,
		utils.WhisperMaxMessageSizeFlag,
		utils.WhisperMinPOWFlag,
	}
146 147 148 149 150 151 152 153 154 155 156 157
)

func init() {
	// Initialize the CLI app and start Geth
	app.Action = geth
	app.HideVersion = true // we have a command to print the version
	app.Copyright = "Copyright 2013-2017 The go-ethereum Authors"
	app.Commands = []cli.Command{
		// See chaincmd.go:
		initCommand,
		importCommand,
		exportCommand,
158
		copydbCommand,
159 160 161 162 163 164 165 166 167 168 169 170
		removedbCommand,
		dumpCommand,
		// See monitorcmd.go:
		monitorCommand,
		// See accountcmd.go:
		accountCommand,
		walletCommand,
		// See consolecmd.go:
		consoleCommand,
		attachCommand,
		javascriptCommand,
		// See misccmd.go:
171
		makecacheCommand,
172 173 174 175 176 177 178
		makedagCommand,
		versionCommand,
		bugCommand,
		licenseCommand,
		// See config.go
		dumpConfigCommand,
	}
179
	sort.Sort(cli.CommandsByName(app.Commands))
180 181 182 183

	app.Flags = append(app.Flags, nodeFlags...)
	app.Flags = append(app.Flags, rpcFlags...)
	app.Flags = append(app.Flags, consoleFlags...)
184
	app.Flags = append(app.Flags, debug.Flags...)
185
	app.Flags = append(app.Flags, whisperFlags...)
186

187
	app.Before = func(ctx *cli.Context) error {
188
		runtime.GOMAXPROCS(runtime.NumCPU())
189 190 191 192 193
		if err := debug.Setup(ctx); err != nil {
			return err
		}
		// Start system runtime metrics collection
		go metrics.CollectProcessMetrics(3 * time.Second)
194

195
		utils.SetupNetwork(ctx)
196
		return nil
197
	}
198 199 200

	app.After = func(ctx *cli.Context) error {
		debug.Exit()
201
		console.Stdin.Close() // Resets terminal mode.
202 203
		return nil
	}
204
}
obscuren's avatar
obscuren committed
205

206 207 208 209 210 211
func main() {
	if err := app.Run(os.Args); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
zelig's avatar
zelig committed
212

213 214 215
// 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.
216
func geth(ctx *cli.Context) error {
217
	node := makeFullNode(ctx)
218 219
	startNode(ctx, node)
	node.Wait()
220
	return nil
221
}
222

223 224 225 226 227 228
// 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)
229

230
	// Unlock any account specifically requested
231
	ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
232

233
	passwords := utils.MakePasswordList(ctx)
234 235
	unlocks := strings.Split(ctx.GlobalString(utils.UnlockedAccountFlag.Name), ",")
	for i, account := range unlocks {
236
		if trimmed := strings.TrimSpace(account); trimmed != "" {
237
			unlockAccount(ctx, ks, trimmed, i, passwords)
zelig's avatar
zelig committed
238
		}
zelig's avatar
zelig committed
239
	}
240 241 242 243 244 245 246 247
	// Register wallet event handlers to open and auto-derive wallets
	events := make(chan accounts.WalletEvent, 16)
	stack.AccountManager().Subscribe(events)

	go func() {
		// Create an chain state reader for self-derivation
		rpcClient, err := stack.Attach()
		if err != nil {
248
			utils.Fatalf("Failed to attach to self: %v", err)
249 250 251
		}
		stateReader := ethclient.NewClient(rpcClient)

252
		// Open any wallets already attached
253 254
		for _, wallet := range stack.AccountManager().Wallets() {
			if err := wallet.Open(""); err != nil {
255
				log.Warn("Failed to open wallet", "url", wallet.URL(), "err", err)
256 257
			}
		}
258 259
		// Listen for wallet event till termination
		for event := range events {
260 261
			switch event.Kind {
			case accounts.WalletArrived:
262
				if err := event.Wallet.Open(""); err != nil {
263
					log.Warn("New wallet appeared, failed to open", "url", event.Wallet.URL(), "err", err)
264 265
				}
			case accounts.WalletOpened:
266 267 268
				status, _ := event.Wallet.Status()
				log.Info("New wallet appeared", "url", event.Wallet.URL(), "status", status)

269 270
				if event.Wallet.URL().Scheme == "ledger" {
					event.Wallet.SelfDerive(accounts.DefaultLedgerBaseDerivationPath, stateReader)
271
				} else {
272
					event.Wallet.SelfDerive(accounts.DefaultBaseDerivationPath, stateReader)
273
				}
274 275

			case accounts.WalletDropped:
276
				log.Info("Old wallet dropped", "url", event.Wallet.URL())
277
				event.Wallet.Close()
278 279 280
			}
		}
	}()
281
	// Start auxiliary services if enabled
282
	if ctx.GlobalBool(utils.MiningEnabledFlag.Name) || ctx.GlobalBool(utils.DeveloperFlag.Name) {
283
		// Mining only makes sense if a full Ethereum node is running
284 285 286
		if ctx.GlobalBool(utils.LightModeFlag.Name) || ctx.GlobalString(utils.SyncModeFlag.Name) == "light" {
			utils.Fatalf("Light clients do not support mining")
		}
287
		var ethereum *eth.Ethereum
288
		if err := stack.Service(&ethereum); err != nil {
289
			utils.Fatalf("Ethereum service not running: %v", err)
290
		}
291
		// Use a reduced number of threads if requested
292 293 294 295 296 297 298 299
		if threads := ctx.GlobalInt(utils.MinerThreadsFlag.Name); threads > 0 {
			type threaded interface {
				SetThreads(threads int)
			}
			if th, ok := ethereum.Engine().(threaded); ok {
				th.SetThreads(threads)
			}
		}
300 301
		// Set the gas price to the limits from the CLI and start mining
		ethereum.TxPool().SetGasPrice(utils.GlobalBig(ctx, utils.GasPriceFlag.Name))
302
		if err := ethereum.StartMining(true); err != nil {
303
			utils.Fatalf("Failed to start mining: %v", err)
304
		}
305 306
	}
}