RPC Middleware & Get/Set dapp-specific accounts

This commit is contained in:
Tomasz Drwięga
2016-11-22 11:56:27 +01:00
parent 21b2b4ac27
commit cd6f565f69
34 changed files with 655 additions and 224 deletions

View File

@@ -12,8 +12,9 @@ build = "build.rs"
log = "0.3"
serde = "0.8"
serde_json = "0.8"
jsonrpc-core = "3.0"
jsonrpc-http-server = { git = "https://github.com/ethcore/jsonrpc-http-server.git" }
jsonrpc-core = { git = "https://github.com/ethcore/jsonrpc.git" }
jsonrpc-http-server = { git = "https://github.com/ethcore/jsonrpc.git" }
jsonrpc-ipc-server = { git = "https://github.com/ethcore/jsonrpc.git" }
ethcore-io = { path = "../util/io" }
ethcore-util = { path = "../util" }
ethcore = { path = "../ethcore" }
@@ -30,7 +31,6 @@ rustc-serialize = "0.3"
transient-hashmap = "0.1"
serde_macros = { version = "0.8.0", optional = true }
clippy = { version = "0.0.96", optional = true}
json-ipc-server = { git = "https://github.com/ethcore/json-ipc-server.git" }
ethcore-ipc = { path = "../ipc/rpc" }
time = "0.1"

View File

@@ -32,7 +32,7 @@ extern crate ethcrypto as crypto;
extern crate ethstore;
extern crate ethsync;
extern crate transient_hashmap;
extern crate json_ipc_server as ipc;
extern crate jsonrpc_ipc_server as ipc;
extern crate ethcore_ipc;
extern crate time;
extern crate rlp;
@@ -51,8 +51,9 @@ extern crate ethcore_devtools as devtools;
use std::sync::Arc;
use std::net::SocketAddr;
use io::PanicHandler;
use self::jsonrpc_core::{IoHandler, IoDelegate};
use jsonrpc_core::{IoHandler, IoDelegate};
pub use ipc::{Server as IpcServer, Error as IpcServerError};
pub use jsonrpc_http_server::{ServerBuilder, Server, RpcServerError};
pub mod v1;
pub use v1::{SigningQueue, SignerService, ConfirmationsQueue, NetworkSettings};
@@ -66,7 +67,7 @@ pub trait Extendable {
/// Http server.
pub struct RpcServer {
handler: Arc<jsonrpc_core::io::IoHandler>,
handler: Arc<IoHandler>,
}
impl Extendable for RpcServer {

View File

@@ -20,7 +20,6 @@ extern crate ethash;
use std::io::{Write};
use std::process::{Command, Stdio};
use std::collections::BTreeSet;
use std::thread;
use std::time::{Instant, Duration};
use std::sync::{Arc, Weak};
@@ -46,7 +45,7 @@ use self::ethash::SeedHashCompute;
use v1::traits::Eth;
use v1::types::{
RichBlock, Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo,
Transaction, CallRequest, Index, Filter, Log, Receipt, Work,
Transaction, CallRequest, Index, Filter, Log, Receipt, Work, DappId,
H64 as RpcH64, H256 as RpcH256, H160 as RpcH160, U256 as RpcU256,
};
use v1::helpers::{CallRequest as CRequest, errors, limit_logs};
@@ -335,15 +334,15 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
Ok(RpcU256::from(default_gas_price(&*client, &*miner)))
}
fn accounts(&self) -> Result<Vec<RpcH160>, Error> {
fn accounts(&self, id: Trailing<DappId>) -> Result<Vec<RpcH160>, Error> {
try!(self.active());
let store = take_weak!(self.accounts);
let accounts = try!(store.accounts().map_err(|e| errors::internal("Could not fetch accounts.", e)));
let addresses = try!(store.addresses_info().map_err(|e| errors::internal("Could not fetch accounts.", e)));
let dapp = id.0;
let set: BTreeSet<Address> = accounts.into_iter().chain(addresses.keys().cloned()).collect();
Ok(set.into_iter().map(Into::into).collect())
let store = take_weak!(self.accounts);
let accounts = try!(store.dapps_addresses(dapp.into()).map_err(|e| errors::internal("Could not fetch accounts.", e)));
Ok(accounts.into_iter().map(Into::into).collect())
}
fn block_number(&self) -> Result<RpcU256, Error> {

View File

@@ -25,7 +25,7 @@ use ethcore::client::MiningBlockChainClient;
use jsonrpc_core::{Value, Error, to_value};
use v1::traits::ParityAccounts;
use v1::types::{H160 as RpcH160, H256 as RpcH256};
use v1::types::{H160 as RpcH160, H256 as RpcH256, DappId};
use v1::helpers::errors;
/// Account management (personal) rpc implementation.
@@ -143,6 +143,15 @@ impl<C: 'static> ParityAccounts for ParityAccountsClient<C> where C: MiningBlock
Ok(false)
}
fn set_dapps_addresses(&self, dapp: DappId, addresses: Vec<RpcH160>) -> Result<bool, Error> {
let store = take_weak!(self.accounts);
let addresses = addresses.into_iter().map(Into::into).collect();
store.set_dapps_addresses(dapp.into(), addresses)
.map_err(|e| errors::account("Couldn't set dapps addresses.", e))
.map(|_| true)
}
fn import_geth_accounts(&self, addresses: Vec<RpcH160>) -> Result<Vec<RpcH160>, Error> {
let store = take_weak!(self.accounts);

View File

@@ -30,7 +30,7 @@ use devtools::RandomTempPath;
use util::Hashable;
use io::IoChannel;
use util::{U256, H256, Uint, Address};
use jsonrpc_core::IoHandler;
use jsonrpc_core::{IoHandler, GenericIoHandler};
use ethjson::blockchain::BlockChain;
use v1::impls::{EthClient, SigningUnsafeClient};

View File

@@ -31,7 +31,7 @@ use ethcore::transaction::{Transaction, Action};
use ethcore::miner::{ExternalMiner, MinerService};
use ethsync::SyncState;
use jsonrpc_core::IoHandler;
use jsonrpc_core::{IoHandler, GenericIoHandler};
use v1::{Eth, EthClient, EthClientOptions, EthFilter, EthFilterClient, EthSigning, SigningUnsafeClient};
use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService, TestSnapshotService};
@@ -357,15 +357,15 @@ fn rpc_eth_accounts() {
let address = tester.accounts_provider.new_account("").unwrap();
let address2 = Address::default();
tester.accounts_provider.set_address_name(address2, "Test Account".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":[""#.to_owned()
+ &format!("0x{:?}", address2)
+ r#"",""#
+ &format!("0x{:?}", address)
+ r#""],"id":1}"#;
let response = r#"{"jsonrpc":"2.0","result":[],"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();
let request = r#"{"jsonrpc": "2.0", "method": "eth_accounts", "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()));
}

View File

@@ -15,7 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::sync::Arc;
use jsonrpc_core::IoHandler;
use jsonrpc_core::{IoHandler, GenericIoHandler};
use v1::{Net, NetClient};
use v1::tests::helpers::{Config, TestSyncProvider};

View File

@@ -23,7 +23,7 @@ use ethcore::client::{TestBlockChainClient};
use ethcore::miner::LocalTransactionStatus;
use ethstore::ethkey::{Generator, Random};
use jsonrpc_core::IoHandler;
use jsonrpc_core::{IoHandler, GenericIoHandler};
use v1::{Parity, ParityClient};
use v1::helpers::{SignerService, NetworkSettings};
use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService};

View File

@@ -19,7 +19,7 @@ use std::sync::Arc;
use ethcore::account_provider::AccountProvider;
use ethcore::client::TestBlockChainClient;
use jsonrpc_core::IoHandler;
use jsonrpc_core::{IoHandler, GenericIoHandler};
use v1::{ParityAccounts, ParityAccountsClient};
struct ParityAccountsTester {
@@ -116,3 +116,18 @@ fn should_be_able_to_set_meta() {
assert_eq!(res, Some(response));
}
#[test]
fn rpc_parity_set_dapps_accounts() {
// given
let tester = setup();
assert_eq!(tester.accounts.dapps_addresses("app1".into()).unwrap(), vec![]);
// when
let request = r#"{"jsonrpc": "2.0", "method": "parity_setDappsAddresses","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.dapps_addresses("app1".into()).unwrap(), vec![10.into()]);
}

View File

@@ -23,7 +23,7 @@ use ethcore::miner::MinerService;
use ethcore::client::TestBlockChainClient;
use ethsync::ManageNetwork;
use jsonrpc_core::IoHandler;
use jsonrpc_core::{IoHandler, GenericIoHandler};
use v1::{ParitySet, ParitySetClient};
use v1::tests::helpers::{TestMinerService, TestFetch};
use super::manage_network::TestManageNetwork;

View File

@@ -16,7 +16,7 @@
use std::sync::Arc;
use std::str::FromStr;
use jsonrpc_core::IoHandler;
use jsonrpc_core::{IoHandler, GenericIoHandler};
use util::{U256, Uint, Address};
use ethcore::account_provider::AccountProvider;
use v1::{PersonalClient, Personal};

View File

@@ -15,7 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::collections::BTreeMap;
use jsonrpc_core::IoHandler;
use jsonrpc_core::{IoHandler, GenericIoHandler};
use v1::{Rpc, RpcClient};

View File

@@ -23,7 +23,7 @@ use ethcore::client::TestBlockChainClient;
use ethcore::transaction::{Transaction, Action};
use rlp::encode;
use jsonrpc_core::IoHandler;
use jsonrpc_core::{IoHandler, GenericIoHandler};
use v1::{SignerClient, Signer};
use v1::tests::helpers::TestMinerService;
use v1::helpers::{SigningQueue, SignerService, FilledTransactionRequest, ConfirmationPayload};

View File

@@ -15,10 +15,10 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::str::FromStr;
use std::sync::Arc;
use std::sync::{mpsc, Arc};
use rlp;
use jsonrpc_core::{IoHandler, Success};
use jsonrpc_core::{IoHandler, Success, GenericIoHandler};
use v1::impls::SigningQueueClient;
use v1::traits::{EthSigning, ParitySigning, Parity};
use v1::helpers::{SignerService, SigningQueue};
@@ -87,13 +87,16 @@ fn should_add_sign_to_queue() {
let response = r#"{"jsonrpc":"2.0","result":"0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","id":1}"#;
// then
let async_result = tester.io.handle_request(&request).unwrap();
let (tx, rx) = mpsc::channel();
tester.io.handle_request(&request, move |response| {
tx.send(response).unwrap();
});
assert_eq!(tester.signer.requests().len(), 1);
// respond
tester.signer.request_confirmed(1.into(), Ok(ConfirmationResponse::Signature(0.into())));
assert!(async_result.on_result(move |res| {
assert_eq!(res, response.to_owned());
}));
let res = rx.try_recv().unwrap();
assert_eq!(res, Some(response.to_owned()));
}
#[test]
@@ -227,13 +230,16 @@ fn should_add_transaction_to_queue() {
let response = r#"{"jsonrpc":"2.0","result":"0x0000000000000000000000000000000000000000000000000000000000000000","id":1}"#;
// then
let async_result = tester.io.handle_request(&request).unwrap();
let (tx, rx) = mpsc::channel();
tester.io.handle_request(&request, move |response| {
tx.send(response).unwrap();
});
assert_eq!(tester.signer.requests().len(), 1);
// respond
tester.signer.request_confirmed(1.into(), Ok(ConfirmationResponse::SendTransaction(0.into())));
assert!(async_result.on_result(move |res| {
assert_eq!(res, response.to_owned());
}));
let res = rx.try_recv().unwrap();
assert_eq!(res, Some(response.to_owned()));
}
#[test]
@@ -289,14 +295,17 @@ fn should_add_sign_transaction_to_the_queue() {
r#"}},"id":1}"#;
// then
let (tx, rx) = mpsc::channel();
tester.miner.last_nonces.write().insert(address.clone(), U256::zero());
let async_result = tester.io.handle_request(&request).unwrap();
tester.io.handle_request(&request, move |response| {
tx.send(response).unwrap();
});
assert_eq!(tester.signer.requests().len(), 1);
// respond
tester.signer.request_confirmed(1.into(), Ok(ConfirmationResponse::SignTransaction(t.into())));
assert!(async_result.on_result(move |res| {
assert_eq!(res, response.to_owned());
}));
let res = rx.try_recv().unwrap();
assert_eq!(res, Some(response.to_owned()));
}
#[test]
@@ -387,11 +396,14 @@ fn should_add_decryption_to_the_queue() {
let response = r#"{"jsonrpc":"2.0","result":"0x0102","id":1}"#;
// then
let async_result = tester.io.handle_request(&request).unwrap();
let (tx, rx) = mpsc::channel();
tester.io.handle_request(&request, move |response| {
tx.send(response).unwrap();
});
assert_eq!(tester.signer.requests().len(), 1);
// respond
tester.signer.request_confirmed(1.into(), Ok(ConfirmationResponse::Decrypt(vec![0x1, 0x2].into())));
assert!(async_result.on_result(move |res| {
assert_eq!(res, response.to_owned());
}));
let res = rx.try_recv().unwrap();
assert_eq!(res, Some(response.to_owned()));
}

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use jsonrpc_core::IoHandler;
use jsonrpc_core::{IoHandler, GenericIoHandler};
use util::version;
use v1::{Web3, Web3Client};

View File

@@ -17,7 +17,7 @@
//! Eth rpc interface.
use jsonrpc_core::Error;
use v1::types::{RichBlock, BlockNumber, Bytes, CallRequest, Filter, FilterChanges, Index};
use v1::types::{RichBlock, BlockNumber, Bytes, CallRequest, Filter, FilterChanges, Index, DappId};
use v1::types::{Log, Receipt, SyncStatus, Transaction, Work};
use v1::types::{H64, H160, H256, U256};
@@ -52,7 +52,7 @@ build_rpc_trait! {
/// Returns accounts list.
#[rpc(name = "eth_accounts")]
fn accounts(&self) -> Result<Vec<H160>, Error>;
fn accounts(&self, Trailing<DappId>) -> Result<Vec<H160>, Error>;
/// Returns highest block number.
#[rpc(name = "eth_blockNumber")]

View File

@@ -19,7 +19,7 @@ use std::collections::BTreeMap;
use jsonrpc_core::{Value, Error};
use v1::helpers::auto_args::Wrap;
use v1::types::{H160, H256};
use v1::types::{H160, H256, DappId};
build_rpc_trait! {
/// Personal Parity rpc interface.
@@ -61,10 +61,14 @@ build_rpc_trait! {
#[rpc(name = "parity_setAccountMeta")]
fn set_account_meta(&self, H160, String) -> Result<bool, Error>;
/// Returns accounts information.
/// Sets account visibility
#[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>;
/// Imports a number of Geth accounts, with the list provided as the argument.
#[rpc(name = "parity_importGethAccounts")]
fn import_geth_accounts(&self, Vec<H160>) -> Result<Vec<H160>, Error>;

View File

@@ -0,0 +1,60 @@
// 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/>.
//! Dapp Id type
/// Dapplication Internal Id
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct DappId(pub String);
impl Into<String> for DappId {
fn into(self) -> String {
self.0
}
}
#[cfg(test)]
mod tests {
use serde_json;
use super::DappId;
#[test]
fn should_serialize_dapp_id() {
// given
let id = DappId("testapp".into());
// when
let res = serde_json::to_string(&id).unwrap();
// then
assert_eq!(res, r#""testapp""#);
}
#[test]
fn should_deserialize_dapp_id() {
// given
let id = r#""testapp""#;
// when
let res: DappId = serde_json::from_str(id).unwrap();
// then
assert_eq!(res, DappId("testapp".into()));
}
}

View File

@@ -19,6 +19,7 @@ mod block;
mod block_number;
mod call_request;
mod confirmations;
mod dapp_id;
mod filter;
mod hash;
mod index;
@@ -39,6 +40,7 @@ pub use self::block::{RichBlock, Block, BlockTransactions};
pub use self::block_number::BlockNumber;
pub use self::call_request::CallRequest;
pub use self::confirmations::{ConfirmationPayload, ConfirmationRequest, ConfirmationResponse, TransactionModification, SignRequest, DecryptRequest, Either};
pub use self::dapp_id::DappId;
pub use self::filter::{Filter, FilterChanges};
pub use self::hash::{H64, H160, H256, H512, H520, H2048};
pub use self::index::Index;