From fc2e33c594449e38b90bad2bd7b5c50f03b7f69d Mon Sep 17 00:00:00 2001
From: zelig <viktor.tron@gmail.com>
Date: Thu, 18 Jun 2015 16:20:00 +0100
Subject: unlock multiple passes and obsolete primary * multiple passwords
 allowed in password file * split on "\n", sideeffect: chop trailing slashes.
 fixes common mistake <(echo 'pass') * remove accounts.Primary method * do not
 fall back to primary account for mining

---
 cmd/geth/js_test.go |  2 +-
 cmd/geth/main.go    | 38 ++++++++++++++++++++++----------------
 2 files changed, 23 insertions(+), 17 deletions(-)

(limited to 'cmd/geth')

diff --git a/cmd/geth/js_test.go b/cmd/geth/js_test.go
index cfbe26bee..fc2444a7b 100644
--- a/cmd/geth/js_test.go
+++ b/cmd/geth/js_test.go
@@ -140,7 +140,7 @@ func TestAccounts(t *testing.T) {
 	defer os.RemoveAll(tmp)
 
 	checkEvalJSON(t, repl, `eth.accounts`, `["`+testAddress+`"]`)
-	checkEvalJSON(t, repl, `eth.coinbase`, `"`+testAddress+`"`)
+	checkEvalJSON(t, repl, `eth.coinbase`, `"`+common.Address{}.Hex()+`"`)
 
 	val, err := repl.re.Run(`personal.newAccount("password")`)
 	if err != nil {
diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index be40d5137..b20c6d85d 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -153,9 +153,12 @@ 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.
+between ethereum nodes by simply copying.
 Make sure you backup your keys regularly.
 
+In order to use your account to send transactions, you need to unlock them using the
+'--unlock' option. The argument is a comma
+
 And finally. DO NOT FORGET YOUR PASSWORD.
 `,
 			Subcommands: []cli.Command{
@@ -430,7 +433,7 @@ func execJSFiles(ctx *cli.Context) {
 	ethereum.WaitForShutdown()
 }
 
-func unlockAccount(ctx *cli.Context, am *accounts.Manager, account string) (passphrase string) {
+func unlockAccount(ctx *cli.Context, am *accounts.Manager, account string, i int) {
 	var err error
 	// Load startup keys. XXX we are going to need a different format
 
@@ -441,7 +444,7 @@ func unlockAccount(ctx *cli.Context, am *accounts.Manager, account string) (pass
 	attempts := 3
 	for tries := 0; tries < attempts; tries++ {
 		msg := fmt.Sprintf("Unlocking account %s | Attempt %d/%d", account, tries+1, attempts)
-		passphrase = getPassPhrase(ctx, msg, false)
+		passphrase := getPassPhrase(ctx, msg, false, i)
 		err = am.Unlock(common.HexToAddress(account), passphrase)
 		if err == nil {
 			break
@@ -451,7 +454,6 @@ func unlockAccount(ctx *cli.Context, am *accounts.Manager, account string) (pass
 		utils.Fatalf("Unlock account failed '%v'", err)
 	}
 	fmt.Printf("Account '%s' unlocked.\n", account)
-	return
 }
 
 func blockRecovery(ctx *cli.Context) {
@@ -492,16 +494,12 @@ func startEth(ctx *cli.Context, eth *eth.Ethereum) {
 
 	account := ctx.GlobalString(utils.UnlockedAccountFlag.Name)
 	accounts := strings.Split(account, " ")
-	for _, account := range accounts {
+	for i, 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()
+				utils.Fatalf("the 'primary' keyword is deprecated. You can use indexes, but the indexes are not permanent, they can change if you add external keys, export your keys or copy your keystore to another node.")
 			}
-			unlockAccount(ctx, am, account)
+			unlockAccount(ctx, am, account, i)
 		}
 	}
 	// Start auxiliary services if enabled.
@@ -535,7 +533,7 @@ func accountList(ctx *cli.Context) {
 	}
 }
 
-func getPassPhrase(ctx *cli.Context, desc string, confirmation bool) (passphrase string) {
+func getPassPhrase(ctx *cli.Context, desc string, confirmation bool, i int) (passphrase string) {
 	passfile := ctx.GlobalString(utils.PasswordFileFlag.Name)
 	if len(passfile) == 0 {
 		fmt.Println(desc)
@@ -559,14 +557,22 @@ func getPassPhrase(ctx *cli.Context, desc string, confirmation bool) (passphrase
 		if err != nil {
 			utils.Fatalf("Unable to read password file '%s': %v", passfile, err)
 		}
-		passphrase = string(passbytes)
+		// this is backwards compatible if the same password unlocks several accounts
+		// it also has the consequence that trailing newlines will not count as part
+		// of the password, so --password <(echo -n 'pass') will now work without -n
+		passphrases := strings.Split(string(passbytes), "\n")
+		if i >= len(passphrases) {
+			passphrase = passphrases[len(passphrases)-1]
+		} else {
+			passphrase = passphrases[i]
+		}
 	}
 	return
 }
 
 func accountCreate(ctx *cli.Context) {
 	am := utils.MakeAccountManager(ctx)
-	passphrase := getPassPhrase(ctx, "Your new account is locked with a password. Please give a password. Do not forget this password.", true)
+	passphrase := getPassPhrase(ctx, "Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0)
 	acct, err := am.NewAccount(passphrase)
 	if err != nil {
 		utils.Fatalf("Could not create the account: %v", err)
@@ -585,7 +591,7 @@ func importWallet(ctx *cli.Context) {
 	}
 
 	am := utils.MakeAccountManager(ctx)
-	passphrase := getPassPhrase(ctx, "", false)
+	passphrase := getPassPhrase(ctx, "", false, 0)
 
 	acct, err := am.ImportPreSaleKey(keyJson, passphrase)
 	if err != nil {
@@ -600,7 +606,7 @@ func accountImport(ctx *cli.Context) {
 		utils.Fatalf("keyfile must be given as argument")
 	}
 	am := utils.MakeAccountManager(ctx)
-	passphrase := getPassPhrase(ctx, "Your new account is locked with a password. Please give a password. Do not forget this password.", true)
+	passphrase := getPassPhrase(ctx, "Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0)
 	acct, err := am.Import(keyfile, passphrase)
 	if err != nil {
 		utils.Fatalf("Could not create the account: %v", err)
-- 
cgit v1.2.3


From 09b69831758cb1001027fbb59dff9b3fbe20bbb2 Mon Sep 17 00:00:00 2001
From: zelig <viktor.tron@gmail.com>
Date: Sun, 21 Jun 2015 04:01:12 +0100
Subject: no primary when listing accounts

---
 cmd/geth/main.go | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

(limited to 'cmd/geth')

diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index b20c6d85d..673a08d45 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -497,7 +497,7 @@ func startEth(ctx *cli.Context, eth *eth.Ethereum) {
 	for i, account := range accounts {
 		if len(account) > 0 {
 			if account == "primary" {
-				utils.Fatalf("the 'primary' keyword is deprecated. You can use indexes, but the indexes are not permanent, they can change if you add external keys, export your keys or copy your keystore to another node.")
+				utils.Fatalf("the 'primary' keyword is deprecated. You can use integer indexes, but the indexes are not permanent, they can change if you add external keys, export your keys or copy your keystore to another node.")
 			}
 			unlockAccount(ctx, am, account, i)
 		}
@@ -526,10 +526,8 @@ func accountList(ctx *cli.Context) {
 	if err != nil {
 		utils.Fatalf("Could not list accounts: %v", err)
 	}
-	name := "Primary"
 	for i, acct := range accts {
-		fmt.Printf("%s #%d: %x\n", name, i, acct)
-		name = "Account"
+		fmt.Printf("Account #%d: %x\n", i, acct)
 	}
 }
 
-- 
cgit v1.2.3


From eb82ca4563cf80bef9b520673d3bd18283da3a1f Mon Sep 17 00:00:00 2001
From: zelig <viktor.tron@gmail.com>
Date: Sun, 21 Jun 2015 20:33:51 +0100
Subject: rpc/js coinbase returns null if no etherbase set

---
 cmd/geth/js_test.go | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

(limited to 'cmd/geth')

diff --git a/cmd/geth/js_test.go b/cmd/geth/js_test.go
index fc2444a7b..5bdfb7048 100644
--- a/cmd/geth/js_test.go
+++ b/cmd/geth/js_test.go
@@ -140,7 +140,7 @@ func TestAccounts(t *testing.T) {
 	defer os.RemoveAll(tmp)
 
 	checkEvalJSON(t, repl, `eth.accounts`, `["`+testAddress+`"]`)
-	checkEvalJSON(t, repl, `eth.coinbase`, `"`+common.Address{}.Hex()+`"`)
+	checkEvalJSON(t, repl, `eth.coinbase`, `null`)
 
 	val, err := repl.re.Run(`personal.newAccount("password")`)
 	if err != nil {
@@ -151,9 +151,7 @@ func TestAccounts(t *testing.T) {
 		t.Errorf("address not hex: %q", addr)
 	}
 
-	// skip until order fixed #824
 	// checkEvalJSON(t, repl, `eth.accounts`, `["`+testAddress+`", "`+addr+`"]`)
-	// checkEvalJSON(t, repl, `eth.coinbase`, `"`+testAddress+`"`)
 }
 
 func TestBlockChain(t *testing.T) {
-- 
cgit v1.2.3


From a4df9d74eabb3bef8449744c4fe966572586dc39 Mon Sep 17 00:00:00 2001
From: zelig <viktor.tron@gmail.com>
Date: Sun, 21 Jun 2015 22:17:17 +0100
Subject: accounts order by keyfile ctime

---
 cmd/geth/js_test.go | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

(limited to 'cmd/geth')

diff --git a/cmd/geth/js_test.go b/cmd/geth/js_test.go
index 5bdfb7048..61e85d399 100644
--- a/cmd/geth/js_test.go
+++ b/cmd/geth/js_test.go
@@ -9,6 +9,7 @@ import (
 	"runtime"
 	"strconv"
 	"testing"
+	"time"
 
 	"github.com/ethereum/go-ethereum/accounts"
 	"github.com/ethereum/go-ethereum/common"
@@ -20,8 +21,8 @@ import (
 	"github.com/ethereum/go-ethereum/core/state"
 	"github.com/ethereum/go-ethereum/crypto"
 	"github.com/ethereum/go-ethereum/eth"
-	"github.com/ethereum/go-ethereum/rpc/comms"
 	"github.com/ethereum/go-ethereum/rpc/codec"
+	"github.com/ethereum/go-ethereum/rpc/comms"
 )
 
 const (
@@ -141,7 +142,6 @@ func TestAccounts(t *testing.T) {
 
 	checkEvalJSON(t, repl, `eth.accounts`, `["`+testAddress+`"]`)
 	checkEvalJSON(t, repl, `eth.coinbase`, `null`)
-
 	val, err := repl.re.Run(`personal.newAccount("password")`)
 	if err != nil {
 		t.Errorf("expected no error, got %v", err)
@@ -151,7 +151,7 @@ func TestAccounts(t *testing.T) {
 		t.Errorf("address not hex: %q", addr)
 	}
 
-	// checkEvalJSON(t, repl, `eth.accounts`, `["`+testAddress+`", "`+addr+`"]`)
+	checkEvalJSON(t, repl, `eth.accounts`, `["`+testAddress+`","`+addr+`"]`)
 }
 
 func TestBlockChain(t *testing.T) {
-- 
cgit v1.2.3


From fc17a527bc2bd07fc30e16d161059a441042d5f1 Mon Sep 17 00:00:00 2001
From: zelig <viktor.tron@gmail.com>
Date: Thu, 2 Jul 2015 22:58:00 +0100
Subject: fix account ordering * chronological order of creation * new naming
 scheme keystore/UTC--<created_at UTC ISO8601>-<address hex> * KeyStore2 ->
 KeyStore * backward compatibility * refactor keyStore methods

---
 cmd/geth/js_test.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'cmd/geth')

diff --git a/cmd/geth/js_test.go b/cmd/geth/js_test.go
index 61e85d399..480f77c91 100644
--- a/cmd/geth/js_test.go
+++ b/cmd/geth/js_test.go
@@ -9,7 +9,6 @@ import (
 	"runtime"
 	"strconv"
 	"testing"
-	"time"
 
 	"github.com/ethereum/go-ethereum/accounts"
 	"github.com/ethereum/go-ethereum/common"
@@ -128,6 +127,7 @@ func TestNodeInfo(t *testing.T) {
 	}
 	defer ethereum.Stop()
 	defer os.RemoveAll(tmp)
+
 	want := `{"DiscPort":0,"IP":"0.0.0.0","ListenAddr":"","Name":"test","NodeID":"4cb2fc32924e94277bf94b5e4c983beedb2eabd5a0bc941db32202735c6625d020ca14a5963d1738af43b6ac0a711d61b1a06de931a499fe2aa0b1a132a902b5","NodeUrl":"enode://4cb2fc32924e94277bf94b5e4c983beedb2eabd5a0bc941db32202735c6625d020ca14a5963d1738af43b6ac0a711d61b1a06de931a499fe2aa0b1a132a902b5@0.0.0.0:0","TCPPort":0,"Td":"131072"}`
 	checkEvalJSON(t, repl, `admin.nodeInfo`, want)
 }
-- 
cgit v1.2.3


From 1959346793bdee469f68841843dd383cf801aba1 Mon Sep 17 00:00:00 2001
From: zelig <viktor.tron@gmail.com>
Date: Fri, 3 Jul 2015 04:56:20 +0100
Subject: account update: migrate or change password * account.Update *
 KeyStore.Cleanup * fix dir rm for old format deleteKey

---
 cmd/geth/main.go | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 61 insertions(+), 7 deletions(-)

(limited to 'cmd/geth')

diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index 673a08d45..ffd26a7c2 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -189,6 +189,33 @@ 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.
 					`,
 				},
+				{
+					Action: accountUpdate,
+					Name:   "update",
+					Usage:  "update an existing account",
+					Description: `
+
+    ethereum account update <address>
+
+Update an existing account.
+
+The account is saved in the newest version in encrypted format, you are prompted
+for a passphrase to unlock the account and another to save the updated file.
+
+This same command can therefore be used to migrate an account of a deprecated
+format to the newest format or change the password for an account.
+
+For non-interactive use the passphrase can be specified with the --password flag:
+
+    ethereum --password <passwordfile> account new
+
+Since only one password can be given, only format update can be performed,
+changing your password is only possible interactively.
+
+Note that account update has the a side effect that the order of your accounts
+changes.
+					`,
+				},
 				{
 					Action: accountImport,
 					Name:   "import",
@@ -433,19 +460,30 @@ func execJSFiles(ctx *cli.Context) {
 	ethereum.WaitForShutdown()
 }
 
-func unlockAccount(ctx *cli.Context, am *accounts.Manager, account string, i int) {
+func unlockAccount(ctx *cli.Context, am *accounts.Manager, addr string, i int) (addrHex, auth string) {
 	var err error
 	// Load startup keys. XXX we are going to need a different format
 
-	if !((len(account) == 40) || (len(account) == 42)) { // with or without 0x
-		utils.Fatalf("Invalid account address '%s'", account)
+	if !((len(addr) == 40) || (len(addr) == 42)) { // with or without 0x
+		var index int
+		index, err = strconv.Atoi(addr)
+		if err != nil {
+			utils.Fatalf("Invalid account address '%s'", addr)
+		}
+
+		addrHex, err = am.AddressByIndex(index)
+		if err != nil {
+			utils.Fatalf("%v", err)
+		}
+	} else {
+		addrHex = addr
 	}
 	// Attempt to unlock the account 3 times
 	attempts := 3
 	for tries := 0; tries < attempts; tries++ {
-		msg := fmt.Sprintf("Unlocking account %s | Attempt %d/%d", account, tries+1, attempts)
-		passphrase := getPassPhrase(ctx, msg, false, i)
-		err = am.Unlock(common.HexToAddress(account), passphrase)
+		msg := fmt.Sprintf("Unlocking account %s | Attempt %d/%d", addr, tries+1, attempts)
+		auth = getPassPhrase(ctx, msg, false, i)
+		err = am.Unlock(common.HexToAddress(addrHex), auth)
 		if err == nil {
 			break
 		}
@@ -453,7 +491,8 @@ func unlockAccount(ctx *cli.Context, am *accounts.Manager, account string, i int
 	if err != nil {
 		utils.Fatalf("Unlock account failed '%v'", err)
 	}
-	fmt.Printf("Account '%s' unlocked.\n", account)
+	fmt.Printf("Account '%s' unlocked.\n", addr)
+	return
 }
 
 func blockRecovery(ctx *cli.Context) {
@@ -578,6 +617,21 @@ func accountCreate(ctx *cli.Context) {
 	fmt.Printf("Address: %x\n", acct)
 }
 
+func accountUpdate(ctx *cli.Context) {
+	am := utils.MakeAccountManager(ctx)
+	arg := ctx.Args().First()
+	if len(arg) == 0 {
+		utils.Fatalf("account address or index must be given as argument")
+	}
+
+	addr, authFrom := unlockAccount(ctx, am, arg, 0)
+	authTo := getPassPhrase(ctx, "Please give a new password. Do not forget this password.", true, 0)
+	err := am.Update(common.HexToAddress(addr), authFrom, authTo)
+	if err != nil {
+		utils.Fatalf("Could not update the account: %v", err)
+	}
+}
+
 func importWallet(ctx *cli.Context) {
 	keyfile := ctx.Args().First()
 	if len(keyfile) == 0 {
-- 
cgit v1.2.3