| 
									
										
										
										
											2015-01-06 12:13:57 +01:00
										 |  |  | /* | 
					
						
							|  |  |  | 	This file is part of go-ethereum | 
					
						
							| 
									
										
										
										
											2014-10-23 15:48:53 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-06 12:13:57 +01: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 12:20:59 +01:00
										 |  |  | package main | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2014-08-06 09:53:12 +02:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2015-05-05 13:24:15 +03:00
										 |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2015-03-24 16:19:11 +00:00
										 |  |  | 	"io/ioutil" | 
					
						
							| 
									
										
										
										
											2015-05-27 13:43:49 +02:00
										 |  |  | 	_ "net/http/pprof" | 
					
						
							| 
									
										
										
										
											2014-08-06 09:53:12 +02:00
										 |  |  | 	"os" | 
					
						
							| 
									
										
										
										
											2015-05-05 08:24:15 +02:00
										 |  |  | 	"path/filepath" | 
					
						
							| 
									
										
										
										
											2014-07-30 01:05:40 +02:00
										 |  |  | 	"runtime" | 
					
						
							| 
									
										
										
										
											2015-03-06 03:00:41 +01:00
										 |  |  | 	"strconv" | 
					
						
							| 
									
										
										
										
											2015-05-05 08:24:15 +02:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2014-07-30 01:05:40 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-06 03:00:41 +01:00
										 |  |  | 	"github.com/codegangsta/cli" | 
					
						
							| 
									
										
										
										
											2015-03-17 14:12:34 +01:00
										 |  |  | 	"github.com/ethereum/ethash" | 
					
						
							| 
									
										
										
										
											2015-03-23 13:00:06 +00:00
										 |  |  | 	"github.com/ethereum/go-ethereum/accounts" | 
					
						
							| 
									
										
										
										
											2014-10-31 14:20:11 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/cmd/utils" | 
					
						
							| 
									
										
										
										
											2015-03-16 22:49:39 +07:00
										 |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							| 
									
										
										
										
											2015-01-04 14:20:16 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/eth" | 
					
						
							| 
									
										
										
										
											2014-10-31 12:56:05 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/logger" | 
					
						
							| 
									
										
										
										
											2015-05-06 23:10:46 +02:00
										 |  |  | 	"github.com/mattn/go-colorable" | 
					
						
							|  |  |  | 	"github.com/mattn/go-isatty" | 
					
						
							| 
									
										
										
										
											2014-06-23 12:20:59 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-03 17:36:24 +01:00
										 |  |  | const ( | 
					
						
							| 
									
										
										
										
											2015-03-26 21:27:52 +01:00
										 |  |  | 	ClientIdentifier = "Geth" | 
					
						
							| 
									
										
										
										
											2015-06-09 21:14:11 +02:00
										 |  |  | 	Version          = "0.9.29" | 
					
						
							| 
									
										
										
										
											2014-07-03 17:36:24 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-28 13:14:53 +02:00
										 |  |  | var ( | 
					
						
							|  |  |  | 	gitCommit       string // set via linker flag | 
					
						
							|  |  |  | 	nodeNameVersion string | 
					
						
							|  |  |  | 	app             *cli.App | 
					
						
							|  |  |  | ) | 
					
						
							| 
									
										
										
										
											2014-06-23 12:20:59 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-06 03:00:41 +01:00
										 |  |  | func init() { | 
					
						
							| 
									
										
										
										
											2015-04-28 13:14:53 +02:00
										 |  |  | 	if gitCommit == "" { | 
					
						
							|  |  |  | 		nodeNameVersion = Version | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		nodeNameVersion = Version + "-" + gitCommit[:8] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	app = utils.NewApp(Version, "the go-ethereum command line interface") | 
					
						
							| 
									
										
										
										
											2015-03-06 03:00:41 +01:00
										 |  |  | 	app.Action = run | 
					
						
							|  |  |  | 	app.HideVersion = true // we have a command to print the version | 
					
						
							|  |  |  | 	app.Commands = []cli.Command{ | 
					
						
							| 
									
										
										
										
											2015-05-27 13:43:49 +02:00
										 |  |  | 		blocktestCommand, | 
					
						
							|  |  |  | 		importCommand, | 
					
						
							|  |  |  | 		exportCommand, | 
					
						
							|  |  |  | 		upgradedbCommand, | 
					
						
							|  |  |  | 		removedbCommand, | 
					
						
							|  |  |  | 		dumpCommand, | 
					
						
							| 
									
										
										
										
											2015-03-17 14:12:34 +01: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 03:00:41 +01: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 16:19:11 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2015-03-26 18:55:39 +00:00
										 |  |  | 			Name:  "wallet", | 
					
						
							|  |  |  | 			Usage: "ethereum presale wallet", | 
					
						
							| 
									
										
										
										
											2015-03-24 16:19:11 +00:00
										 |  |  | 			Subcommands: []cli.Command{ | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					Action: importWallet, | 
					
						
							|  |  |  | 					Name:   "import", | 
					
						
							|  |  |  | 					Usage:  "import ethereum presale wallet", | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2015-05-20 02:42:10 +01: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 12:39:52 +01:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			Action: accountList, | 
					
						
							|  |  |  | 			Name:   "account", | 
					
						
							|  |  |  | 			Usage:  "manage accounts", | 
					
						
							| 
									
										
										
										
											2015-03-26 18:55:39 +00:00
										 |  |  | 			Description: ` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Manage accounts lets you create new accounts, list all existing accounts, | 
					
						
							|  |  |  | import a private key into a new account. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-20 16:56:17 +01:00
										 |  |  | '            help' shows a list of subcommands or help for one subcommand. | 
					
						
							| 
									
										
										
										
											2015-04-22 00:41:34 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-26 18:55:39 +00: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 12:39:52 +01:00
										 |  |  | 			Subcommands: []cli.Command{ | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					Action: accountList, | 
					
						
							|  |  |  | 					Name:   "list", | 
					
						
							|  |  |  | 					Usage:  "print account addresses", | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					Action: accountCreate, | 
					
						
							|  |  |  | 					Name:   "new", | 
					
						
							|  |  |  | 					Usage:  "create a new account", | 
					
						
							| 
									
										
										
										
											2015-03-23 13:00:06 +00:00
										 |  |  | 					Description: ` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ethereum account new | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-26 18:55:39 +00: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 13:00:06 +00:00
										 |  |  | For non-interactive use the passphrase can be specified with the --password flag: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ethereum --password <passwordfile> account new | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-26 18:55:39 +00: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 13:00:06 +00:00
										 |  |  | 					`, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					Action: accountImport, | 
					
						
							|  |  |  | 					Name:   "import", | 
					
						
							|  |  |  | 					Usage:  "import a private key into a new account", | 
					
						
							|  |  |  | 					Description: ` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ethereum account import <keyfile> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-26 18:55:39 +00:00
										 |  |  | Imports an unencrypted private key from <keyfile> and creates a new account. | 
					
						
							|  |  |  | Prints the address. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-08 23:03:47 +02:00
										 |  |  | The keyfile is assumed to contain an unencrypted private key in hexadecimal format. | 
					
						
							| 
									
										
										
										
											2015-03-23 13:00:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | The account is saved in encrypted format, you are prompted for a passphrase. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-26 18:55:39 +00:00
										 |  |  | You must remember this passphrase to unlock your account in the future. | 
					
						
							| 
									
										
										
										
											2015-03-23 13:00:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-26 18:55:39 +00:00
										 |  |  | For non-interactive use the passphrase can be specified with the -password flag: | 
					
						
							| 
									
										
										
										
											2015-03-23 13:00:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-26 18:55:39 +00:00
										 |  |  |     ethereum --password <passwordfile> account import <keyfile> | 
					
						
							| 
									
										
										
										
											2015-03-23 13:00:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | Note: | 
					
						
							| 
									
										
										
										
											2015-03-24 16:05:27 +00:00
										 |  |  | As you can directly copy your encrypted accounts to another ethereum instance, | 
					
						
							| 
									
										
										
										
											2015-03-26 18:55:39 +00:00
										 |  |  | this import mechanism is not needed when you transfer an account between | 
					
						
							| 
									
										
										
										
											2015-03-24 16:05:27 +00:00
										 |  |  | nodes. | 
					
						
							| 
									
										
										
										
											2015-03-23 13:00:06 +00:00
										 |  |  | 					`, | 
					
						
							| 
									
										
										
										
											2015-03-07 12:39:52 +01:00
										 |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2015-03-06 03:00:41 +01:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2015-03-15 13:31:40 +07:00
										 |  |  | 			Action: console, | 
					
						
							|  |  |  | 			Name:   "console", | 
					
						
							| 
									
										
										
										
											2015-03-26 21:27:52 +01:00
										 |  |  | 			Usage:  `Geth Console: interactive JavaScript environment`, | 
					
						
							| 
									
										
										
										
											2015-03-15 13:31:40 +07:00
										 |  |  | 			Description: ` | 
					
						
							| 
									
										
										
										
											2015-03-26 21:27:52 +01:00
										 |  |  | The Geth console is an interactive shell for the JavaScript runtime environment | 
					
						
							| 
									
										
										
										
											2015-04-22 00:41:34 +01: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-03-15 13:31:40 +07:00
										 |  |  | `, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			Action: execJSFiles, | 
					
						
							| 
									
										
										
										
											2015-03-06 03:00:41 +01:00
										 |  |  | 			Name:   "js", | 
					
						
							| 
									
										
										
										
											2015-03-26 21:27:52 +01:00
										 |  |  | 			Usage:  `executes the given JavaScript files in the Geth JavaScript VM`, | 
					
						
							| 
									
										
										
										
											2015-03-06 03:00:41 +01:00
										 |  |  | 			Description: ` | 
					
						
							| 
									
										
										
										
											2015-04-22 00:41:34 +01:00
										 |  |  | The JavaScript VM exposes a node admin interface as well as the Ðapp | 
					
						
							| 
									
										
										
										
											2015-03-24 16:05:27 +00:00
										 |  |  | JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Console | 
					
						
							| 
									
										
										
										
											2015-03-06 03:00:41 +01:00
										 |  |  | `, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	app.Flags = []cli.Flag{ | 
					
						
							| 
									
										
										
										
											2015-04-18 23:53:30 +02:00
										 |  |  | 		utils.IdentityFlag, | 
					
						
							| 
									
										
										
										
											2015-03-11 01:08:42 +01:00
										 |  |  | 		utils.UnlockedAccountFlag, | 
					
						
							| 
									
										
										
										
											2015-03-23 13:00:06 +00:00
										 |  |  | 		utils.PasswordFileFlag, | 
					
						
							| 
									
										
										
										
											2015-06-08 12:12:13 +02:00
										 |  |  | 		utils.GenesisNonceFlag, | 
					
						
							| 
									
										
										
										
											2015-03-06 03:00:41 +01:00
										 |  |  | 		utils.BootnodesFlag, | 
					
						
							|  |  |  | 		utils.DataDirFlag, | 
					
						
							| 
									
										
										
										
											2015-04-13 10:13:52 +02:00
										 |  |  | 		utils.BlockchainVersionFlag, | 
					
						
							| 
									
										
										
										
											2015-03-15 13:31:40 +07:00
										 |  |  | 		utils.JSpathFlag, | 
					
						
							| 
									
										
										
										
											2015-03-06 03:00:41 +01:00
										 |  |  | 		utils.ListenPortFlag, | 
					
						
							|  |  |  | 		utils.MaxPeersFlag, | 
					
						
							| 
									
										
										
										
											2015-05-04 17:35:49 +03:00
										 |  |  | 		utils.MaxPendingPeersFlag, | 
					
						
							| 
									
										
										
										
											2015-03-26 21:49:22 +00:00
										 |  |  | 		utils.EtherbaseFlag, | 
					
						
							| 
									
										
										
										
											2015-05-09 12:00:51 +02:00
										 |  |  | 		utils.GasPriceFlag, | 
					
						
							| 
									
										
										
										
											2015-03-06 03:00:41 +01:00
										 |  |  | 		utils.MinerThreadsFlag, | 
					
						
							|  |  |  | 		utils.MiningEnabledFlag, | 
					
						
							| 
									
										
										
										
											2015-05-20 16:56:17 +01:00
										 |  |  | 		utils.AutoDAGFlag, | 
					
						
							| 
									
										
										
										
											2015-03-06 03:00:41 +01:00
										 |  |  | 		utils.NATFlag, | 
					
						
							| 
									
										
										
										
											2015-04-08 13:22:31 +02:00
										 |  |  | 		utils.NatspecEnabledFlag, | 
					
						
							| 
									
										
										
										
											2015-05-26 19:07:24 +03:00
										 |  |  | 		utils.NoDiscoverFlag, | 
					
						
							| 
									
										
										
										
											2015-03-06 03:00:41 +01:00
										 |  |  | 		utils.NodeKeyFileFlag, | 
					
						
							|  |  |  | 		utils.NodeKeyHexFlag, | 
					
						
							|  |  |  | 		utils.RPCEnabledFlag, | 
					
						
							|  |  |  | 		utils.RPCListenAddrFlag, | 
					
						
							|  |  |  | 		utils.RPCPortFlag, | 
					
						
							| 
									
										
										
										
											2015-04-20 18:45:37 +03:00
										 |  |  | 		utils.WhisperEnabledFlag, | 
					
						
							| 
									
										
										
										
											2015-03-06 16:58:52 +01:00
										 |  |  | 		utils.VMDebugFlag, | 
					
						
							| 
									
										
										
										
											2015-03-18 14:44:58 +07:00
										 |  |  | 		utils.ProtocolVersionFlag, | 
					
						
							|  |  |  | 		utils.NetworkIdFlag, | 
					
						
							| 
									
										
										
										
											2015-03-29 21:21:14 +02:00
										 |  |  | 		utils.RPCCORSDomainFlag, | 
					
						
							| 
									
										
										
										
											2015-05-09 12:00:51 +02:00
										 |  |  | 		utils.VerbosityFlag, | 
					
						
							| 
									
										
										
										
											2015-04-03 17:09:01 +02:00
										 |  |  | 		utils.BacktraceAtFlag, | 
					
						
							|  |  |  | 		utils.LogToStdErrFlag, | 
					
						
							| 
									
										
										
										
											2015-04-07 14:57:16 +02: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-04-22 23:11:11 +01:00
										 |  |  | 		utils.SolcPathFlag, | 
					
						
							| 
									
										
										
										
											2015-03-06 03:00:41 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-04-20 18:59:41 +03:00
										 |  |  | 	app.Before = func(ctx *cli.Context) error { | 
					
						
							| 
									
										
										
										
											2015-05-27 13:29:34 +02: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 03:00:41 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-12-23 14:33:15 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-06 03:00:41 +01: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 10:47:45 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-06 03:00:41 +01:00
										 |  |  | func run(ctx *cli.Context) { | 
					
						
							| 
									
										
										
										
											2015-03-06 12:18:44 +01:00
										 |  |  | 	utils.HandleInterrupt() | 
					
						
							| 
									
										
										
										
											2015-04-28 13:14:53 +02:00
										 |  |  | 	cfg := utils.MakeEthConfig(ClientIdentifier, nodeNameVersion, ctx) | 
					
						
							| 
									
										
										
										
											2015-03-13 18:30:45 +01:00
										 |  |  | 	ethereum, err := eth.New(cfg) | 
					
						
							| 
									
										
										
										
											2015-03-11 23:41:51 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-03-10 15:44:05 +01:00
										 |  |  | 		utils.Fatalf("%v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-13 18:30:45 +01:00
										 |  |  | 	startEth(ctx, ethereum) | 
					
						
							| 
									
										
										
										
											2015-03-06 03:00:41 +01:00
										 |  |  | 	// this blocks the thread | 
					
						
							| 
									
										
										
										
											2015-03-13 18:30:45 +01:00
										 |  |  | 	ethereum.WaitForShutdown() | 
					
						
							| 
									
										
										
										
											2015-03-06 03:00:41 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-07-11 16:04:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-15 13:31:40 +07: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 13:14:53 +02:00
										 |  |  | 	cfg := utils.MakeEthConfig(ClientIdentifier, nodeNameVersion, ctx) | 
					
						
							| 
									
										
										
										
											2015-03-13 18:30:45 +01:00
										 |  |  | 	ethereum, err := eth.New(cfg) | 
					
						
							| 
									
										
										
										
											2015-03-11 23:41:51 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-03-10 15:44:05 +01:00
										 |  |  | 		utils.Fatalf("%v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-13 18:30:45 +01:00
										 |  |  | 	startEth(ctx, ethereum) | 
					
						
							| 
									
										
										
										
											2015-04-22 23:11:11 +01:00
										 |  |  | 	repl := newJSRE( | 
					
						
							|  |  |  | 		ethereum, | 
					
						
							|  |  |  | 		ctx.String(utils.JSpathFlag.Name), | 
					
						
							|  |  |  | 		ctx.GlobalString(utils.RPCCORSDomainFlag.Name), | 
					
						
							|  |  |  | 		true, | 
					
						
							|  |  |  | 		nil, | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2015-03-15 13:31:40 +07:00
										 |  |  | 	repl.interactive() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ethereum.Stop() | 
					
						
							|  |  |  | 	ethereum.WaitForShutdown() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func execJSFiles(ctx *cli.Context) { | 
					
						
							| 
									
										
										
										
											2015-04-28 13:14:53 +02:00
										 |  |  | 	cfg := utils.MakeEthConfig(ClientIdentifier, nodeNameVersion, ctx) | 
					
						
							| 
									
										
										
										
											2015-03-15 13:31:40 +07:00
										 |  |  | 	ethereum, err := eth.New(cfg) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		utils.Fatalf("%v", err) | 
					
						
							| 
									
										
										
										
											2015-01-07 01:21:55 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-03-15 13:31:40 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	startEth(ctx, ethereum) | 
					
						
							| 
									
										
										
										
											2015-04-22 23:11:11 +01:00
										 |  |  | 	repl := newJSRE( | 
					
						
							|  |  |  | 		ethereum, | 
					
						
							|  |  |  | 		ctx.String(utils.JSpathFlag.Name), | 
					
						
							|  |  |  | 		ctx.GlobalString(utils.RPCCORSDomainFlag.Name), | 
					
						
							|  |  |  | 		false, | 
					
						
							|  |  |  | 		nil, | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2015-03-15 13:31:40 +07:00
										 |  |  | 	for _, file := range ctx.Args() { | 
					
						
							|  |  |  | 		repl.exec(file) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-13 18:30:45 +01:00
										 |  |  | 	ethereum.Stop() | 
					
						
							|  |  |  | 	ethereum.WaitForShutdown() | 
					
						
							| 
									
										
										
										
											2015-03-06 03:00:41 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-01-07 01:21:55 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-23 13:00:06 +00:00
										 |  |  | func unlockAccount(ctx *cli.Context, am *accounts.Manager, account string) (passphrase string) { | 
					
						
							| 
									
										
										
										
											2015-03-26 18:55:39 +00:00
										 |  |  | 	var err error | 
					
						
							|  |  |  | 	// Load startup keys. XXX we are going to need a different format | 
					
						
							| 
									
										
										
										
											2015-05-19 13:40:41 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-28 15:20:05 +02:00
										 |  |  | 	if !((len(account) == 40) || (len(account) == 42)) { // with or without 0x | 
					
						
							| 
									
										
										
										
											2015-03-26 18:55:39 +00:00
										 |  |  | 		utils.Fatalf("Invalid account address '%s'", account) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-05-19 14:46:32 -05:00
										 |  |  | 	// Attempt to unlock the account 3 times | 
					
						
							|  |  |  | 	attempts := 3 | 
					
						
							|  |  |  | 	for tries := 0; tries < attempts; tries++ { | 
					
						
							| 
									
										
										
										
											2015-05-28 15:20:05 +02:00
										 |  |  | 		msg := fmt.Sprintf("Unlocking account %s | Attempt %d/%d", account, tries+1, attempts) | 
					
						
							| 
									
										
										
										
											2015-05-19 14:46:32 -05:00
										 |  |  | 		passphrase = getPassPhrase(ctx, msg, false) | 
					
						
							|  |  |  | 		err = am.Unlock(common.HexToAddress(account), passphrase) | 
					
						
							|  |  |  | 		if err == nil { | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-03-26 18:55:39 +00:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		utils.Fatalf("Unlock account failed '%v'", err) | 
					
						
							| 
									
										
										
										
											2015-03-11 01:08:42 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-05-13 01:11:17 +02:00
										 |  |  | 	fmt.Printf("Account '%s' unlocked.\n", account) | 
					
						
							| 
									
										
										
										
											2015-03-23 13:00:06 +00:00
										 |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func startEth(ctx *cli.Context, eth *eth.Ethereum) { | 
					
						
							| 
									
										
										
										
											2015-04-20 18:45:37 +03:00
										 |  |  | 	// Start Ethereum itself | 
					
						
							| 
									
										
										
										
											2015-04-22 23:11:11 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-23 13:00:06 +00:00
										 |  |  | 	utils.StartEthereum(eth) | 
					
						
							|  |  |  | 	am := eth.AccountManager() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	account := ctx.GlobalString(utils.UnlockedAccountFlag.Name) | 
					
						
							| 
									
										
										
										
											2015-05-19 13:40:41 -05: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 15:45:56 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-05-19 13:40:41 -05:00
										 |  |  | 			unlockAccount(ctx, am, account) | 
					
						
							| 
									
										
										
										
											2015-03-24 12:37:00 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-03-23 13:00:06 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-03-10 16:44:22 +01:00
										 |  |  | 	// Start auxiliary services if enabled. | 
					
						
							| 
									
										
										
										
											2015-03-06 03:00:41 +01:00
										 |  |  | 	if ctx.GlobalBool(utils.RPCEnabledFlag.Name) { | 
					
						
							| 
									
										
										
										
											2015-04-22 00:47:17 +01:00
										 |  |  | 		if err := utils.StartRPC(eth, ctx); err != nil { | 
					
						
							|  |  |  | 			utils.Fatalf("Error starting RPC: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-03-06 03:00:41 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if ctx.GlobalBool(utils.MiningEnabledFlag.Name) { | 
					
						
							| 
									
										
										
										
											2015-05-11 15:43:14 +02:00
										 |  |  | 		if err := eth.StartMining(ctx.GlobalInt(utils.MinerThreadsFlag.Name)); err != nil { | 
					
						
							| 
									
										
										
										
											2015-04-22 01:36:28 +01:00
										 |  |  | 			utils.Fatalf("%v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-03-06 03:00:41 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-01-05 17:10:42 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-07 12:39:52 +01:00
										 |  |  | func accountList(ctx *cli.Context) { | 
					
						
							| 
									
										
										
										
											2015-05-27 14:50:31 +02:00
										 |  |  | 	am := utils.MakeAccountManager(ctx) | 
					
						
							| 
									
										
										
										
											2015-03-07 12:39:52 +01:00
										 |  |  | 	accts, err := am.Accounts() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		utils.Fatalf("Could not list accounts: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-04-22 00:41:34 +01:00
										 |  |  | 	name := "Primary" | 
					
						
							|  |  |  | 	for i, acct := range accts { | 
					
						
							|  |  |  | 		fmt.Printf("%s #%d: %x\n", name, i, acct) | 
					
						
							|  |  |  | 		name = "Account" | 
					
						
							| 
									
										
										
										
											2015-03-07 12:39:52 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-24 16:19:11 +00:00
										 |  |  | func getPassPhrase(ctx *cli.Context, desc string, confirmation bool) (passphrase string) { | 
					
						
							| 
									
										
										
										
											2015-03-26 18:55:39 +00:00
										 |  |  | 	passfile := ctx.GlobalString(utils.PasswordFileFlag.Name) | 
					
						
							|  |  |  | 	if len(passfile) == 0 { | 
					
						
							|  |  |  | 		fmt.Println(desc) | 
					
						
							| 
									
										
										
										
											2015-05-18 12:24:30 -05:00
										 |  |  | 		auth, err := utils.PromptPassword("Passphrase: ", true) | 
					
						
							| 
									
										
										
										
											2015-03-26 18:55:39 +00:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			utils.Fatalf("%v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if confirmation { | 
					
						
							| 
									
										
										
										
											2015-05-18 12:24:30 -05:00
										 |  |  | 			confirm, err := utils.PromptPassword("Repeat Passphrase: ", false) | 
					
						
							| 
									
										
										
										
											2015-03-23 13:00:06 +00:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				utils.Fatalf("%v", err) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-03-26 18:55:39 +00:00
										 |  |  | 			if auth != confirm { | 
					
						
							|  |  |  | 				utils.Fatalf("Passphrases did not match.") | 
					
						
							| 
									
										
										
										
											2015-03-23 13:00:06 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-03-26 18:55:39 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		passphrase = auth | 
					
						
							| 
									
										
										
										
											2015-03-23 13:00:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-26 18:55:39 +00:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		passbytes, err := ioutil.ReadFile(passfile) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			utils.Fatalf("Unable to read password file '%s': %v", passfile, err) | 
					
						
							| 
									
										
										
										
											2015-03-11 13:56:02 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-03-26 18:55:39 +00:00
										 |  |  | 		passphrase = string(passbytes) | 
					
						
							| 
									
										
										
										
											2015-03-07 12:39:52 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-03-23 13:00:06 +00:00
										 |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func accountCreate(ctx *cli.Context) { | 
					
						
							| 
									
										
										
										
											2015-05-27 14:50:31 +02:00
										 |  |  | 	am := utils.MakeAccountManager(ctx) | 
					
						
							| 
									
										
										
										
											2015-03-24 16:19:11 +00: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 13:56:02 +01:00
										 |  |  | 	acct, err := am.NewAccount(passphrase) | 
					
						
							| 
									
										
										
										
											2015-03-07 12:39:52 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		utils.Fatalf("Could not create the account: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-03-23 13:00:06 +00:00
										 |  |  | 	fmt.Printf("Address: %x\n", acct) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-24 16:19:11 +00: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 14:50:31 +02:00
										 |  |  | 	am := utils.MakeAccountManager(ctx) | 
					
						
							| 
									
										
										
										
											2015-03-24 16:19:11 +00: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 13:00:06 +00: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 14:50:31 +02:00
										 |  |  | 	am := utils.MakeAccountManager(ctx) | 
					
						
							| 
									
										
										
										
											2015-03-24 16:19:11 +00: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 13:00:06 +00: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 14:12:34 +01:00
										 |  |  | func makedag(ctx *cli.Context) { | 
					
						
							| 
									
										
										
										
											2015-05-05 08:24:15 +02: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 14:12:34 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-06 03:00:41 +01:00
										 |  |  | func version(c *cli.Context) { | 
					
						
							| 
									
										
										
										
											2015-04-28 13:14:53 +02:00
										 |  |  | 	fmt.Println(ClientIdentifier) | 
					
						
							|  |  |  | 	fmt.Println("Version:", Version) | 
					
						
							|  |  |  | 	if gitCommit != "" { | 
					
						
							|  |  |  | 		fmt.Println("Git Commit:", gitCommit) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	fmt.Println("Protocol Version:", c.GlobalInt(utils.ProtocolVersionFlag.Name)) | 
					
						
							|  |  |  | 	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 01:21:55 +01:00
										 |  |  | } |