Personal split (#2879)

* Split personal namespace into Safe and Unsafe part

* Re-add api.personal.accountsInfo() calls to dapps

* Removing listGethAccounts from safe personal
This commit is contained in:
Jaco Greeff 2016-10-27 19:26:34 +02:00 committed by Gav Wood
parent abb1da5f4b
commit 8dff4012a6
17 changed files with 276 additions and 199 deletions

View File

@ -16,7 +16,7 @@
import React, { Component, PropTypes } from 'react'; import React, { Component, PropTypes } from 'react';
// import { api } from '../parity'; import { api } from '../parity';
import { attachInstances } from '../services'; import { attachInstances } from '../services';
import Header from './Header'; import Header from './Header';
@ -83,7 +83,7 @@ export default class Application extends Component {
Promise Promise
.all([ .all([
attachInstances(), attachInstances(),
null // api.personal.accountsInfo() api.personal.accountsInfo()
]) ])
.then(([{ managerInstance, registryInstance, tokenregInstance }, accountsInfo]) => { .then(([{ managerInstance, registryInstance, tokenregInstance }, accountsInfo]) => {
accountsInfo = accountsInfo || {}; accountsInfo = accountsInfo || {};

View File

@ -206,7 +206,7 @@ export default class Application extends Component {
.all([ .all([
registry.getAddress.call({}, [api.util.sha3('gavcoin'), 'A']), registry.getAddress.call({}, [api.util.sha3('gavcoin'), 'A']),
api.eth.accounts(), api.eth.accounts(),
null // api.personal.accountsInfo() api.personal.accountsInfo()
]); ]);
}) })
.then(([address, addresses, infos]) => { .then(([address, addresses, infos]) => {

View File

@ -29,7 +29,7 @@ export function attachInterface () {
.all([ .all([
registry.getAddress.call({}, [api.util.sha3('githubhint'), 'A']), registry.getAddress.call({}, [api.util.sha3('githubhint'), 'A']),
api.eth.accounts(), api.eth.accounts(),
null // api.personal.accountsInfo() api.personal.accountsInfo()
]); ]);
}) })
.then(([address, addresses, accountsInfo]) => { .then(([address, addresses, accountsInfo]) => {

View File

@ -22,12 +22,16 @@ export const fetch = () => (dispatch) => {
return Promise return Promise
.all([ .all([
api.eth.accounts(), api.eth.accounts(),
null // api.personal.accountsInfo() api.personal.accountsInfo()
]) ])
.then(([ accounts, data ]) => { .then(([ accounts, data ]) => {
const addresses = accounts.map((address) => { data = data || {};
return { address, isAccount: true }; const addresses = Object.keys(data)
}); .filter((address) => data[address] && !data[address].meta.deleted)
.map((address) => ({
...data[address], address,
isAccount: accounts.includes(address)
}));
dispatch(set(addresses)); dispatch(set(addresses));
}) })
.catch((error) => { .catch((error) => {

View File

@ -50,7 +50,7 @@ export function attachInterface (callback) {
.all([ .all([
registry.getAddress.call({}, [api.util.sha3('signaturereg'), 'A']), registry.getAddress.call({}, [api.util.sha3('signaturereg'), 'A']),
api.eth.accounts(), api.eth.accounts(),
null // api.personal.accountsInfo() api.personal.accountsInfo()
]); ]);
}) })
.then(([address, addresses, accountsInfo]) => { .then(([address, addresses, accountsInfo]) => {

View File

@ -38,7 +38,7 @@ export const loadAccounts = () => (dispatch) => {
Promise Promise
.all([ .all([
api.eth.accounts(), api.eth.accounts(),
null // api.personal.accountsInfo() api.personal.accountsInfo()
]) ])
.then(([ accounts, accountsInfo ]) => { .then(([ accounts, accountsInfo ]) => {
accountsInfo = accountsInfo || {}; accountsInfo = accountsInfo || {};

View File

@ -41,13 +41,13 @@ disable = false
port = 8545 port = 8545
interface = "local" interface = "local"
cors = "null" cors = "null"
apis = ["web3", "eth", "net", "ethcore", "traces", "rpc"] apis = ["web3", "eth", "net", "ethcore", "traces", "rpc", "personal_safe"]
hosts = ["none"] hosts = ["none"]
[ipc] [ipc]
disable = false disable = false
path = "$HOME/.parity/jsonrpc.ipc" path = "$HOME/.parity/jsonrpc.ipc"
apis = ["web3", "eth", "net", "ethcore", "traces", "rpc"] apis = ["web3", "eth", "net", "ethcore", "traces", "rpc", "personal_safe"]
[dapps] [dapps]
disable = false disable = false

View File

@ -145,7 +145,7 @@ usage! {
or |c: &Config| otry!(c.rpc).interface.clone(), or |c: &Config| otry!(c.rpc).interface.clone(),
flag_jsonrpc_cors: Option<String> = None, flag_jsonrpc_cors: Option<String> = None,
or |c: &Config| otry!(c.rpc).cors.clone().map(Some), or |c: &Config| otry!(c.rpc).cors.clone().map(Some),
flag_jsonrpc_apis: String = "web3,eth,net,ethcore,traces,rpc", flag_jsonrpc_apis: String = "web3,eth,net,ethcore,traces,rpc,personal_safe",
or |c: &Config| otry!(c.rpc).apis.clone().map(|vec| vec.join(",")), or |c: &Config| otry!(c.rpc).apis.clone().map(|vec| vec.join(",")),
flag_jsonrpc_hosts: String = "none", flag_jsonrpc_hosts: String = "none",
or |c: &Config| otry!(c.rpc).hosts.clone().map(|vec| vec.join(",")), or |c: &Config| otry!(c.rpc).hosts.clone().map(|vec| vec.join(",")),
@ -155,7 +155,7 @@ usage! {
or |c: &Config| otry!(c.ipc).disable.clone(), or |c: &Config| otry!(c.ipc).disable.clone(),
flag_ipc_path: String = "$HOME/.parity/jsonrpc.ipc", flag_ipc_path: String = "$HOME/.parity/jsonrpc.ipc",
or |c: &Config| otry!(c.ipc).path.clone(), or |c: &Config| otry!(c.ipc).path.clone(),
flag_ipc_apis: String = "web3,eth,net,ethcore,traces,rpc", flag_ipc_apis: String = "web3,eth,net,ethcore,traces,rpc,personal_safe",
or |c: &Config| otry!(c.ipc).apis.clone().map(|vec| vec.join(",")), or |c: &Config| otry!(c.ipc).apis.clone().map(|vec| vec.join(",")),
// DAPPS // DAPPS
@ -534,13 +534,13 @@ mod tests {
flag_jsonrpc_port: 8545u16, flag_jsonrpc_port: 8545u16,
flag_jsonrpc_interface: "local".into(), flag_jsonrpc_interface: "local".into(),
flag_jsonrpc_cors: Some("null".into()), flag_jsonrpc_cors: Some("null".into()),
flag_jsonrpc_apis: "web3,eth,net,ethcore,traces,rpc".into(), flag_jsonrpc_apis: "web3,eth,net,ethcore,traces,rpc,personal_safe".into(),
flag_jsonrpc_hosts: "none".into(), flag_jsonrpc_hosts: "none".into(),
// IPC // IPC
flag_no_ipc: false, flag_no_ipc: false,
flag_ipc_path: "$HOME/.parity/jsonrpc.ipc".into(), flag_ipc_path: "$HOME/.parity/jsonrpc.ipc".into(),
flag_ipc_apis: "web3,eth,net,ethcore,traces,rpc".into(), flag_ipc_apis: "web3,eth,net,ethcore,traces,rpc,personal_safe".into(),
// DAPPS // DAPPS
flag_no_dapps: false, flag_no_dapps: false,

View File

@ -107,7 +107,7 @@ API and Console Options:
--jsonrpc-apis APIS Specify the APIs available through the JSONRPC --jsonrpc-apis APIS Specify the APIs available through the JSONRPC
interface. APIS is a comma-delimited list of API interface. APIS is a comma-delimited list of API
name. Possible name are web3, eth, net, personal, name. Possible name are web3, eth, net, personal,
ethcore, ethcore_set, traces, rpc. ethcore, ethcore_set, traces, rpc, personal_safe.
(default: {flag_jsonrpc_apis}). (default: {flag_jsonrpc_apis}).
--jsonrpc-hosts HOSTS List of allowed Host header values. This option will --jsonrpc-hosts HOSTS List of allowed Host header values. This option will
validate the Host header sent by the browser, it validate the Host header sent by the browser, it

View File

@ -33,7 +33,8 @@ pub enum Api {
Web3, Web3,
Net, Net,
Eth, Eth,
Personal, PersonalSafe,
PersonalAccounts,
Signer, Signer,
Ethcore, Ethcore,
EthcoreSet, EthcoreSet,
@ -51,7 +52,8 @@ impl FromStr for Api {
"web3" => Ok(Web3), "web3" => Ok(Web3),
"net" => Ok(Net), "net" => Ok(Net),
"eth" => Ok(Eth), "eth" => Ok(Eth),
"personal" => Ok(Personal), "personal" => Ok(PersonalAccounts),
"personal_safe" => Ok(PersonalSafe),
"signer" => Ok(Signer), "signer" => Ok(Signer),
"ethcore" => Ok(Ethcore), "ethcore" => Ok(Ethcore),
"ethcore_set" => Ok(EthcoreSet), "ethcore_set" => Ok(EthcoreSet),
@ -114,7 +116,8 @@ fn to_modules(apis: &[Api]) -> BTreeMap<String, String> {
Api::Web3 => ("web3", "1.0"), Api::Web3 => ("web3", "1.0"),
Api::Net => ("net", "1.0"), Api::Net => ("net", "1.0"),
Api::Eth => ("eth", "1.0"), Api::Eth => ("eth", "1.0"),
Api::Personal => ("personal", "1.0"), Api::PersonalSafe => ("personal_safe", "1.0"),
Api::PersonalAccounts => ("personal", "1.0"),
Api::Signer => ("signer", "1.0"), Api::Signer => ("signer", "1.0"),
Api::Ethcore => ("ethcore", "1.0"), Api::Ethcore => ("ethcore", "1.0"),
Api::EthcoreSet => ("ethcore_set", "1.0"), Api::EthcoreSet => ("ethcore_set", "1.0"),
@ -131,11 +134,11 @@ impl ApiSet {
match *self { match *self {
ApiSet::List(ref apis) => apis.clone(), ApiSet::List(ref apis) => apis.clone(),
ApiSet::UnsafeContext => { ApiSet::UnsafeContext => {
vec![Api::Web3, Api::Net, Api::Eth, Api::Ethcore, Api::Traces, Api::Rpc] vec![Api::Web3, Api::Net, Api::Eth, Api::Ethcore, Api::Traces, Api::Rpc, Api::PersonalSafe]
.into_iter().collect() .into_iter().collect()
}, },
ApiSet::SafeContext => { ApiSet::SafeContext => {
vec![Api::Web3, Api::Net, Api::Eth, Api::Personal, Api::Signer, Api::Ethcore, Api::EthcoreSet, Api::Traces, Api::Rpc] vec![Api::Web3, Api::Net, Api::Eth, Api::PersonalAccounts, Api::PersonalSafe, Api::Signer, Api::Ethcore, Api::EthcoreSet, Api::Traces, Api::Rpc]
.into_iter().collect() .into_iter().collect()
}, },
} }
@ -178,8 +181,11 @@ pub fn setup_rpc<T: Extendable>(server: T, deps: Arc<Dependencies>, apis: ApiSet
server.add_delegate(EthSigningUnsafeClient::new(&deps.client, &deps.secret_store, &deps.miner).to_delegate()); server.add_delegate(EthSigningUnsafeClient::new(&deps.client, &deps.secret_store, &deps.miner).to_delegate());
} }
}, },
Api::Personal => { Api::PersonalAccounts => {
server.add_delegate(PersonalClient::new(&deps.secret_store, &deps.client, &deps.miner, deps.geth_compatibility).to_delegate()); server.add_delegate(PersonalAccountsClient::new(&deps.secret_store, &deps.client, &deps.miner, deps.geth_compatibility).to_delegate());
},
Api::PersonalSafe => {
server.add_delegate(PersonalClient::new(&deps.secret_store, &deps.client).to_delegate());
}, },
Api::Signer => { Api::Signer => {
server.add_delegate(SignerClient::new(&deps.secret_store, &deps.client, &deps.miner, &deps.signer_service).to_delegate()); server.add_delegate(SignerClient::new(&deps.secret_store, &deps.client, &deps.miner, &deps.signer_service).to_delegate());
@ -224,7 +230,8 @@ mod test {
assert_eq!(Api::Web3, "web3".parse().unwrap()); assert_eq!(Api::Web3, "web3".parse().unwrap());
assert_eq!(Api::Net, "net".parse().unwrap()); assert_eq!(Api::Net, "net".parse().unwrap());
assert_eq!(Api::Eth, "eth".parse().unwrap()); assert_eq!(Api::Eth, "eth".parse().unwrap());
assert_eq!(Api::Personal, "personal".parse().unwrap()); assert_eq!(Api::PersonalAccounts, "personal".parse().unwrap());
assert_eq!(Api::PersonalSafe, "personal_safe".parse().unwrap());
assert_eq!(Api::Signer, "signer".parse().unwrap()); assert_eq!(Api::Signer, "signer".parse().unwrap());
assert_eq!(Api::Ethcore, "ethcore".parse().unwrap()); assert_eq!(Api::Ethcore, "ethcore".parse().unwrap());
assert_eq!(Api::EthcoreSet, "ethcore_set".parse().unwrap()); assert_eq!(Api::EthcoreSet, "ethcore_set".parse().unwrap());
@ -245,14 +252,14 @@ mod test {
#[test] #[test]
fn test_api_set_unsafe_context() { fn test_api_set_unsafe_context() {
let expected = vec![Api::Web3, Api::Net, Api::Eth, Api::Ethcore, Api::Traces, Api::Rpc] let expected = vec![Api::Web3, Api::Net, Api::Eth, Api::Ethcore, Api::Traces, Api::Rpc, Api::PersonalSafe]
.into_iter().collect(); .into_iter().collect();
assert_eq!(ApiSet::UnsafeContext.list_apis(), expected); assert_eq!(ApiSet::UnsafeContext.list_apis(), expected);
} }
#[test] #[test]
fn test_api_set_safe_context() { fn test_api_set_safe_context() {
let expected = vec![Api::Web3, Api::Net, Api::Eth, Api::Personal, Api::Signer, Api::Ethcore, Api::EthcoreSet, Api::Traces, Api::Rpc] let expected = vec![Api::Web3, Api::Net, Api::Eth, Api::PersonalAccounts, Api::PersonalSafe, Api::Signer, Api::Ethcore, Api::EthcoreSet, Api::Traces, Api::Rpc]
.into_iter().collect(); .into_iter().collect();
assert_eq!(ApiSet::SafeContext.list_apis(), expected); assert_eq!(ApiSet::SafeContext.list_apis(), expected);
} }

View File

@ -32,6 +32,7 @@ mod ethcore;
mod ethcore_set; mod ethcore_set;
mod net; mod net;
mod personal; mod personal;
mod personal_accounts;
mod personal_signer; mod personal_signer;
mod rpc; mod rpc;
mod traces; mod traces;
@ -43,6 +44,7 @@ pub use self::eth_filter::EthFilterClient;
pub use self::eth_signing::{EthSigningUnsafeClient, EthSigningQueueClient}; pub use self::eth_signing::{EthSigningUnsafeClient, EthSigningQueueClient};
pub use self::net::NetClient; pub use self::net::NetClient;
pub use self::personal::PersonalClient; pub use self::personal::PersonalClient;
pub use self::personal_accounts::PersonalAccountsClient;
pub use self::personal_signer::SignerClient; pub use self::personal_signer::SignerClient;
pub use self::ethcore::EthcoreClient; pub use self::ethcore::EthcoreClient;
pub use self::ethcore_set::EthcoreSetClient; pub use self::ethcore_set::EthcoreSetClient;

View File

@ -17,34 +17,26 @@
//! Account management (personal) rpc implementation //! Account management (personal) rpc implementation
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
use std::collections::{BTreeMap}; use std::collections::{BTreeMap};
use util::{Address};
use jsonrpc_core::*; use jsonrpc_core::*;
use ethkey::{Brain, Generator};
use v1::traits::Personal; use v1::traits::Personal;
use v1::types::{H160 as RpcH160, TransactionRequest}; use v1::types::{H160 as RpcH160};
use v1::helpers::errors; use v1::helpers::errors;
use v1::helpers::params::expect_no_params; use v1::helpers::params::expect_no_params;
use v1::helpers::dispatch::sign_and_dispatch;
use ethcore::account_provider::AccountProvider; use ethcore::account_provider::AccountProvider;
use ethcore::client::MiningBlockChainClient; use ethcore::client::MiningBlockChainClient;
use ethcore::miner::MinerService;
/// Account management (personal) rpc implementation. /// Account management (personal) rpc implementation.
pub struct PersonalClient<C, M> where C: MiningBlockChainClient, M: MinerService { pub struct PersonalClient<C> where C: MiningBlockChainClient {
accounts: Weak<AccountProvider>, accounts: Weak<AccountProvider>,
client: Weak<C>, client: Weak<C>,
miner: Weak<M>,
allow_perm_unlock: bool,
} }
impl<C, M> PersonalClient<C, M> where C: MiningBlockChainClient, M: MinerService { impl<C> PersonalClient<C> where C: MiningBlockChainClient {
/// Creates new PersonalClient /// Creates new PersonalClient
pub fn new(store: &Arc<AccountProvider>, client: &Arc<C>, miner: &Arc<M>, allow_perm_unlock: bool) -> Self { pub fn new(store: &Arc<AccountProvider>, client: &Arc<C>) -> Self {
PersonalClient { PersonalClient {
accounts: Arc::downgrade(store), accounts: Arc::downgrade(store),
client: Arc::downgrade(client), client: Arc::downgrade(client),
miner: Arc::downgrade(miner),
allow_perm_unlock: allow_perm_unlock,
} }
} }
@ -55,7 +47,7 @@ impl<C, M> PersonalClient<C, M> where C: MiningBlockChainClient, M: MinerService
} }
} }
impl<C: 'static, M: 'static> Personal for PersonalClient<C, M> where C: MiningBlockChainClient, M: MinerService { impl<C: 'static> Personal for PersonalClient<C> where C: MiningBlockChainClient {
fn accounts(&self, params: Params) -> Result<Value, Error> { fn accounts(&self, params: Params) -> Result<Value, Error> {
try!(self.active()); try!(self.active());
@ -66,125 +58,6 @@ impl<C: 'static, M: 'static> Personal for PersonalClient<C, M> where C: MiningBl
Ok(to_value(&accounts.into_iter().map(Into::into).collect::<Vec<RpcH160>>())) Ok(to_value(&accounts.into_iter().map(Into::into).collect::<Vec<RpcH160>>()))
} }
fn new_account(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
from_params::<(String, )>(params).and_then(
|(pass, )| {
let store = take_weak!(self.accounts);
match store.new_account(&pass) {
Ok(address) => Ok(to_value(&RpcH160::from(address))),
Err(e) => Err(errors::account("Could not create account.", e)),
}
}
)
}
fn new_account_from_phrase(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
from_params::<(String, String, )>(params).and_then(
|(phrase, pass, )| {
let store = take_weak!(self.accounts);
match store.insert_account(*Brain::new(phrase).generate().unwrap().secret(), &pass) {
Ok(address) => Ok(to_value(&RpcH160::from(address))),
Err(e) => Err(errors::account("Could not create account.", e)),
}
}
)
}
fn new_account_from_wallet(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
from_params::<(String, String, )>(params).and_then(
|(json, pass, )| {
let store = take_weak!(self.accounts);
match store.import_presale(json.as_bytes(), &pass).or_else(|_| store.import_wallet(json.as_bytes(), &pass)) {
Ok(address) => Ok(to_value(&RpcH160::from(address))),
Err(e) => Err(errors::account("Could not create account.", e)),
}
}
)
}
fn unlock_account(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
from_params::<(RpcH160, String, Option<u64>)>(params).and_then(
|(account, account_pass, duration)| {
let account: Address = account.into();
let store = take_weak!(self.accounts);
let r = match (self.allow_perm_unlock, duration) {
(false, _) => store.unlock_account_temporarily(account, account_pass),
(true, Some(0)) => store.unlock_account_permanently(account, account_pass),
(true, Some(d)) => store.unlock_account_timed(account, account_pass, d as u32 * 1000),
(true, None) => store.unlock_account_timed(account, account_pass, 300_000),
};
match r {
Ok(_) => Ok(Value::Bool(true)),
Err(_) => Ok(Value::Bool(false)),
}
}
)
}
fn test_password(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
from_params::<(RpcH160, String)>(params).and_then(
|(account, password)| {
let account: Address = account.into();
take_weak!(self.accounts)
.test_password(&account, password)
.map(|b| Value::Bool(b))
.map_err(|e| errors::account("Could not fetch account info.", e))
}
)
}
fn change_password(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
from_params::<(RpcH160, String, String)>(params).and_then(
|(account, password, new_password)| {
let account: Address = account.into();
take_weak!(self.accounts)
.change_password(&account, password, new_password)
.map(|_| Value::Null)
.map_err(|e| errors::account("Could not fetch account info.", e))
}
)
}
fn sign_and_send_transaction(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
from_params::<(TransactionRequest, String)>(params)
.and_then(|(request, password)| {
sign_and_dispatch(
&*take_weak!(self.client),
&*take_weak!(self.miner),
&*take_weak!(self.accounts),
request.into(),
Some(password)
)
})
}
fn set_account_name(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
let store = take_weak!(self.accounts);
from_params::<(RpcH160, String)>(params).and_then(|(addr, name)| {
let addr: Address = addr.into();
store.set_account_name(addr.clone(), name.clone()).or_else(|_| store.set_address_name(addr, name)).expect("set_address_name always returns Ok; qed");
Ok(Value::Null)
})
}
fn set_account_meta(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
let store = take_weak!(self.accounts);
from_params::<(RpcH160, String)>(params).and_then(|(addr, meta)| {
let addr: Address = addr.into();
store.set_account_meta(addr.clone(), meta.clone()).or_else(|_| store.set_address_meta(addr, meta)).expect("set_address_meta always returns Ok; qed");
Ok(Value::Null)
})
}
fn accounts_info(&self, params: Params) -> Result<Value, Error> { fn accounts_info(&self, params: Params) -> Result<Value, Error> {
try!(self.active()); try!(self.active());
try!(expect_no_params(params)); try!(expect_no_params(params));
@ -204,21 +77,4 @@ impl<C: 'static, M: 'static> Personal for PersonalClient<C, M> where C: MiningBl
(format!("0x{}", a.hex()), Value::Object(m)) (format!("0x{}", a.hex()), Value::Object(m))
}).collect::<BTreeMap<_, _>>())) }).collect::<BTreeMap<_, _>>()))
} }
fn geth_accounts(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
try!(expect_no_params(params));
let store = take_weak!(self.accounts);
Ok(to_value(&store.list_geth_accounts(false).into_iter().map(Into::into).collect::<Vec<RpcH160>>()))
}
fn import_geth_accounts(&self, params: Params) -> Result<Value, Error> {
from_params::<(Vec<RpcH160>,)>(params).and_then(|(addresses,)| {
let store = take_weak!(self.accounts);
Ok(to_value(&try!(store
.import_geth_accounts(addresses.into_iter().map(Into::into).collect(), false)
.map_err(|e| errors::account("Couldn't import Geth accounts", e))
).into_iter().map(Into::into).collect::<Vec<RpcH160>>()))
})
}
} }

View File

@ -0,0 +1,194 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity 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.
// Parity 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 Parity. If not, see <http://www.gnu.org/licenses/>.
//! Account management (personal) rpc implementation
use std::sync::{Arc, Weak};
use util::{Address};
use jsonrpc_core::*;
use ethkey::{Brain, Generator};
use v1::traits::PersonalAccounts;
use v1::types::{H160 as RpcH160, TransactionRequest};
use v1::helpers::errors;
use v1::helpers::params::expect_no_params;
use v1::helpers::dispatch::sign_and_dispatch;
use ethcore::account_provider::AccountProvider;
use ethcore::client::MiningBlockChainClient;
use ethcore::miner::MinerService;
/// Account management (personal) rpc implementation.
pub struct PersonalAccountsClient<C, M> where C: MiningBlockChainClient, M: MinerService {
accounts: Weak<AccountProvider>,
client: Weak<C>,
miner: Weak<M>,
allow_perm_unlock: bool,
}
impl<C, M> PersonalAccountsClient<C, M> where C: MiningBlockChainClient, M: MinerService {
/// Creates new PersonalClient
pub fn new(store: &Arc<AccountProvider>, client: &Arc<C>, miner: &Arc<M>, allow_perm_unlock: bool) -> Self {
PersonalAccountsClient {
accounts: Arc::downgrade(store),
client: Arc::downgrade(client),
miner: Arc::downgrade(miner),
allow_perm_unlock: allow_perm_unlock,
}
}
fn active(&self) -> Result<(), Error> {
// TODO: only call every 30s at most.
take_weak!(self.client).keep_alive();
Ok(())
}
}
impl<C: 'static, M: 'static> PersonalAccounts for PersonalAccountsClient<C, M> where C: MiningBlockChainClient, M: MinerService {
fn new_account(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
from_params::<(String, )>(params).and_then(
|(pass, )| {
let store = take_weak!(self.accounts);
match store.new_account(&pass) {
Ok(address) => Ok(to_value(&RpcH160::from(address))),
Err(e) => Err(errors::account("Could not create account.", e)),
}
}
)
}
fn new_account_from_phrase(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
from_params::<(String, String, )>(params).and_then(
|(phrase, pass, )| {
let store = take_weak!(self.accounts);
match store.insert_account(*Brain::new(phrase).generate().unwrap().secret(), &pass) {
Ok(address) => Ok(to_value(&RpcH160::from(address))),
Err(e) => Err(errors::account("Could not create account.", e)),
}
}
)
}
fn new_account_from_wallet(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
from_params::<(String, String, )>(params).and_then(
|(json, pass, )| {
let store = take_weak!(self.accounts);
match store.import_presale(json.as_bytes(), &pass).or_else(|_| store.import_wallet(json.as_bytes(), &pass)) {
Ok(address) => Ok(to_value(&RpcH160::from(address))),
Err(e) => Err(errors::account("Could not create account.", e)),
}
}
)
}
fn unlock_account(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
from_params::<(RpcH160, String, Option<u64>)>(params).and_then(
|(account, account_pass, duration)| {
let account: Address = account.into();
let store = take_weak!(self.accounts);
let r = match (self.allow_perm_unlock, duration) {
(false, _) => store.unlock_account_temporarily(account, account_pass),
(true, Some(0)) => store.unlock_account_permanently(account, account_pass),
(true, Some(d)) => store.unlock_account_timed(account, account_pass, d as u32 * 1000),
(true, None) => store.unlock_account_timed(account, account_pass, 300_000),
};
match r {
Ok(_) => Ok(Value::Bool(true)),
Err(_) => Ok(Value::Bool(false)),
}
}
)
}
fn test_password(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
from_params::<(RpcH160, String)>(params).and_then(
|(account, password)| {
let account: Address = account.into();
take_weak!(self.accounts)
.test_password(&account, password)
.map(|b| Value::Bool(b))
.map_err(|e| errors::account("Could not fetch account info.", e))
}
)
}
fn change_password(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
from_params::<(RpcH160, String, String)>(params).and_then(
|(account, password, new_password)| {
let account: Address = account.into();
take_weak!(self.accounts)
.change_password(&account, password, new_password)
.map(|_| Value::Null)
.map_err(|e| errors::account("Could not fetch account info.", e))
}
)
}
fn sign_and_send_transaction(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
from_params::<(TransactionRequest, String)>(params)
.and_then(|(request, password)| {
sign_and_dispatch(
&*take_weak!(self.client),
&*take_weak!(self.miner),
&*take_weak!(self.accounts),
request.into(),
Some(password)
)
})
}
fn set_account_name(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
let store = take_weak!(self.accounts);
from_params::<(RpcH160, String)>(params).and_then(|(addr, name)| {
let addr: Address = addr.into();
store.set_account_name(addr.clone(), name.clone()).or_else(|_| store.set_address_name(addr, name)).expect("set_address_name always returns Ok; qed");
Ok(Value::Null)
})
}
fn set_account_meta(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
let store = take_weak!(self.accounts);
from_params::<(RpcH160, String)>(params).and_then(|(addr, meta)| {
let addr: Address = addr.into();
store.set_account_meta(addr.clone(), meta.clone()).or_else(|_| store.set_address_meta(addr, meta)).expect("set_address_meta always returns Ok; qed");
Ok(Value::Null)
})
}
fn import_geth_accounts(&self, params: Params) -> Result<Value, Error> {
from_params::<(Vec<RpcH160>,)>(params).and_then(|(addresses,)| {
let store = take_weak!(self.accounts);
Ok(to_value(&try!(store
.import_geth_accounts(addresses.into_iter().map(Into::into).collect(), false)
.map_err(|e| errors::account("Couldn't import Geth accounts", e))
).into_iter().map(Into::into).collect::<Vec<RpcH160>>()))
})
}
fn geth_accounts(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
try!(expect_no_params(params));
let store = take_weak!(self.accounts);
Ok(to_value(&store.list_geth_accounts(false).into_iter().map(Into::into).collect::<Vec<RpcH160>>()))
}
}

View File

@ -26,6 +26,6 @@ pub mod traits;
pub mod tests; pub mod tests;
pub mod types; pub mod types;
pub use self::traits::{Web3, Eth, EthFilter, EthSigning, Personal, PersonalSigner, Net, Ethcore, EthcoreSet, Traces, Rpc}; pub use self::traits::{Web3, Eth, EthFilter, EthSigning, Personal, PersonalAccounts, PersonalSigner, Net, Ethcore, EthcoreSet, Traces, Rpc};
pub use self::impls::*; pub use self::impls::*;
pub use self::helpers::{SigningQueue, SignerService, ConfirmationsQueue, NetworkSettings, block_import}; pub use self::helpers::{SigningQueue, SignerService, ConfirmationsQueue, NetworkSettings, block_import};

View File

@ -19,7 +19,7 @@ use std::str::FromStr;
use jsonrpc_core::IoHandler; use jsonrpc_core::IoHandler;
use util::{U256, Uint, Address}; use util::{U256, Uint, Address};
use ethcore::account_provider::AccountProvider; use ethcore::account_provider::AccountProvider;
use v1::{PersonalClient, Personal}; use v1::{PersonalClient, PersonalAccountsClient, PersonalAccounts, Personal};
use v1::tests::helpers::TestMinerService; use v1::tests::helpers::TestMinerService;
use ethcore::client::TestBlockChainClient; use ethcore::client::TestBlockChainClient;
use ethcore::transaction::{Action, Transaction}; use ethcore::transaction::{Action, Transaction};
@ -50,10 +50,12 @@ fn setup() -> PersonalTester {
let accounts = accounts_provider(); let accounts = accounts_provider();
let client = blockchain_client(); let client = blockchain_client();
let miner = miner_service(); let miner = miner_service();
let personal = PersonalClient::new(&accounts, &client, &miner, false); let personal = PersonalClient::new(&accounts, &client);
let personal_accounts = PersonalAccountsClient::new(&accounts, &client, &miner, false);
let io = IoHandler::new(); let io = IoHandler::new();
io.add_delegate(personal.to_delegate()); io.add_delegate(personal.to_delegate());
io.add_delegate(personal_accounts.to_delegate());
let tester = PersonalTester { let tester = PersonalTester {
accounts: accounts, accounts: accounts,

View File

@ -30,7 +30,7 @@ pub use self::web3::Web3;
pub use self::eth::{Eth, EthFilter}; pub use self::eth::{Eth, EthFilter};
pub use self::eth_signing::EthSigning; pub use self::eth_signing::EthSigning;
pub use self::net::Net; pub use self::net::Net;
pub use self::personal::{Personal, PersonalSigner}; pub use self::personal::{Personal, PersonalAccounts, PersonalSigner};
pub use self::ethcore::Ethcore; pub use self::ethcore::Ethcore;
pub use self::ethcore_set::EthcoreSet; pub use self::ethcore_set::EthcoreSet;
pub use self::traces::Traces; pub use self::traces::Traces;

View File

@ -18,12 +18,28 @@
use std::sync::Arc; use std::sync::Arc;
use jsonrpc_core::*; use jsonrpc_core::*;
/// Personal rpc interface. /// Personal rpc interface. Safe (read-only) functions.
pub trait Personal: Sized + Send + Sync + 'static { pub trait Personal: Sized + Send + Sync + 'static {
/// Lists all stored accounts /// Lists all stored accounts
fn accounts(&self, _: Params) -> Result<Value, Error>; fn accounts(&self, _: Params) -> Result<Value, Error>;
/// Returns accounts information.
fn accounts_info(&self, _: Params) -> Result<Value, Error>;
/// Should be used to convert object to io delegate.
fn to_delegate(self) -> IoDelegate<Self> {
let mut delegate = IoDelegate::new(Arc::new(self));
delegate.add_method("personal_listAccounts", Personal::accounts);
delegate.add_method("personal_accountsInfo", Personal::accounts_info);
delegate
}
}
/// Personal rpc methods altering stored accounts or their settings.
pub trait PersonalAccounts: Sized + Send + Sync + 'static {
/// Creates new account (it becomes new current unlocked account) /// Creates new account (it becomes new current unlocked account)
/// Param is the password for the account. /// Param is the password for the account.
fn new_account(&self, _: Params) -> Result<Value, Error>; fn new_account(&self, _: Params) -> Result<Value, Error>;
@ -56,31 +72,26 @@ pub trait Personal: Sized + Send + Sync + 'static {
/// Set an account's metadata string. /// Set an account's metadata string.
fn set_account_meta(&self, _: Params) -> Result<Value, Error>; fn set_account_meta(&self, _: Params) -> Result<Value, Error>;
/// Returns accounts information. /// Imports a number of Geth accounts, with the list provided as the argument.
fn accounts_info(&self, _: Params) -> Result<Value, Error>; fn import_geth_accounts(&self, _: Params) -> Result<Value, Error>;
/// Returns the accounts available for importing from Geth. /// Returns the accounts available for importing from Geth.
fn geth_accounts(&self, _: Params) -> Result<Value, Error>; fn geth_accounts(&self, _: Params) -> Result<Value, Error>;
/// Imports a number of Geth accounts, with the list provided as the argument.
fn import_geth_accounts(&self, _: Params) -> Result<Value, Error>;
/// Should be used to convert object to io delegate. /// Should be used to convert object to io delegate.
fn to_delegate(self) -> IoDelegate<Self> { fn to_delegate(self) -> IoDelegate<Self> {
let mut delegate = IoDelegate::new(Arc::new(self)); let mut delegate = IoDelegate::new(Arc::new(self));
delegate.add_method("personal_listAccounts", Personal::accounts); delegate.add_method("personal_newAccount", PersonalAccounts::new_account);
delegate.add_method("personal_newAccount", Personal::new_account); delegate.add_method("personal_newAccountFromPhrase", PersonalAccounts::new_account_from_phrase);
delegate.add_method("personal_newAccountFromPhrase", Personal::new_account_from_phrase); delegate.add_method("personal_newAccountFromWallet", PersonalAccounts::new_account_from_wallet);
delegate.add_method("personal_newAccountFromWallet", Personal::new_account_from_wallet); delegate.add_method("personal_unlockAccount", PersonalAccounts::unlock_account);
delegate.add_method("personal_unlockAccount", Personal::unlock_account); delegate.add_method("personal_testPassword", PersonalAccounts::test_password);
delegate.add_method("personal_testPassword", Personal::test_password); delegate.add_method("personal_changePassword", PersonalAccounts::change_password);
delegate.add_method("personal_changePassword", Personal::change_password); delegate.add_method("personal_signAndSendTransaction", PersonalAccounts::sign_and_send_transaction);
delegate.add_method("personal_signAndSendTransaction", Personal::sign_and_send_transaction); delegate.add_method("personal_setAccountName", PersonalAccounts::set_account_name);
delegate.add_method("personal_setAccountName", Personal::set_account_name); delegate.add_method("personal_setAccountMeta", PersonalAccounts::set_account_meta);
delegate.add_method("personal_setAccountMeta", Personal::set_account_meta); delegate.add_method("personal_importGethAccounts", PersonalAccounts::import_geth_accounts);
delegate.add_method("personal_accountsInfo", Personal::accounts_info); delegate.add_method("personal_listGethAccounts", PersonalAccounts::geth_accounts);
delegate.add_method("personal_listGethAccounts", Personal::geth_accounts);
delegate.add_method("personal_importGethAccounts", Personal::import_geth_accounts);
delegate delegate
} }
@ -108,6 +119,7 @@ pub trait PersonalSigner: Sized + Send + Sync + 'static {
delegate.add_method("personal_confirmRequest", PersonalSigner::confirm_request); delegate.add_method("personal_confirmRequest", PersonalSigner::confirm_request);
delegate.add_method("personal_rejectRequest", PersonalSigner::reject_request); delegate.add_method("personal_rejectRequest", PersonalSigner::reject_request);
delegate.add_method("personal_generateAuthorizationToken", PersonalSigner::generate_token); delegate.add_method("personal_generateAuthorizationToken", PersonalSigner::generate_token);
delegate delegate
} }
} }