Merge pull request #3417 from karalabe/mobile-polishes
Account management API polishes
This commit is contained in:
		
						commit
						bb2e99dfc2
					
				| @ -152,8 +152,8 @@ func (am *Manager) Sign(addr common.Address, hash []byte) ([]byte, error) { | |||||||
| // SignWithPassphrase signs hash if the private key matching the given address
 | // SignWithPassphrase signs hash if the private key matching the given address
 | ||||||
| // can be decrypted with the given passphrase. The produced signature is in the
 | // can be decrypted with the given passphrase. The produced signature is in the
 | ||||||
| // [R || S || V] format where V is 0 or 1.
 | // [R || S || V] format where V is 0 or 1.
 | ||||||
| func (am *Manager) SignWithPassphrase(addr common.Address, passphrase string, hash []byte) (signature []byte, err error) { | func (am *Manager) SignWithPassphrase(a Account, passphrase string, hash []byte) (signature []byte, err error) { | ||||||
| 	_, key, err := am.getDecryptedKey(Account{Address: addr}, passphrase) | 	_, key, err := am.getDecryptedKey(a, passphrase) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -95,7 +95,7 @@ func TestSignWithPassphrase(t *testing.T) { | |||||||
| 		t.Fatal("expected account to be locked") | 		t.Fatal("expected account to be locked") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	_, err = am.SignWithPassphrase(acc.Address, pass, testSigData) | 	_, err = am.SignWithPassphrase(acc, pass, testSigData) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		t.Fatal(err) | 		t.Fatal(err) | ||||||
| 	} | 	} | ||||||
| @ -104,7 +104,7 @@ func TestSignWithPassphrase(t *testing.T) { | |||||||
| 		t.Fatal("expected account to be locked") | 		t.Fatal("expected account to be locked") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if _, err = am.SignWithPassphrase(acc.Address, "invalid passwd", testSigData); err == nil { | 	if _, err = am.SignWithPassphrase(acc, "invalid passwd", testSigData); err == nil { | ||||||
| 		t.Fatal("expected SignHash to fail with invalid password") | 		t.Fatal("expected SignHash to fail with invalid password") | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | |||||||
| @ -264,7 +264,7 @@ func (s *PrivateAccountAPI) SendTransaction(ctx context.Context, args SendTxArgs | |||||||
| 	} | 	} | ||||||
| 	tx := args.toTransaction() | 	tx := args.toTransaction() | ||||||
| 	signer := types.MakeSigner(s.b.ChainConfig(), s.b.CurrentBlock().Number()) | 	signer := types.MakeSigner(s.b.ChainConfig(), s.b.CurrentBlock().Number()) | ||||||
| 	signature, err := s.am.SignWithPassphrase(args.From, passwd, signer.Hash(tx).Bytes()) | 	signature, err := s.am.SignWithPassphrase(accounts.Account{Address: args.From}, passwd, signer.Hash(tx).Bytes()) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return common.Hash{}, err | 		return common.Hash{}, err | ||||||
| 	} | 	} | ||||||
| @ -294,11 +294,11 @@ func signHash(data []byte) []byte { | |||||||
| //
 | //
 | ||||||
| // https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_sign
 | // https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_sign
 | ||||||
| func (s *PrivateAccountAPI) Sign(ctx context.Context, data hexutil.Bytes, addr common.Address, passwd string) (hexutil.Bytes, error) { | func (s *PrivateAccountAPI) Sign(ctx context.Context, data hexutil.Bytes, addr common.Address, passwd string) (hexutil.Bytes, error) { | ||||||
| 	signature, err := s.b.AccountManager().SignWithPassphrase(addr, passwd, signHash(data)) | 	signature, err := s.b.AccountManager().SignWithPassphrase(accounts.Account{Address: addr}, passwd, signHash(data)) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 	signature[64] += 27 // SignWithPassphrase uses canonical secp256k1 signatures (v = 0 or 1), transform to yellow paper
 | 	signature[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper
 | ||||||
| 	return signature, nil | 	return signature, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -319,7 +319,7 @@ func (s *PrivateAccountAPI) EcRecover(ctx context.Context, data, sig hexutil.Byt | |||||||
| 	if sig[64] != 27 && sig[64] != 28 { | 	if sig[64] != 27 && sig[64] != 28 { | ||||||
| 		return common.Address{}, fmt.Errorf("invalid Ethereum signature (V is not 27 or 28)") | 		return common.Address{}, fmt.Errorf("invalid Ethereum signature (V is not 27 or 28)") | ||||||
| 	} | 	} | ||||||
| 	sig[64] -= 27 // Transform yellow paper signatures to canonical secp256k1 form
 | 	sig[64] -= 27 // Transform yellow paper V from 27/28 to 0/1
 | ||||||
| 
 | 
 | ||||||
| 	rpk, err := crypto.Ecrecover(signHash(data), sig) | 	rpk, err := crypto.Ecrecover(signHash(data), sig) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @ -1104,8 +1104,7 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encod | |||||||
| func (s *PublicTransactionPoolAPI) Sign(addr common.Address, data hexutil.Bytes) (hexutil.Bytes, error) { | func (s *PublicTransactionPoolAPI) Sign(addr common.Address, data hexutil.Bytes) (hexutil.Bytes, error) { | ||||||
| 	signature, err := s.b.AccountManager().Sign(addr, signHash(data)) | 	signature, err := s.b.AccountManager().Sign(addr, signHash(data)) | ||||||
| 	if err == nil { | 	if err == nil { | ||||||
| 		// Sign uses canonical secp256k1 signatures (v = 0 or 1), transform to yellow paper
 | 		signature[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper
 | ||||||
| 		signature[64] += 27 |  | ||||||
| 	} | 	} | ||||||
| 	return signature, err | 	return signature, err | ||||||
| } | } | ||||||
|  | |||||||
| @ -109,15 +109,17 @@ func (am *AccountManager) DeleteAccount(account *Account, passphrase string) err | |||||||
| 	}, passphrase) | 	}, passphrase) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Sign signs hash with an unlocked private key matching the given address.
 | // Sign calculates a ECDSA signature for the given hash. The produced signature
 | ||||||
|  | // is in the [R || S || V] format where V is 0 or 1.
 | ||||||
| func (am *AccountManager) Sign(address *Address, hash []byte) (signature []byte, _ error) { | func (am *AccountManager) Sign(address *Address, hash []byte) (signature []byte, _ error) { | ||||||
| 	return am.manager.Sign(address.address, hash) | 	return am.manager.Sign(address.address, hash) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // SignWithPassphrase signs hash if the private key matching the given address can be
 | // SignWithPassphrase signs hash if the private key matching the given address
 | ||||||
| // decrypted with the given passphrase.
 | // can be decrypted with the given passphrase. The produced signature is in the
 | ||||||
| func (am *AccountManager) SignWithPassphrase(address *Address, passphrase string, hash []byte) (signature []byte, _ error) { | // [R || S || V] format where V is 0 or 1.
 | ||||||
| 	return am.manager.SignWithPassphrase(address.address, passphrase, hash) | func (am *AccountManager) SignWithPassphrase(account *Account, passphrase string, hash []byte) (signature []byte, _ error) { | ||||||
|  | 	return am.manager.SignWithPassphrase(account.account, passphrase, hash) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Unlock unlocks the given account indefinitely.
 | // Unlock unlocks the given account indefinitely.
 | ||||||
| @ -130,15 +132,15 @@ func (am *AccountManager) Lock(address *Address) error { | |||||||
| 	return am.manager.Lock(address.address) | 	return am.manager.Lock(address.address) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // TimedUnlock unlocks the given account with the passphrase. The account
 | // TimedUnlock unlocks the given account with the passphrase. The account stays
 | ||||||
| // stays unlocked for the duration of timeout. A timeout of 0 unlocks the account
 | // unlocked for the duration of timeout (nanoseconds). A timeout of 0 unlocks the
 | ||||||
| // until the program exits. The account must match a unique key file.
 | // account until the program exits. The account must match a unique key file.
 | ||||||
| //
 | //
 | ||||||
| // If the account address is already unlocked for a duration, TimedUnlock extends or
 | // If the account address is already unlocked for a duration, TimedUnlock extends or
 | ||||||
| // shortens the active unlock timeout. If the address was previously unlocked
 | // shortens the active unlock timeout. If the address was previously unlocked
 | ||||||
| // indefinitely the timeout is not altered.
 | // indefinitely the timeout is not altered.
 | ||||||
| func (am *AccountManager) TimedUnlock(a *Account, passphrase string, timeout int64) error { | func (am *AccountManager) TimedUnlock(account *Account, passphrase string, timeout int64) error { | ||||||
| 	return am.manager.TimedUnlock(a.account, passphrase, time.Duration(timeout)) | 	return am.manager.TimedUnlock(account.account, passphrase, time.Duration(timeout)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewAccount generates a new key and stores it into the key directory,
 | // NewAccount generates a new key and stores it into the key directory,
 | ||||||
| @ -165,8 +167,8 @@ func (am *AccountManager) ImportKey(keyJSON []byte, passphrase, newPassphrase st | |||||||
| 	return &Account{acc}, nil | 	return &Account{acc}, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Update changes the passphrase of an existing account.
 | // UpdateAccount changes the passphrase of an existing account.
 | ||||||
| func (am *AccountManager) Update(account *Account, passphrase, newPassphrase string) error { | func (am *AccountManager) UpdateAccount(account *Account, passphrase, newPassphrase string) error { | ||||||
| 	return am.manager.Update(account.account, passphrase, newPassphrase) | 	return am.manager.Update(account.account, passphrase, newPassphrase) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -14,9 +14,6 @@ | |||||||
| // You should have received a copy of the GNU Lesser General Public License
 | // You should have received a copy of the GNU Lesser General Public License
 | ||||||
| // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 | ||||||
| 
 | 
 | ||||||
| // Contains all the wrappers from the accounts package to support client side key
 |  | ||||||
| // management on mobile platforms.
 |  | ||||||
| 
 |  | ||||||
| package geth | package geth | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| @ -46,14 +43,42 @@ public class AndroidTest extends InstrumentationTestCase { | |||||||
| 	public AndroidTest() {} | 	public AndroidTest() {} | ||||||
| 
 | 
 | ||||||
| 	public void testAccountManagement() { | 	public void testAccountManagement() { | ||||||
| 		try { | 		// Create an encrypted keystore manager with light crypto parameters.
 | ||||||
| 			AccountManager am = new AccountManager(getInstrumentation().getContext().getFilesDir() + "/keystore", Geth.LightScryptN, Geth.LightScryptP); | 		AccountManager am = new AccountManager(getInstrumentation().getContext().getFilesDir() + "/keystore", Geth.LightScryptN, Geth.LightScryptP); | ||||||
| 
 | 
 | ||||||
|  | 		try { | ||||||
|  | 			// Create a new account with the specified encryption passphrase.
 | ||||||
| 			Account newAcc = am.newAccount("Creation password"); | 			Account newAcc = am.newAccount("Creation password"); | ||||||
|  | 
 | ||||||
|  | 			// Export the newly created account with a different passphrase. The returned
 | ||||||
|  | 			// data from this method invocation is a JSON encoded, encrypted key-file.
 | ||||||
| 			byte[] jsonAcc = am.exportKey(newAcc, "Creation password", "Export password"); | 			byte[] jsonAcc = am.exportKey(newAcc, "Creation password", "Export password"); | ||||||
| 
 | 
 | ||||||
| 			am.deleteAccount(newAcc, "Creation password"); | 			// Update the passphrase on the account created above inside the local keystore.
 | ||||||
|  | 			am.updateAccount(newAcc, "Creation password", "Update password"); | ||||||
|  | 
 | ||||||
|  | 			// Delete the account updated above from the local keystore.
 | ||||||
|  | 			am.deleteAccount(newAcc, "Update password"); | ||||||
|  | 
 | ||||||
|  | 			// Import back the account we've exported (and then deleted) above with yet
 | ||||||
|  | 			// again a fresh passphrase.
 | ||||||
| 			Account impAcc = am.importKey(jsonAcc, "Export password", "Import password"); | 			Account impAcc = am.importKey(jsonAcc, "Export password", "Import password"); | ||||||
|  | 
 | ||||||
|  | 			// Create a new account to sign transactions with
 | ||||||
|  | 			Account signer = am.newAccount("Signer password"); | ||||||
|  | 			Hash txHash = new Hash("0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"); | ||||||
|  | 
 | ||||||
|  | 			// Sign a transaction with a single authorization
 | ||||||
|  | 			byte[] signature = am.signWithPassphrase(signer, "Signer password", txHash.getBytes()); | ||||||
|  | 
 | ||||||
|  | 			// Sign a transaction with multiple manually cancelled authorizations
 | ||||||
|  | 			am.unlock(signer, "Signer password"); | ||||||
|  | 			signature = am.sign(signer.getAddress(), txHash.getBytes()); | ||||||
|  | 			am.lock(signer.getAddress()); | ||||||
|  | 
 | ||||||
|  | 			// Sign a transaction with multiple automatically cancelled authorizations
 | ||||||
|  | 			am.timedUnlock(signer, "Signer password", 1000000000); | ||||||
|  | 			signature = am.sign(signer.getAddress(), txHash.getBytes()); | ||||||
| 		} catch (Exception e) { | 		} catch (Exception e) { | ||||||
| 			fail(e.toString()); | 			fail(e.toString()); | ||||||
| 		} | 		} | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user