use generic dispatcher everywhere, squash errors

This commit is contained in:
Robert Habermeier 2017-02-08 16:55:06 +01:00
parent e73ea80954
commit 5223e25aa6
7 changed files with 79 additions and 58 deletions

View File

@ -94,12 +94,13 @@ impl<C: MiningBlockChainClient, M: MinerService> Dispatcher for FullDispatcher<C
{
let inner = move || {
let (client, miner) = (take_weak!(self.client), take_weak!(self.miner));
let request = request;
Ok(FilledTransactionRequest {
from: request.from.unwrap_or(default_sender),
used_default_from: request.from.is_none(),
to: request.to,
nonce: request.nonce,
gas_price: request.gas_price.unwrap_or_else(|| default_gas_price(client, miner)),
gas_price: request.gas_price.unwrap_or_else(|| default_gas_price(&*client, &*miner)),
gas: request.gas.unwrap_or_else(|| miner.sensible_gas_limit()),
value: request.value.unwrap_or_else(|| 0.into()),
data: request.data.unwrap_or_else(Vec::new),
@ -147,7 +148,7 @@ impl<C: MiningBlockChainClient, M: MinerService> Dispatcher for FullDispatcher<C
fn dispatch_transaction(&self, signed_transaction: PendingTransaction) -> Result<H256, Error> {
let hash = signed_transaction.transaction.hash();
take_weak!(self.miner).import_own_transaction(take_weak!(self.client), signed_transaction)
take_weak!(self.miner).import_own_transaction(&*take_weak!(self.client), signed_transaction)
.map_err(errors::from_transaction_error)
.map(|_| hash)
}
@ -223,7 +224,7 @@ impl<T: Debug> From<(T, Option<AccountToken>)> for WithToken<T> {
}
}
pub fn execute<D: Dispatcher>(
pub fn execute<D: Dispatcher + 'static>(
dispatcher: D,
accounts: &AccountProvider,
payload: ConfirmationPayload,
@ -231,7 +232,7 @@ pub fn execute<D: Dispatcher>(
) -> BoxFuture<WithToken<ConfirmationResponse>, Error> {
match payload {
ConfirmationPayload::SendTransaction(request) => {
let condition = request.condition.clone();
let condition = request.condition.clone().map(Into::into);
dispatcher.sign(accounts, request, pass)
.map(move |v| v.map(move |tx| PendingTransaction::new(tx, condition)))
.map(WithToken::into_tuple)

View File

@ -46,7 +46,7 @@ use jsonrpc_core::Error;
use jsonrpc_macros::Trailing;
use v1::helpers::{CallRequest as CRequest, errors, limit_logs};
use v1::helpers::dispatch::{dispatch_transaction, default_gas_price};
use v1::helpers::dispatch::{Dispatcher, FullDispatcher, default_gas_price};
use v1::helpers::block_import::is_major_importing;
use v1::traits::Eth;
use v1::types::{
@ -634,7 +634,8 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
.map_err(errors::from_rlp_error)
.and_then(|tx| SignedTransaction::new(tx).map_err(errors::from_transaction_error))
.and_then(|signed_transaction| {
dispatch_transaction(&*take_weak!(self.client), &*take_weak!(self.miner), PendingTransaction::new(signed_transaction, None))
FullDispatcher::new(self.client.clone(), self.miner.clone())
.dispatch_transaction(signed_transaction.into())
})
.map(Into::into)
}

View File

@ -37,7 +37,6 @@ use futures::{future, Future, BoxFuture};
use futures::sync::oneshot;
use v1::helpers::{CallRequest as CRequest, errors, limit_logs};
use v1::helpers::dispatch::{dispatch_transaction, default_gas_price};
use v1::helpers::block_import::is_major_importing;
use v1::traits::Eth;
use v1::types::{

View File

@ -23,46 +23,52 @@ use ethcore::account_provider::AccountProvider;
use ethcore::client::MiningBlockChainClient;
use ethcore::transaction::{SignedTransaction, PendingTransaction};
use ethcore::miner::MinerService;
use futures::{self, future, BoxFuture, Future, IntoFuture};
use jsonrpc_core::Error;
use v1::helpers::{errors, SignerService, SigningQueue, ConfirmationPayload};
use v1::helpers::dispatch::{self, dispatch_transaction, WithToken};
use v1::helpers::dispatch::{self, Dispatcher, WithToken};
use v1::traits::Signer;
use v1::types::{TransactionModification, ConfirmationRequest, ConfirmationResponse, ConfirmationResponseWithToken, U256, Bytes};
/// Transactions confirmation (personal) rpc implementation.
pub struct SignerClient<C, M> where C: MiningBlockChainClient, M: MinerService {
pub struct SignerClient<D: Dispatcher> {
signer: Weak<SignerService>,
accounts: Weak<AccountProvider>,
client: Weak<C>,
miner: Weak<M>,
dispatcher: D
}
impl<C: 'static, M: 'static> SignerClient<C, M> where C: MiningBlockChainClient, M: MinerService {
impl<D: Dispatcher + 'static> SignerClient<D> {
/// Create new instance of signer client.
pub fn new(
store: &Arc<AccountProvider>,
client: &Arc<C>,
miner: &Arc<M>,
dispatcher: D,
signer: &Arc<SignerService>,
) -> Self {
SignerClient {
signer: Arc::downgrade(signer),
accounts: Arc::downgrade(store),
client: Arc::downgrade(client),
miner: Arc::downgrade(miner),
dispatcher: dispatcher,
}
}
fn confirm_internal<F>(&self, id: U256, modification: TransactionModification, f: F) -> Result<WithToken<ConfirmationResponse>, Error> where
F: FnOnce(&C, &M, &AccountProvider, ConfirmationPayload) -> Result<WithToken<ConfirmationResponse>, Error>,
fn confirm_internal<F, T>(&self, id: U256, modification: TransactionModification, f: F) -> BoxFuture<WithToken<ConfirmationResponse>, Error> where
F: FnOnce(D, &AccountProvider, ConfirmationPayload) -> T,
T: IntoFuture<Item=WithToken<ConfirmationResponse>, Error=Error>,
T::Future: Send + 'static
{
let id = id.into();
let accounts = take_weak!(self.accounts);
let signer = take_weak!(self.signer);
let client = take_weak!(self.client);
let miner = take_weak!(self.miner);
let dispatcher = self.dispatcher.clone();
let setup = || {
Ok((take_weak!(self.accounts), take_weak!(self.signer)))
};
let (accounts, signer) = match setup() {
Ok(x) => x,
Err(e) => return future::err(e).boxed(),
};
signer.peek(&id).map(|confirmation| {
let mut payload = confirmation.payload.clone();
@ -83,17 +89,21 @@ impl<C: 'static, M: 'static> SignerClient<C, M> where C: MiningBlockChainClient,
request.condition = condition.clone().map(Into::into);
}
}
let result = f(&*client, &*miner, &*accounts, payload);
// Execute
if let Ok(ref response) = result {
signer.request_confirmed(id, Ok((*response).clone()));
}
result
}).unwrap_or_else(|| Err(errors::invalid_params("Unknown RequestID", id)))
let fut = f(dispatcher, &*accounts, payload);
fut.into_future().then(move |result| {
// Execute
if let Ok(ref response) = result {
signer.request_confirmed(id, Ok((*response).clone()));
}
result
}).boxed()
})
.unwrap_or_else(|| future::err(errors::invalid_params("Unknown RequestID", id)).boxed())
}
}
impl<C: 'static, M: 'static> Signer for SignerClient<C, M> where C: MiningBlockChainClient, M: MinerService {
impl<D: Dispatcher + 'static> Signer for SignerClient<D> {
fn requests_to_confirm(&self) -> Result<Vec<ConfirmationRequest>, Error> {
let signer = take_weak!(self.signer);
@ -107,29 +117,31 @@ impl<C: 'static, M: 'static> Signer for SignerClient<C, M> where C: MiningBlockC
// TODO [ToDr] TransactionModification is redundant for some calls
// might be better to replace it in future
fn confirm_request(&self, id: U256, modification: TransactionModification, pass: String) -> Result<ConfirmationResponse, Error> {
self.confirm_internal(id, modification, move |client, miner, accounts, payload| {
dispatch::execute(client, miner, accounts, payload, dispatch::SignWith::Password(pass))
}).map(|v| v.into_value())
fn confirm_request(&self, id: U256, modification: TransactionModification, pass: String)
-> BoxFuture<ConfirmationResponse, Error>
{
self.confirm_internal(id, modification, move |dis, accounts, payload| {
dispatch::execute(dis, accounts, payload, dispatch::SignWith::Password(pass))
}).map(|v| v.into_value()).boxed()
}
fn confirm_request_with_token(&self, id: U256, modification: TransactionModification, token: String) -> Result<ConfirmationResponseWithToken, Error> {
self.confirm_internal(id, modification, move |client, miner, accounts, payload| {
dispatch::execute(client, miner, accounts, payload, dispatch::SignWith::Token(token))
fn confirm_request_with_token(&self, id: U256, modification: TransactionModification, token: String)
-> BoxFuture<ConfirmationResponseWithToken, Error>
{
self.confirm_internal(id, modification, move |dis, accounts, payload| {
dispatch::execute(dis, accounts, payload, dispatch::SignWith::Token(token))
}).and_then(|v| match v {
WithToken::No(_) => Err(errors::internal("Unexpected response without token.", "")),
WithToken::Yes(response, token) => Ok(ConfirmationResponseWithToken {
result: response,
token: token,
}),
})
}).boxed()
}
fn confirm_request_raw(&self, id: U256, bytes: Bytes) -> Result<ConfirmationResponse, Error> {
let id = id.into();
let signer = take_weak!(self.signer);
let client = take_weak!(self.client);
let miner = take_weak!(self.miner);
signer.peek(&id).map(|confirmation| {
let result = match confirmation.payload {
@ -150,7 +162,7 @@ impl<C: 'static, M: 'static> Signer for SignerClient<C, M> where C: MiningBlockC
// Dispatch if everything is ok
if sender_matches && data_matches && value_matches && nonce_matches {
let pending_transaction = PendingTransaction::new(signed_transaction, request.condition.map(Into::into));
dispatch_transaction(&*client, &*miner, pending_transaction)
self.dispatcher.dispatch_transaction(pending_transaction)
.map(Into::into)
.map(ConfirmationResponse::SendTransaction)
} else {

View File

@ -72,7 +72,7 @@ fn handle_dispatch<OnResponse>(res: Result<DispatchResult, Error>, on_response:
}
}
impl<D: Dispatcher> SigningQueueClient<D> {
impl<D: Dispatcher + 'static> SigningQueueClient<D> {
/// Creates a new signing queue client given shared signing queue.
pub fn new(signer: &Arc<SignerService>, dispatcher: D, accounts: &Arc<AccountProvider>) -> Self {
SigningQueueClient {
@ -84,30 +84,34 @@ impl<D: Dispatcher> SigningQueueClient<D> {
}
fn dispatch(&self, payload: RpcConfirmationPayload, default_account: DefaultAccount) -> BoxFuture<DispatchResult, Error> {
let setup = || {
let setup = move || {
let accounts = take_weak!(self.accounts);
let default_account = default_account;
let default_account = match default_account {
DefaultAccount::Provided(acc) => acc,
DefaultAccount::ForDapp(dapp) => accounts.default_address(dapp).ok().unwrap_or_default(),
};
(self.dispatcher.clone(), accounts, default_account)
Ok((self.dispatcher.clone(), accounts, default_account))
};
let weak_signer = self.signer.clone();
future::done(setup)
future::done(setup())
.and_then(move |(dispatcher, accounts, default_account)| {
dispatch::from_rpc(payload, default_account, &dispatcher)
.and_then(move |payload| {
let sender = payload.sender();
if accounts.is_unlocked(sender) {
dispatch::execute(dispatcher, &accounts, payload, dispatch::SignWith::Nothing)
.map(|v| v.into_value())
.map(DispatchResult::Value)
.boxed()
} else {
future::lazy(move || take_weak!(weak_signer).add_request(payload))
.map(DispatchResult::Promise)
.map_err(|_| errors::request_rejected_limit())
.boxed()
future::lazy(move ||
take_weak!(weak_signer).add_request(payload)
.map(DispatchResult::Promise)
.map_err(|_| errors::request_rejected_limit())
).boxed()
}
})
})
@ -129,6 +133,7 @@ impl<D: Dispatcher + 'static> ParitySigning for SigningQueueClient<D> {
RpcEither::Either(id.into())
},
})
.boxed()
}
fn post_transaction(&self, meta: Metadata, request: RpcTransactionRequest) -> BoxFuture<RpcEither<RpcU256, RpcConfirmationResponse>, Error> {
@ -142,6 +147,7 @@ impl<D: Dispatcher + 'static> ParitySigning for SigningQueueClient<D> {
RpcEither::Either(id.into())
},
})
.boxed()
}
fn check_request(&self, id: RpcU256) -> Result<Option<RpcConfirmationResponse>, Error> {

View File

@ -44,7 +44,7 @@ pub struct SigningUnsafeClient<D> {
dispatcher: D,
}
impl<D: Dispatcher> SigningUnsafeClient<D> {
impl<D: Dispatcher + 'static> SigningUnsafeClient<D> {
/// Creates new SigningUnsafeClient.
pub fn new(accounts: &Arc<AccountProvider>, dispatcher: D) -> Self {
SigningUnsafeClient {
@ -56,20 +56,21 @@ impl<D: Dispatcher> SigningUnsafeClient<D> {
fn handle(&self, payload: RpcConfirmationPayload, account: DefaultAccount) -> BoxFuture<RpcConfirmationResponse, Error> {
let setup = move || {
let accounts = take_weak!(self.accounts);
let default_account = match account {
let default_account = account;
let default_account = match default_account {
DefaultAccount::Provided(acc) => acc,
DefaultAccount::ForDapp(dapp) => accounts.default_address(dapp).ok().unwrap_or_default(),
};
(accounts, default_account)
Ok((accounts, default_account))
};
let dis = self.dispatcher.clone();
future::done(setup())
.and_then(move |(accounts, default)| {
dispatch::from_rpc(payload, default, &dis)
.and_then(|payload| {
dispatch::execute(&dis, &accounts, payload, dispatch::SignWith::Nothing)
.and_then(move |payload| {
dispatch::execute(dis, &accounts, payload, dispatch::SignWith::Nothing)
})
.map(|v| v.into_value())
})

View File

@ -16,6 +16,7 @@
//! Parity Signer-related rpc interface.
use jsonrpc_core::Error;
use futures::BoxFuture;
use v1::types::{U256, Bytes, TransactionModification, ConfirmationRequest, ConfirmationResponse, ConfirmationResponseWithToken};
@ -28,12 +29,12 @@ build_rpc_trait! {
fn requests_to_confirm(&self) -> Result<Vec<ConfirmationRequest>, Error>;
/// Confirm specific request.
#[rpc(name = "signer_confirmRequest")]
fn confirm_request(&self, U256, TransactionModification, String) -> Result<ConfirmationResponse, Error>;
#[rpc(async, name = "signer_confirmRequest")]
fn confirm_request(&self, U256, TransactionModification, String) -> BoxFuture<ConfirmationResponse, Error>;
/// Confirm specific request with token.
#[rpc(name = "signer_confirmRequestWithToken")]
fn confirm_request_with_token(&self, U256, TransactionModification, String) -> Result<ConfirmationResponseWithToken, Error>;
#[rpc(async, name = "signer_confirmRequestWithToken")]
fn confirm_request_with_token(&self, U256, TransactionModification, String) -> BoxFuture<ConfirmationResponseWithToken, Error>;
/// Confirm specific request with already signed data.
#[rpc(name = "signer_confirmRequestRaw")]