Proper default accounts RPCs (#4580)

* Default accounts setting - account provider

* RPC support for default accounts

* Updating JS code

* Rename whitelist to addresses
This commit is contained in:
Tomasz Drwięga
2017-02-20 16:33:12 +01:00
committed by Gav Wood
parent 1949d44d0c
commit 72998d3ce3
22 changed files with 511 additions and 161 deletions

View File

@@ -221,7 +221,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> EthClient<C, SN, S, M, EM> where
let store = take_weak!(self.accounts);
store
.note_dapp_used(dapp.clone())
.and_then(|_| store.dapps_addresses(dapp))
.and_then(|_| store.dapp_addresses(dapp))
.map_err(|e| errors::internal("Could not fetch accounts.", e))
}
}
@@ -308,10 +308,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
let author = move || {
let mut miner = take_weak!(self.miner).author();
if miner == 0.into() {
let accounts = self.dapp_accounts(dapp.into())?;
if let Some(address) = accounts.get(0) {
miner = *address;
}
miner = self.dapp_accounts(dapp.into())?.get(0).cloned().unwrap_or_default();
}
Ok(RpcH160::from(miner))

View File

@@ -187,7 +187,7 @@ impl Eth for EthClient {
let accounts = self.accounts
.note_dapp_used(dapp.clone())
.and_then(|_| self.accounts.dapps_addresses(dapp))
.and_then(|_| self.accounts.dapp_addresses(dapp))
.map_err(|e| errors::internal("Could not fetch accounts.", e))
.map(|accs| accs.into_iter().map(Into::<RpcH160>::into).collect());

View File

@@ -18,7 +18,7 @@
use std::sync::{Arc, Weak};
use std::str::FromStr;
use std::collections::{BTreeMap, HashSet};
use futures::{self, Future, BoxFuture};
use futures::{future, Future, BoxFuture};
use util::{RotatingLogger, Address};
use util::misc::version_data;
@@ -118,7 +118,7 @@ impl<C, M, S: ?Sized, U> Parity for ParityClient<C, M, S, U> where
let store = take_weak!(self.accounts);
let dapp_accounts = store
.note_dapp_used(dapp.clone().into())
.and_then(|_| store.dapps_addresses(dapp.into()))
.and_then(|_| store.dapp_addresses(dapp.into()))
.map_err(|e| errors::internal("Could not fetch accounts.", e))?
.into_iter().collect::<HashSet<_>>();
@@ -146,16 +146,13 @@ impl<C, M, S: ?Sized, U> Parity for ParityClient<C, M, S, U> where
fn default_account(&self, meta: Self::Metadata) -> BoxFuture<H160, Error> {
let dapp_id = meta.dapp_id();
let default_account = move || {
Ok(take_weak!(self.accounts)
.dapps_addresses(dapp_id.into())
future::ok(
take_weakf!(self.accounts)
.dapp_default_address(dapp_id.into())
.map(Into::into)
.ok()
.and_then(|accounts| accounts.get(0).cloned())
.map(|acc| acc.into())
.unwrap_or_default())
};
futures::done(default_account()).boxed()
.unwrap_or_default()
).boxed()
}
fn transactions_limit(&self) -> Result<usize, Error> {

View File

@@ -142,41 +142,69 @@ impl ParityAccounts for ParityAccountsClient {
Ok(true)
}
fn set_account_visibility(&self, _address: RpcH160, _dapp: RpcH256, _visible: bool) -> Result<bool, Error> {
Ok(false)
}
fn set_dapps_addresses(&self, dapp: DappId, addresses: Vec<RpcH160>) -> Result<bool, Error> {
fn set_dapp_addresses(&self, dapp: DappId, addresses: Option<Vec<RpcH160>>) -> Result<bool, Error> {
let store = take_weak!(self.accounts);
store.set_dapps_addresses(dapp.into(), into_vec(addresses))
store.set_dapp_addresses(dapp.into(), addresses.map(into_vec))
.map_err(|e| errors::account("Couldn't set dapp addresses.", e))
.map(|_| true)
}
fn dapp_addresses(&self, dapp: DappId) -> Result<Vec<RpcH160>, Error> {
let store = take_weak!(self.accounts);
store.dapp_addresses(dapp.into())
.map_err(|e| errors::account("Couldn't get dapp addresses.", e))
.map(into_vec)
}
fn set_dapp_default_address(&self, dapp: DappId, address: RpcH160) -> Result<bool, Error> {
let store = take_weak!(self.accounts);
store.set_dapp_default_address(dapp.into(), address.into())
.map_err(|e| errors::account("Couldn't set dapp default address.", e))
.map(|_| true)
}
fn dapp_default_address(&self, dapp: DappId) -> Result<RpcH160, Error> {
let store = take_weak!(self.accounts);
store.dapp_default_address(dapp.into())
.map_err(|e| errors::account("Couldn't get dapp default address.", e))
.map(Into::into)
}
fn set_new_dapps_addresses(&self, addresses: Option<Vec<RpcH160>>) -> Result<bool, Error> {
let store = take_weak!(self.accounts);
store
.set_new_dapps_addresses(addresses.map(into_vec))
.map_err(|e| errors::account("Couldn't set dapps addresses.", e))
.map(|_| true)
}
fn dapps_addresses(&self, dapp: DappId) -> Result<Vec<RpcH160>, Error> {
fn new_dapps_addresses(&self) -> Result<Option<Vec<RpcH160>>, Error> {
let store = take_weak!(self.accounts);
store.dapps_addresses(dapp.into())
store.new_dapps_addresses()
.map_err(|e| errors::account("Couldn't get dapps addresses.", e))
.map(into_vec)
.map(|accounts| accounts.map(into_vec))
}
fn set_new_dapps_whitelist(&self, whitelist: Option<Vec<RpcH160>>) -> Result<bool, Error> {
fn set_new_dapps_default_address(&self, address: RpcH160) -> Result<bool, Error> {
let store = take_weak!(self.accounts);
store
.set_new_dapps_whitelist(whitelist.map(into_vec))
.map_err(|e| errors::account("Couldn't set dapps whitelist.", e))
store.set_new_dapps_default_address(address.into())
.map_err(|e| errors::account("Couldn't set new dapps default address.", e))
.map(|_| true)
}
fn new_dapps_whitelist(&self) -> Result<Option<Vec<RpcH160>>, Error> {
fn new_dapps_default_address(&self) -> Result<RpcH160, Error> {
let store = take_weak!(self.accounts);
store.new_dapps_whitelist()
.map_err(|e| errors::account("Couldn't get dapps whitelist.", e))
.map(|accounts| accounts.map(into_vec))
store.new_dapps_default_address()
.map_err(|e| errors::account("Couldn't get new dapps default address.", e))
.map(Into::into)
}
fn recent_dapps(&self) -> Result<BTreeMap<DappId, u64>, Error> {

View File

@@ -101,7 +101,7 @@ impl<D: Dispatcher + 'static> Personal for PersonalClient<D> {
let default = match request.from.as_ref() {
Some(account) => Ok(account.clone().into()),
None => accounts
.default_address(meta.dapp_id().into())
.dapp_default_address(meta.dapp_id().into())
.map_err(|e| errors::account("Cannot find default account.", e)),
};

View File

@@ -86,7 +86,7 @@ impl<D: Dispatcher + 'static> SigningQueueClient<D> {
let accounts = take_weakf!(self.accounts);
let default_account = match default_account {
DefaultAccount::Provided(acc) => acc,
DefaultAccount::ForDapp(dapp) => accounts.default_address(dapp).ok().unwrap_or_default(),
DefaultAccount::ForDapp(dapp) => accounts.dapp_default_address(dapp).ok().unwrap_or_default(),
};
let dispatcher = self.dispatcher.clone();

View File

@@ -55,7 +55,7 @@ impl<D: Dispatcher + 'static> SigningUnsafeClient<D> {
let accounts = take_weakf!(self.accounts);
let default = match account {
DefaultAccount::Provided(acc) => acc,
DefaultAccount::ForDapp(dapp) => accounts.default_address(dapp).ok().unwrap_or_default(),
DefaultAccount::ForDapp(dapp) => accounts.dapp_default_address(dapp).ok().unwrap_or_default(),
};
let dis = self.dispatcher.clone();

View File

@@ -368,7 +368,7 @@ fn rpc_eth_gas_price() {
fn rpc_eth_accounts() {
let tester = EthTester::default();
let address = tester.accounts_provider.new_account("").unwrap();
tester.accounts_provider.set_new_dapps_whitelist(None).unwrap();
tester.accounts_provider.set_new_dapps_addresses(None).unwrap();
tester.accounts_provider.set_address_name(1.into(), "1".into());
tester.accounts_provider.set_address_name(10.into(), "10".into());
@@ -377,14 +377,14 @@ fn rpc_eth_accounts() {
let response = r#"{"jsonrpc":"2.0","result":[""#.to_owned() + &format!("0x{:?}", address) + r#""],"id":1}"#;
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
tester.accounts_provider.set_new_dapps_whitelist(Some(vec![1.into()])).unwrap();
tester.accounts_provider.set_new_dapps_addresses(Some(vec![1.into()])).unwrap();
// even with some account it should return empty list (no dapp detected)
let request = r#"{"jsonrpc": "2.0", "method": "eth_accounts", "params": [], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":["0x0000000000000000000000000000000000000001"],"id":1}"#;
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
// when we add visible address it should return that.
tester.accounts_provider.set_dapps_addresses("app1".into(), vec![10.into()]).unwrap();
tester.accounts_provider.set_dapp_addresses("app1".into(), Some(vec![10.into()])).unwrap();
let request = r#"{"jsonrpc": "2.0", "method": "eth_accounts", "params": [], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":["0x000000000000000000000000000000000000000a"],"id":1}"#;
let mut meta = Metadata::default();

View File

@@ -110,17 +110,19 @@ fn rpc_parity_accounts_info() {
assert_eq!(accounts.len(), 1);
let address = accounts[0];
deps.accounts.set_account_name(address.clone(), "Test".to_owned()).unwrap();
deps.accounts.set_account_meta(address.clone(), "{foo: 69}".to_owned()).unwrap();
deps.accounts.set_address_name(1.into(), "XX".into());
deps.accounts.set_account_name(address.clone(), "Test".into()).unwrap();
deps.accounts.set_account_meta(address.clone(), "{foo: 69}".into()).unwrap();
let request = r#"{"jsonrpc": "2.0", "method": "parity_accountsInfo", "params": [], "id": 1}"#;
let response = format!("{{\"jsonrpc\":\"2.0\",\"result\":{{\"0x{}\":{{\"name\":\"Test\"}}}},\"id\":1}}", address.hex());
assert_eq!(io.handle_request_sync(request), Some(response));
// Change the whitelist
deps.accounts.set_new_dapps_whitelist(Some(vec![1.into()])).unwrap();
let address = Address::from(1);
deps.accounts.set_new_dapps_addresses(Some(vec![address.clone()])).unwrap();
let request = r#"{"jsonrpc": "2.0", "method": "parity_accountsInfo", "params": [], "id": 1}"#;
let response = format!("{{\"jsonrpc\":\"2.0\",\"result\":{{}},\"id\":1}}");
let response = format!("{{\"jsonrpc\":\"2.0\",\"result\":{{\"0x{}\":{{\"name\":\"XX\"}}}},\"id\":1}}", address.hex());
assert_eq!(io.handle_request_sync(request), Some(response));
}

View File

@@ -125,48 +125,87 @@ fn rpc_parity_set_and_get_dapps_accounts() {
// given
let tester = setup();
tester.accounts.set_address_name(10.into(), "10".into());
assert_eq!(tester.accounts.dapps_addresses("app1".into()).unwrap(), vec![]);
assert_eq!(tester.accounts.dapp_addresses("app1".into()).unwrap(), vec![]);
// when
let request = r#"{"jsonrpc": "2.0", "method": "parity_setDappsAddresses","params":["app1",["0x000000000000000000000000000000000000000a","0x0000000000000000000000000000000000000001"]], "id": 1}"#;
let request = r#"{"jsonrpc": "2.0", "method": "parity_setDappAddresses","params":["app1",["0x000000000000000000000000000000000000000a","0x0000000000000000000000000000000000000001"]], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
// then
assert_eq!(tester.accounts.dapps_addresses("app1".into()).unwrap(), vec![10.into()]);
let request = r#"{"jsonrpc": "2.0", "method": "parity_getDappsAddresses","params":["app1"], "id": 1}"#;
assert_eq!(tester.accounts.dapp_addresses("app1".into()).unwrap(), vec![10.into()]);
let request = r#"{"jsonrpc": "2.0", "method": "parity_getDappAddresses","params":["app1"], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":["0x000000000000000000000000000000000000000a"],"id":1}"#;
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
}
#[test]
fn rpc_parity_set_and_get_dapp_default_address() {
// given
let tester = setup();
tester.accounts.set_address_name(10.into(), "10".into());
assert_eq!(tester.accounts.dapp_addresses("app1".into()).unwrap(), vec![]);
// when
let request = r#"{"jsonrpc": "2.0", "method": "parity_setDappDefaultAddress","params":["app1", "0x000000000000000000000000000000000000000a"], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
// then
assert_eq!(tester.accounts.dapp_addresses("app1".into()).unwrap(), vec![10.into()]);
let request = r#"{"jsonrpc": "2.0", "method": "parity_getDappDefaultAddress","params":["app1"], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":"0x000000000000000000000000000000000000000a","id":1}"#;
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
}
#[test]
fn rpc_parity_set_and_get_new_dapps_whitelist() {
// given
let tester = setup();
// when set to whitelist
let request = r#"{"jsonrpc": "2.0", "method": "parity_setNewDappsWhitelist","params":[["0x000000000000000000000000000000000000000a"]], "id": 1}"#;
let request = r#"{"jsonrpc": "2.0", "method": "parity_setNewDappsAddresses","params":[["0x000000000000000000000000000000000000000a"]], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
// then
assert_eq!(tester.accounts.new_dapps_whitelist().unwrap(), Some(vec![10.into()]));
let request = r#"{"jsonrpc": "2.0", "method": "parity_getNewDappsWhitelist","params":[], "id": 1}"#;
assert_eq!(tester.accounts.new_dapps_addresses().unwrap(), Some(vec![10.into()]));
let request = r#"{"jsonrpc": "2.0", "method": "parity_getNewDappsAddresses","params":[], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":["0x000000000000000000000000000000000000000a"],"id":1}"#;
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
// when set to empty
let request = r#"{"jsonrpc": "2.0", "method": "parity_setNewDappsWhitelist","params":[null], "id": 1}"#;
let request = r#"{"jsonrpc": "2.0", "method": "parity_setNewDappsAddresses","params":[null], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
// then
assert_eq!(tester.accounts.new_dapps_whitelist().unwrap(), None);
let request = r#"{"jsonrpc": "2.0", "method": "parity_getNewDappsWhitelist","params":[], "id": 1}"#;
assert_eq!(tester.accounts.new_dapps_addresses().unwrap(), None);
let request = r#"{"jsonrpc": "2.0", "method": "parity_getNewDappsAddresses","params":[], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":null,"id":1}"#;
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
}
#[test]
fn rpc_parity_set_and_get_new_dapps_default_address() {
// given
let tester = setup();
tester.accounts.set_address_name(10.into(), "10".into());
assert_eq!(tester.accounts.new_dapps_default_address().unwrap(), 0.into());
// when
let request = r#"{"jsonrpc": "2.0", "method": "parity_setNewDappsDefaultAddress","params":["0x000000000000000000000000000000000000000a"], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
// then
assert_eq!(tester.accounts.new_dapps_default_address().unwrap(), 10.into());
let request = r#"{"jsonrpc": "2.0", "method": "parity_getNewDappsDefaultAddress","params":[], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":"0x000000000000000000000000000000000000000a","id":1}"#;
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
}
#[test]
fn rpc_parity_recent_dapps() {
// given

View File

@@ -70,28 +70,51 @@ build_rpc_trait! {
#[rpc(name = "parity_setAccountMeta")]
fn set_account_meta(&self, H160, String) -> Result<bool, Error>;
/// Sets account visibility.
/// @unimplemented
#[rpc(name = "parity_setAccountVisiblity")]
fn set_account_visibility(&self, H160, H256, bool) -> Result<bool, Error>;
/// Sets accounts exposed for particular dapp.
#[rpc(name = "parity_setDappsAddresses")]
fn set_dapps_addresses(&self, DappId, Vec<H160>) -> Result<bool, Error>;
/// Sets addresses exposed for particular dapp.
/// Setting a non-empty list will also override default account.
/// Setting `None` will resets visible account to what's visible for new dapps
/// (does not affect default account though)
#[rpc(name = "parity_setDappAddresses")]
fn set_dapp_addresses(&self, DappId, Option<Vec<H160>>) -> Result<bool, Error>;
/// Gets accounts exposed for particular dapp.
#[rpc(name = "parity_getDappsAddresses")]
fn dapps_addresses(&self, DappId) -> Result<Vec<H160>, Error>;
#[rpc(name = "parity_getDappAddresses")]
fn dapp_addresses(&self, DappId) -> Result<Vec<H160>, Error>;
/// Changes dapp default address.
/// Does not affect other accounts exposed for this dapp, but
/// default account will always be retured as the first one.
#[rpc(name = "parity_setDappDefaultAddress")]
fn set_dapp_default_address(&self, DappId, H160) -> Result<bool, Error>;
/// Returns current dapp default address.
/// If not set explicite for the dapp will return global default.
#[rpc(name = "parity_getDappDefaultAddress")]
fn dapp_default_address(&self, DappId) -> Result<H160, Error>;
/// Sets accounts exposed for new dapps.
/// `None` means that all accounts will be exposed.
#[rpc(name = "parity_setNewDappsWhitelist")]
fn set_new_dapps_whitelist(&self, Option<Vec<H160>>) -> Result<bool, Error>;
/// Setting a non-empty list will also override default account.
/// Setting `None` exposes all internal-managed accounts.
/// (does not affect default account though)
#[rpc(name = "parity_setNewDappsAddresses")]
fn set_new_dapps_addresses(&self, Option<Vec<H160>>) -> Result<bool, Error>;
/// Gets accounts exposed for new dapps.
/// `None` means that all accounts will be exposed.
#[rpc(name = "parity_getNewDappsWhitelist")]
fn new_dapps_whitelist(&self) -> Result<Option<Vec<H160>>, Error>;
/// `None` means that all accounts are exposes.
#[rpc(name = "parity_getNewDappsAddresses")]
fn new_dapps_addresses(&self) -> Result<Option<Vec<H160>>, Error>;
/// Changes default address for new dapps (global default address)
/// Does not affect other accounts exposed for new dapps, but
/// default account will always be retured as the first one.
#[rpc(name = "parity_setNewDappsDefaultAddress")]
fn set_new_dapps_default_address(&self, H160) -> Result<bool, Error>;
/// Returns current default address for new dapps (global default address)
/// In case it's not set explicite will return first available account.
/// If no accounts are available will return `0x0`
#[rpc(name = "parity_getNewDappsDefaultAddress")]
fn new_dapps_default_address(&self) -> Result<H160, Error>;
/// Returns identified dapps that recently used RPC
/// Includes last usage timestamp.