dispatcher abstraction, port most things to it
This commit is contained in:
		
							parent
							
								
									4bb45c4f64
								
							
						
					
					
						commit
						e73ea80954
					
				@ -472,6 +472,12 @@ impl PendingTransaction {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Deref for PendingTransaction {
 | 
			
		||||
	type Target = SignedTransaction;
 | 
			
		||||
 | 
			
		||||
	fn deref(&self) -> &SignedTransaction { &self.transaction }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<SignedTransaction> for PendingTransaction {
 | 
			
		||||
	fn from(t: SignedTransaction) -> Self {
 | 
			
		||||
		PendingTransaction {
 | 
			
		||||
 | 
			
		||||
@ -16,6 +16,9 @@
 | 
			
		||||
 | 
			
		||||
use std::fmt::Debug;
 | 
			
		||||
use std::ops::Deref;
 | 
			
		||||
use std::sync::Weak;
 | 
			
		||||
 | 
			
		||||
use futures::{future, Future, BoxFuture};
 | 
			
		||||
use rlp;
 | 
			
		||||
use util::{Address, H520, H256, U256, Uint, Bytes};
 | 
			
		||||
use util::bytes::ToPretty;
 | 
			
		||||
@ -38,6 +41,118 @@ use v1::types::{
 | 
			
		||||
	DecryptRequest as RpcDecryptRequest,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// Has the capability to dispatch, sign, and decrypt.
 | 
			
		||||
///
 | 
			
		||||
/// Requires a clone implementation, with the implication that it be cheap;
 | 
			
		||||
/// usually just bumping a reference count or two.
 | 
			
		||||
pub trait Dispatcher: Send + Sync + Clone {
 | 
			
		||||
	// TODO: when ATC exist, use zero-cost
 | 
			
		||||
	// type Out<T>: IntoFuture<T, Error>
 | 
			
		||||
 | 
			
		||||
	/// Fill optional fields of a transaction request, fetching gas price but not nonce.
 | 
			
		||||
	fn fill_optional_fields(&self, request: TransactionRequest, default_sender: Address)
 | 
			
		||||
		-> BoxFuture<FilledTransactionRequest, Error>;
 | 
			
		||||
 | 
			
		||||
	/// Sign the given transaction request without dispatching, fetching appropriate nonce.
 | 
			
		||||
	fn sign(&self, accounts: &AccountProvider, filled: FilledTransactionRequest, password: SignWith)
 | 
			
		||||
		-> BoxFuture<WithToken<SignedTransaction>, Error>;
 | 
			
		||||
 | 
			
		||||
	/// "Dispatch" a local transaction.
 | 
			
		||||
	fn dispatch_transaction(&self, signed_transaction: PendingTransaction) -> Result<H256, Error>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// A dispatcher which uses references to a client and miner in order to sign
 | 
			
		||||
/// requests locally.
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub struct FullDispatcher<C, M> {
 | 
			
		||||
	client: Weak<C>,
 | 
			
		||||
	miner: Weak<M>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<C, M> FullDispatcher<C, M> {
 | 
			
		||||
	/// Create a `FullDispatcher` from weak references to a client and miner.
 | 
			
		||||
	pub fn new(client: Weak<C>, miner: Weak<M>) -> Self {
 | 
			
		||||
		FullDispatcher {
 | 
			
		||||
			client: client,
 | 
			
		||||
			miner: miner,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<C, M> Clone for FullDispatcher<C, M> {
 | 
			
		||||
	fn clone(&self) -> Self {
 | 
			
		||||
		FullDispatcher {
 | 
			
		||||
			client: self.client.clone(),
 | 
			
		||||
			miner: self.miner.clone(),
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<C: MiningBlockChainClient, M: MinerService> Dispatcher for FullDispatcher<C, M> {
 | 
			
		||||
	fn fill_optional_fields(&self, request: TransactionRequest, default_sender: Address)
 | 
			
		||||
		-> BoxFuture<FilledTransactionRequest, Error>
 | 
			
		||||
	{
 | 
			
		||||
		let inner = move || {
 | 
			
		||||
			let (client, miner) = (take_weak!(self.client), take_weak!(self.miner));
 | 
			
		||||
			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: 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),
 | 
			
		||||
				condition: request.condition,
 | 
			
		||||
			})
 | 
			
		||||
		};
 | 
			
		||||
		future::done(inner()).boxed()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn sign(&self, accounts: &AccountProvider, filled: FilledTransactionRequest, password: SignWith)
 | 
			
		||||
		-> BoxFuture<WithToken<SignedTransaction>, Error>
 | 
			
		||||
	{
 | 
			
		||||
		let inner = move || {
 | 
			
		||||
			let (client, miner) = (take_weak!(self.client), take_weak!(self.miner));
 | 
			
		||||
			let network_id = client.signing_network_id();
 | 
			
		||||
			let address = filled.from;
 | 
			
		||||
			let signed_transaction = {
 | 
			
		||||
				let t = Transaction {
 | 
			
		||||
					nonce: filled.nonce
 | 
			
		||||
						.or_else(|| miner
 | 
			
		||||
							.last_nonce(&filled.from)
 | 
			
		||||
							.map(|nonce| nonce + U256::one()))
 | 
			
		||||
						.unwrap_or_else(|| client.latest_nonce(&filled.from)),
 | 
			
		||||
 | 
			
		||||
					action: filled.to.map_or(Action::Create, Action::Call),
 | 
			
		||||
					gas: filled.gas,
 | 
			
		||||
					gas_price: filled.gas_price,
 | 
			
		||||
					value: filled.value,
 | 
			
		||||
					data: filled.data,
 | 
			
		||||
				};
 | 
			
		||||
 | 
			
		||||
				let hash = t.hash(network_id);
 | 
			
		||||
				let signature = signature(accounts, address, hash, password)?;
 | 
			
		||||
				signature.map(|sig| {
 | 
			
		||||
					SignedTransaction::new(t.with_signature(sig, network_id))
 | 
			
		||||
						.expect("Transaction was signed by AccountsProvider; it never produces invalid signatures; qed")
 | 
			
		||||
				})
 | 
			
		||||
			};
 | 
			
		||||
			Ok(signed_transaction)
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		future::done(inner()).boxed()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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)
 | 
			
		||||
			.map_err(errors::from_transaction_error)
 | 
			
		||||
			.map(|_| hash)
 | 
			
		||||
		}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub const DEFAULT_MAC: [u8; 2] = [0, 0];
 | 
			
		||||
 | 
			
		||||
type AccountToken = String;
 | 
			
		||||
@ -83,6 +198,14 @@ impl<T: Debug> WithToken<T> {
 | 
			
		||||
			WithToken::Yes(v, _) => v,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Convert the `WithToken` into a tuple.
 | 
			
		||||
	pub fn into_tuple(self) -> (T, Option<AccountToken>) {
 | 
			
		||||
		match self {
 | 
			
		||||
			WithToken::No(v) => (v, None),
 | 
			
		||||
			WithToken::Yes(v, token) => (v, Some(token))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: Debug> From<(T, AccountToken)> for WithToken<T> {
 | 
			
		||||
@ -91,26 +214,44 @@ impl<T: Debug> From<(T, AccountToken)> for WithToken<T> {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn execute<C, M>(client: &C, miner: &M, accounts: &AccountProvider, payload: ConfirmationPayload, pass: SignWith) -> Result<WithToken<ConfirmationResponse>, Error>
 | 
			
		||||
	where C: MiningBlockChainClient, M: MinerService
 | 
			
		||||
{
 | 
			
		||||
impl<T: Debug> From<(T, Option<AccountToken>)> for WithToken<T> {
 | 
			
		||||
	fn from(tuple: (T, Option<AccountToken>)) -> Self {
 | 
			
		||||
		match tuple.1 {
 | 
			
		||||
			Some(token) => WithToken::Yes(tuple.0, token),
 | 
			
		||||
			None => WithToken::No(tuple.0),
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn execute<D: Dispatcher>(
 | 
			
		||||
	dispatcher: D,
 | 
			
		||||
	accounts: &AccountProvider,
 | 
			
		||||
	payload: ConfirmationPayload,
 | 
			
		||||
	pass: SignWith
 | 
			
		||||
) -> BoxFuture<WithToken<ConfirmationResponse>, Error> {
 | 
			
		||||
	match payload {
 | 
			
		||||
		ConfirmationPayload::SendTransaction(request) => {
 | 
			
		||||
			sign_and_dispatch(client, miner, accounts, request, pass)
 | 
			
		||||
				.map(|result| result
 | 
			
		||||
			let condition = request.condition.clone();
 | 
			
		||||
			dispatcher.sign(accounts, request, pass)
 | 
			
		||||
				.map(move |v| v.map(move |tx| PendingTransaction::new(tx, condition)))
 | 
			
		||||
				.map(WithToken::into_tuple)
 | 
			
		||||
				.map(|(tx, token)| (tx, token, dispatcher))
 | 
			
		||||
				.and_then(|(tx, tok, dispatcher)| {
 | 
			
		||||
					dispatcher.dispatch_transaction(tx)
 | 
			
		||||
						.map(RpcH256::from)
 | 
			
		||||
						.map(ConfirmationResponse::SendTransaction)
 | 
			
		||||
				)
 | 
			
		||||
						.map(move |h| WithToken::from((h, tok)))
 | 
			
		||||
				}).boxed()
 | 
			
		||||
		},
 | 
			
		||||
		ConfirmationPayload::SignTransaction(request) => {
 | 
			
		||||
			sign_no_dispatch(client, miner, accounts, request, pass)
 | 
			
		||||
			dispatcher.sign(accounts, request, pass)
 | 
			
		||||
				.map(|result| result
 | 
			
		||||
					.map(RpcRichRawTransaction::from)
 | 
			
		||||
					.map(ConfirmationResponse::SignTransaction)
 | 
			
		||||
				)
 | 
			
		||||
				).boxed()
 | 
			
		||||
		},
 | 
			
		||||
		ConfirmationPayload::Signature(address, data) => {
 | 
			
		||||
			signature(accounts, address, data.sha3(), pass)
 | 
			
		||||
			let res = signature(accounts, address, data.sha3(), pass)
 | 
			
		||||
				.map(|result| result
 | 
			
		||||
					.map(|rsv| {
 | 
			
		||||
						let mut vrs = [0u8; 65];
 | 
			
		||||
@ -122,14 +263,16 @@ pub fn execute<C, M>(client: &C, miner: &M, accounts: &AccountProvider, payload:
 | 
			
		||||
					})
 | 
			
		||||
					.map(RpcH520::from)
 | 
			
		||||
					.map(ConfirmationResponse::Signature)
 | 
			
		||||
				)
 | 
			
		||||
				);
 | 
			
		||||
			future::done(res).boxed()
 | 
			
		||||
		},
 | 
			
		||||
		ConfirmationPayload::Decrypt(address, data) => {
 | 
			
		||||
			decrypt(accounts, address, data, pass)
 | 
			
		||||
			let res = decrypt(accounts, address, data, pass)
 | 
			
		||||
				.map(|result| result
 | 
			
		||||
					.map(RpcBytes)
 | 
			
		||||
					.map(ConfirmationResponse::Decrypt)
 | 
			
		||||
				)
 | 
			
		||||
				);
 | 
			
		||||
			future::done(res).boxed()
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -156,105 +299,34 @@ fn decrypt(accounts: &AccountProvider, address: Address, msg: Bytes, password: S
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn dispatch_transaction<C, M>(client: &C, miner: &M, signed_transaction: PendingTransaction) -> Result<H256, Error>
 | 
			
		||||
	where C: MiningBlockChainClient, M: MinerService {
 | 
			
		||||
	let hash = signed_transaction.transaction.hash();
 | 
			
		||||
 | 
			
		||||
	miner.import_own_transaction(client, signed_transaction)
 | 
			
		||||
		.map_err(errors::from_transaction_error)
 | 
			
		||||
		.map(|_| hash)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn sign_no_dispatch<C, M>(client: &C, miner: &M, accounts: &AccountProvider, filled: FilledTransactionRequest, password: SignWith) -> Result<WithToken<SignedTransaction>, Error>
 | 
			
		||||
	where C: MiningBlockChainClient, M: MinerService {
 | 
			
		||||
 | 
			
		||||
	let network_id = client.signing_network_id();
 | 
			
		||||
	let address = filled.from;
 | 
			
		||||
	let signed_transaction = {
 | 
			
		||||
		let t = Transaction {
 | 
			
		||||
			nonce: filled.nonce
 | 
			
		||||
				.or_else(|| miner
 | 
			
		||||
					.last_nonce(&filled.from)
 | 
			
		||||
					.map(|nonce| nonce + U256::one()))
 | 
			
		||||
				.unwrap_or_else(|| client.latest_nonce(&filled.from)),
 | 
			
		||||
 | 
			
		||||
			action: filled.to.map_or(Action::Create, Action::Call),
 | 
			
		||||
			gas: filled.gas,
 | 
			
		||||
			gas_price: filled.gas_price,
 | 
			
		||||
			value: filled.value,
 | 
			
		||||
			data: filled.data,
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		let hash = t.hash(network_id);
 | 
			
		||||
		let signature = signature(accounts, address, hash, password)?;
 | 
			
		||||
		signature.map(|sig| {
 | 
			
		||||
			SignedTransaction::new(t.with_signature(sig, network_id))
 | 
			
		||||
				.expect("Transaction was signed by AccountsProvider; it never produces invalid signatures; qed")
 | 
			
		||||
		})
 | 
			
		||||
	};
 | 
			
		||||
	Ok(signed_transaction)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn sign_and_dispatch<C, M>(client: &C, miner: &M, accounts: &AccountProvider, filled: FilledTransactionRequest, password: SignWith) -> Result<WithToken<H256>, Error>
 | 
			
		||||
	where C: MiningBlockChainClient, M: MinerService
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	let network_id = client.signing_network_id();
 | 
			
		||||
	let condition = filled.condition.clone();
 | 
			
		||||
	let signed_transaction = sign_no_dispatch(client, miner, accounts, filled, password)?;
 | 
			
		||||
 | 
			
		||||
	let (signed_transaction, token) = match signed_transaction {
 | 
			
		||||
		WithToken::No(signed_transaction) => (signed_transaction, None),
 | 
			
		||||
		WithToken::Yes(signed_transaction, token) => (signed_transaction, Some(token)),
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	trace!(target: "miner", "send_transaction: dispatching tx: {} for network ID {:?}", rlp::encode(&signed_transaction).to_vec().pretty(), network_id);
 | 
			
		||||
	let pending_transaction = PendingTransaction::new(signed_transaction, condition.map(Into::into));
 | 
			
		||||
	dispatch_transaction(&*client, &*miner, pending_transaction).map(|hash| {
 | 
			
		||||
		match token {
 | 
			
		||||
			Some(ref token) => WithToken::Yes(hash, token.clone()),
 | 
			
		||||
			None => WithToken::No(hash),
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn fill_optional_fields<C, M>(request: TransactionRequest, default_sender: Address, client: &C, miner: &M) -> FilledTransactionRequest
 | 
			
		||||
	where C: MiningBlockChainClient, M: MinerService
 | 
			
		||||
{
 | 
			
		||||
	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: 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),
 | 
			
		||||
		condition: request.condition,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Extract default gas price from a client and miner.
 | 
			
		||||
pub fn default_gas_price<C, M>(client: &C, miner: &M) -> U256
 | 
			
		||||
	where C: MiningBlockChainClient, M: MinerService
 | 
			
		||||
{
 | 
			
		||||
	client.gas_price_median(100).unwrap_or_else(|| miner.sensible_gas_price())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn from_rpc<C, M>(payload: RpcConfirmationPayload, default_account: Address, client: &C, miner: &M) -> ConfirmationPayload
 | 
			
		||||
	where C: MiningBlockChainClient, M: MinerService {
 | 
			
		||||
 | 
			
		||||
/// Convert RPC confirmation payload to signer confirmation payload.
 | 
			
		||||
/// May need to resolve in the future to fetch things like gas price.
 | 
			
		||||
pub fn from_rpc<D>(payload: RpcConfirmationPayload, default_account: Address, dispatcher: &D) -> BoxFuture<ConfirmationPayload, Error>
 | 
			
		||||
	where D: Dispatcher
 | 
			
		||||
{
 | 
			
		||||
	match payload {
 | 
			
		||||
		RpcConfirmationPayload::SendTransaction(request) => {
 | 
			
		||||
			ConfirmationPayload::SendTransaction(fill_optional_fields(request.into(), default_account, client, miner))
 | 
			
		||||
			dispatcher.fill_optional_fields(request.into(), default_account)
 | 
			
		||||
				.map(ConfirmationPayload::SendTransaction)
 | 
			
		||||
				.boxed()
 | 
			
		||||
		},
 | 
			
		||||
		RpcConfirmationPayload::SignTransaction(request) => {
 | 
			
		||||
			ConfirmationPayload::SignTransaction(fill_optional_fields(request.into(), default_account, client, miner))
 | 
			
		||||
			dispatcher.fill_optional_fields(request.into(), default_account)
 | 
			
		||||
				.map(ConfirmationPayload::SignTransaction)
 | 
			
		||||
				.boxed()
 | 
			
		||||
		},
 | 
			
		||||
		RpcConfirmationPayload::Decrypt(RpcDecryptRequest { address, msg }) => {
 | 
			
		||||
			ConfirmationPayload::Decrypt(address.into(), msg.into())
 | 
			
		||||
			future::ok(ConfirmationPayload::Decrypt(address.into(), msg.into())).boxed()
 | 
			
		||||
		},
 | 
			
		||||
		RpcConfirmationPayload::Signature(RpcSignRequest { address, data }) => {
 | 
			
		||||
			ConfirmationPayload::Signature(address.into(), data.into())
 | 
			
		||||
			future::ok(ConfirmationPayload::Signature(address.into(), data.into())).boxed()
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -16,15 +16,6 @@
 | 
			
		||||
 | 
			
		||||
//! Ethereum rpc interface implementation.
 | 
			
		||||
 | 
			
		||||
macro_rules! take_weak {
 | 
			
		||||
	($weak: expr) => {
 | 
			
		||||
		match $weak.upgrade() {
 | 
			
		||||
			Some(arc) => arc,
 | 
			
		||||
			None => return Err(Error::internal_error())
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
mod eth;
 | 
			
		||||
mod eth_filter;
 | 
			
		||||
mod net;
 | 
			
		||||
 | 
			
		||||
@ -20,46 +20,37 @@ use std::sync::{Arc, Weak};
 | 
			
		||||
use ethcore::account_provider::AccountProvider;
 | 
			
		||||
use ethcore::client::MiningBlockChainClient;
 | 
			
		||||
use ethcore::miner::MinerService;
 | 
			
		||||
use util::{Address, U128, Uint};
 | 
			
		||||
use ethcore::transaction::PendingTransaction;
 | 
			
		||||
 | 
			
		||||
use futures::{self, Future, BoxFuture};
 | 
			
		||||
use util::{Address, U128, Uint, ToPretty};
 | 
			
		||||
 | 
			
		||||
use futures::{self, future, Future, BoxFuture};
 | 
			
		||||
use jsonrpc_core::Error;
 | 
			
		||||
use v1::helpers::errors;
 | 
			
		||||
use v1::helpers::dispatch::{self, sign_and_dispatch};
 | 
			
		||||
use v1::helpers::dispatch::{Dispatcher, SignWith};
 | 
			
		||||
use v1::traits::Personal;
 | 
			
		||||
use v1::types::{H160 as RpcH160, H256 as RpcH256, U128 as RpcU128, TransactionRequest};
 | 
			
		||||
use v1::metadata::Metadata;
 | 
			
		||||
 | 
			
		||||
/// Account management (personal) rpc implementation.
 | 
			
		||||
pub struct PersonalClient<C, M> where
 | 
			
		||||
	C: MiningBlockChainClient,
 | 
			
		||||
	M: MinerService,
 | 
			
		||||
{
 | 
			
		||||
pub struct PersonalClient<D: Dispatcher> {
 | 
			
		||||
	accounts: Weak<AccountProvider>,
 | 
			
		||||
	client: Weak<C>,
 | 
			
		||||
	miner: Weak<M>,
 | 
			
		||||
	dispatcher: D,
 | 
			
		||||
	allow_perm_unlock: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<C, M> PersonalClient<C, M> where
 | 
			
		||||
	C: MiningBlockChainClient,
 | 
			
		||||
	M: MinerService,
 | 
			
		||||
{
 | 
			
		||||
impl<D: Dispatcher> PersonalClient<D> {
 | 
			
		||||
	/// 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>, dispatcher: D, allow_perm_unlock: bool) -> Self {
 | 
			
		||||
		PersonalClient {
 | 
			
		||||
			accounts: Arc::downgrade(store),
 | 
			
		||||
			client: Arc::downgrade(client),
 | 
			
		||||
			miner: Arc::downgrade(miner),
 | 
			
		||||
			dispatcher: dispatcher,
 | 
			
		||||
			allow_perm_unlock: allow_perm_unlock,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<C, M> Personal for PersonalClient<C, M> where
 | 
			
		||||
	C: MiningBlockChainClient + 'static,
 | 
			
		||||
	M: MinerService + 'static,
 | 
			
		||||
{
 | 
			
		||||
impl<D: Dispatcher + 'static> Personal for PersonalClient<D> {
 | 
			
		||||
	type Metadata = Metadata;
 | 
			
		||||
 | 
			
		||||
	fn accounts(&self) -> Result<Vec<RpcH160>, Error> {
 | 
			
		||||
@ -106,28 +97,41 @@ impl<C, M> Personal for PersonalClient<C, M> where
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn send_transaction(&self, meta: Metadata, request: TransactionRequest, password: String) -> BoxFuture<RpcH256, Error> {
 | 
			
		||||
		let sign_and_send = move || {
 | 
			
		||||
			let client = take_weak!(self.client);
 | 
			
		||||
			let miner = take_weak!(self.miner);
 | 
			
		||||
		let setup = || {
 | 
			
		||||
			let dispatcher = self.dispatcher.clone();
 | 
			
		||||
			let accounts = take_weak!(self.accounts);
 | 
			
		||||
 | 
			
		||||
			let default_account = match request.from {
 | 
			
		||||
				Some(ref account) => account.clone().into(),
 | 
			
		||||
			Ok((accounts, dispatcher))
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		future::done(setup())
 | 
			
		||||
			.and_then(move |(accounts, dispatcher)| {
 | 
			
		||||
				let default = match request.from.as_ref() {
 | 
			
		||||
					Some(account) => Ok(account.clone().into()),
 | 
			
		||||
					None => accounts
 | 
			
		||||
						.default_address(meta.dapp_id.unwrap_or_default().into())
 | 
			
		||||
					.map_err(|e| errors::account("Cannot find default account.", e))?,
 | 
			
		||||
						.map_err(|e| errors::account("Cannot find default account.", e)),
 | 
			
		||||
				};
 | 
			
		||||
 | 
			
		||||
			let request = dispatch::fill_optional_fields(request.into(), default_account, &*client, &*miner);
 | 
			
		||||
			sign_and_dispatch(
 | 
			
		||||
				&*client,
 | 
			
		||||
				&*miner,
 | 
			
		||||
				&*accounts,
 | 
			
		||||
				request,
 | 
			
		||||
				dispatch::SignWith::Password(password)
 | 
			
		||||
			).map(|v| v.into_value().into())
 | 
			
		||||
		};
 | 
			
		||||
				let dis = dispatcher.clone();
 | 
			
		||||
				future::done(default)
 | 
			
		||||
					.and_then(move |default| dis.fill_optional_fields(request.into(), default))
 | 
			
		||||
					.map(move |tx| (tx, accounts, dispatcher))
 | 
			
		||||
			})
 | 
			
		||||
			.and_then(move |(filled, accounts, dispatcher)| {
 | 
			
		||||
				let condition = filled.condition.clone().map(Into::into);
 | 
			
		||||
				dispatcher.sign(&accounts, filled, SignWith::Password(password))
 | 
			
		||||
					.map(|tx| tx.into_value())
 | 
			
		||||
					.map(move |tx| PendingTransaction::new(tx, condition))
 | 
			
		||||
					.map(move |tx| (tx, dispatcher))
 | 
			
		||||
			})
 | 
			
		||||
			.and_then(move |(pending_tx, dispatcher)| {
 | 
			
		||||
				let network_id = pending_tx.network_id();
 | 
			
		||||
				trace!(target: "miner", "send_transaction: dispatching tx: {} for network ID {:?}",
 | 
			
		||||
					::rlp::encode(&*pending_tx).to_vec().pretty(), network_id);
 | 
			
		||||
 | 
			
		||||
		futures::done(sign_and_send()).boxed()
 | 
			
		||||
				dispatcher.dispatch_transaction(pending_tx).map(Into::into)
 | 
			
		||||
			})
 | 
			
		||||
			.boxed()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -24,13 +24,14 @@ use ethcore::account_provider::AccountProvider;
 | 
			
		||||
use ethcore::miner::MinerService;
 | 
			
		||||
use ethcore::client::MiningBlockChainClient;
 | 
			
		||||
 | 
			
		||||
use futures::{self, BoxFuture, Future};
 | 
			
		||||
use futures::{self, future, BoxFuture, Future};
 | 
			
		||||
use jsonrpc_core::Error;
 | 
			
		||||
use v1::helpers::{
 | 
			
		||||
	errors, dispatch,
 | 
			
		||||
	errors,
 | 
			
		||||
	DefaultAccount,
 | 
			
		||||
	SigningQueue, ConfirmationPromise, ConfirmationResult, ConfirmationPayload, SignerService
 | 
			
		||||
};
 | 
			
		||||
use v1::helpers::dispatch::{self, Dispatcher};
 | 
			
		||||
use v1::metadata::Metadata;
 | 
			
		||||
use v1::traits::{EthSigning, ParitySigning};
 | 
			
		||||
use v1::types::{
 | 
			
		||||
@ -50,33 +51,16 @@ enum DispatchResult {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Implementation of functions that require signing when no trusted signer is used.
 | 
			
		||||
pub struct SigningQueueClient<C, M> where C: MiningBlockChainClient, M: MinerService {
 | 
			
		||||
pub struct SigningQueueClient<D> {
 | 
			
		||||
	signer: Weak<SignerService>,
 | 
			
		||||
	accounts: Weak<AccountProvider>,
 | 
			
		||||
	client: Weak<C>,
 | 
			
		||||
	miner: Weak<M>,
 | 
			
		||||
 | 
			
		||||
	pending: Mutex<TransientHashMap<U256, ConfirmationPromise>>,
 | 
			
		||||
	dispatcher: D,
 | 
			
		||||
	pending: Arc<Mutex<TransientHashMap<U256, ConfirmationPromise>>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<C, M> SigningQueueClient<C, M> where
 | 
			
		||||
	C: MiningBlockChainClient,
 | 
			
		||||
	M: MinerService,
 | 
			
		||||
{
 | 
			
		||||
	/// Creates a new signing queue client given shared signing queue.
 | 
			
		||||
	pub fn new(signer: &Arc<SignerService>, client: &Arc<C>, miner: &Arc<M>, accounts: &Arc<AccountProvider>) -> Self {
 | 
			
		||||
		SigningQueueClient {
 | 
			
		||||
			signer: Arc::downgrade(signer),
 | 
			
		||||
			accounts: Arc::downgrade(accounts),
 | 
			
		||||
			client: Arc::downgrade(client),
 | 
			
		||||
			miner: Arc::downgrade(miner),
 | 
			
		||||
			pending: Mutex::new(TransientHashMap::new(MAX_PENDING_DURATION)),
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn handle_dispatch<OnResponse>(&self, res: Result<DispatchResult, Error>, on_response: OnResponse)
 | 
			
		||||
fn handle_dispatch<OnResponse>(res: Result<DispatchResult, Error>, on_response: OnResponse)
 | 
			
		||||
	where OnResponse: FnOnce(Result<RpcConfirmationResponse, Error>) + Send + 'static
 | 
			
		||||
	{
 | 
			
		||||
{
 | 
			
		||||
	match res {
 | 
			
		||||
		Ok(DispatchResult::Value(result)) => on_response(Ok(result)),
 | 
			
		||||
		Ok(DispatchResult::Promise(promise)) => {
 | 
			
		||||
@ -86,69 +70,78 @@ impl<C, M> SigningQueueClient<C, M> where
 | 
			
		||||
		},
 | 
			
		||||
		Err(e) => on_response(Err(e)),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<D: Dispatcher> 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 {
 | 
			
		||||
			signer: Arc::downgrade(signer),
 | 
			
		||||
			accounts: Arc::downgrade(accounts),
 | 
			
		||||
			dispatcher: dispatcher,
 | 
			
		||||
			pending: Arc::new(Mutex::new(TransientHashMap::new(MAX_PENDING_DURATION))),
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn add_to_queue(&self, payload: ConfirmationPayload) -> Result<DispatchResult, Error> {
 | 
			
		||||
		let client = take_weak!(self.client);
 | 
			
		||||
		let miner = take_weak!(self.miner);
 | 
			
		||||
	fn dispatch(&self, payload: RpcConfirmationPayload, default_account: DefaultAccount) -> BoxFuture<DispatchResult, Error> {
 | 
			
		||||
		let setup = || {
 | 
			
		||||
			let accounts = take_weak!(self.accounts);
 | 
			
		||||
 | 
			
		||||
		let sender = payload.sender();
 | 
			
		||||
		if accounts.is_unlocked(sender) {
 | 
			
		||||
			return dispatch::execute(&*client, &*miner, &*accounts, payload, dispatch::SignWith::Nothing)
 | 
			
		||||
				.map(|v| v.into_value())
 | 
			
		||||
				.map(DispatchResult::Value);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		take_weak!(self.signer).add_request(payload)
 | 
			
		||||
			.map(DispatchResult::Promise)
 | 
			
		||||
			.map_err(|_| errors::request_rejected_limit())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn dispatch(&self, payload: RpcConfirmationPayload, default_account: DefaultAccount) -> Result<DispatchResult, Error> {
 | 
			
		||||
		let client = take_weak!(self.client);
 | 
			
		||||
		let miner = take_weak!(self.miner);
 | 
			
		||||
 | 
			
		||||
			let default_account = match default_account {
 | 
			
		||||
				DefaultAccount::Provided(acc) => acc,
 | 
			
		||||
			DefaultAccount::ForDapp(dapp) => take_weak!(self.accounts).default_address(dapp).ok().unwrap_or_default(),
 | 
			
		||||
				DefaultAccount::ForDapp(dapp) => accounts.default_address(dapp).ok().unwrap_or_default(),
 | 
			
		||||
			};
 | 
			
		||||
		let payload = dispatch::from_rpc(payload, default_account, &*client, &*miner);
 | 
			
		||||
		self.add_to_queue(payload)
 | 
			
		||||
 | 
			
		||||
			(self.dispatcher.clone(), accounts, default_account)
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		let weak_signer = self.signer.clone();
 | 
			
		||||
		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)
 | 
			
		||||
								.boxed()
 | 
			
		||||
						} else {
 | 
			
		||||
							future::lazy(move || take_weak!(weak_signer).add_request(payload))
 | 
			
		||||
								.map(DispatchResult::Promise)
 | 
			
		||||
								.map_err(|_| errors::request_rejected_limit())
 | 
			
		||||
								.boxed()
 | 
			
		||||
						}
 | 
			
		||||
					})
 | 
			
		||||
			})
 | 
			
		||||
			.boxed()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<C: 'static, M: 'static> ParitySigning for SigningQueueClient<C, M> where
 | 
			
		||||
	C: MiningBlockChainClient,
 | 
			
		||||
	M: MinerService,
 | 
			
		||||
{
 | 
			
		||||
impl<D: Dispatcher + 'static> ParitySigning for SigningQueueClient<D> {
 | 
			
		||||
	type Metadata = Metadata;
 | 
			
		||||
 | 
			
		||||
	fn post_sign(&self, address: RpcH160, data: RpcBytes) -> Result<RpcEither<RpcU256, RpcConfirmationResponse>, Error> {
 | 
			
		||||
	fn post_sign(&self, address: RpcH160, data: RpcBytes) -> BoxFuture<RpcEither<RpcU256, RpcConfirmationResponse>, Error> {
 | 
			
		||||
		let pending = self.pending.clone();
 | 
			
		||||
		self.dispatch(RpcConfirmationPayload::Signature((address.clone(), data).into()), DefaultAccount::Provided(address.into()))
 | 
			
		||||
			.map(|result| match result {
 | 
			
		||||
			.map(move |result| match result {
 | 
			
		||||
				DispatchResult::Value(v) => RpcEither::Or(v),
 | 
			
		||||
				DispatchResult::Promise(promise) => {
 | 
			
		||||
					let id = promise.id();
 | 
			
		||||
					self.pending.lock().insert(id, promise);
 | 
			
		||||
					pending.lock().insert(id, promise);
 | 
			
		||||
					RpcEither::Either(id.into())
 | 
			
		||||
				},
 | 
			
		||||
			})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn post_transaction(&self, meta: Metadata, request: RpcTransactionRequest) -> BoxFuture<RpcEither<RpcU256, RpcConfirmationResponse>, Error> {
 | 
			
		||||
		let post_transaction = move || {
 | 
			
		||||
		let pending = self.pending.clone();
 | 
			
		||||
		self.dispatch(RpcConfirmationPayload::SendTransaction(request), meta.into())
 | 
			
		||||
				.map(|result| match result {
 | 
			
		||||
			.map(move |result| match result {
 | 
			
		||||
				DispatchResult::Value(v) => RpcEither::Or(v),
 | 
			
		||||
				DispatchResult::Promise(promise) => {
 | 
			
		||||
					let id = promise.id();
 | 
			
		||||
						self.pending.lock().insert(id, promise);
 | 
			
		||||
					pending.lock().insert(id, promise);
 | 
			
		||||
					RpcEither::Either(id.into())
 | 
			
		||||
				},
 | 
			
		||||
			})
 | 
			
		||||
		};
 | 
			
		||||
		futures::done(post_transaction()).boxed()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn check_request(&self, id: RpcU256) -> Result<Option<RpcConfirmationResponse>, Error> {
 | 
			
		||||
@ -170,8 +163,11 @@ impl<C: 'static, M: 'static> ParitySigning for SigningQueueClient<C, M> where
 | 
			
		||||
		let res = self.dispatch(RpcConfirmationPayload::Decrypt((address.clone(), data).into()), address.into());
 | 
			
		||||
 | 
			
		||||
		let (ready, p) = futures::oneshot();
 | 
			
		||||
		// TODO [todr] typed handle_dispatch
 | 
			
		||||
		self.handle_dispatch(res, |response| {
 | 
			
		||||
 | 
			
		||||
		// when dispatch is complete
 | 
			
		||||
		res.then(move |res| {
 | 
			
		||||
			// register callback via the oneshot sender.
 | 
			
		||||
			handle_dispatch(res, move |response| {
 | 
			
		||||
				match response {
 | 
			
		||||
					Ok(RpcConfirmationResponse::Decrypt(data)) => ready.complete(Ok(data)),
 | 
			
		||||
					Err(e) => ready.complete(Err(e)),
 | 
			
		||||
@ -179,36 +175,40 @@ impl<C: 'static, M: 'static> ParitySigning for SigningQueueClient<C, M> where
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// and wait for that to resolve.
 | 
			
		||||
			p.then(|result| futures::done(result.expect("Ready is never dropped nor canceled."))).boxed()
 | 
			
		||||
		}).boxed()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<C: 'static, M: 'static> EthSigning for SigningQueueClient<C, M> where
 | 
			
		||||
	C: MiningBlockChainClient,
 | 
			
		||||
	M: MinerService,
 | 
			
		||||
{
 | 
			
		||||
impl<D: Dispatcher + 'static> EthSigning for SigningQueueClient<D> {
 | 
			
		||||
	type Metadata = Metadata;
 | 
			
		||||
 | 
			
		||||
	fn sign(&self, address: RpcH160, data: RpcBytes) -> BoxFuture<RpcH520, Error> {
 | 
			
		||||
		let res = self.dispatch(RpcConfirmationPayload::Signature((address.clone(), data).into()), address.into());
 | 
			
		||||
 | 
			
		||||
		let (ready, p) = futures::oneshot();
 | 
			
		||||
		self.handle_dispatch(res, |response| {
 | 
			
		||||
 | 
			
		||||
		res.then(move |res| {
 | 
			
		||||
			handle_dispatch(res, move |response| {
 | 
			
		||||
				match response {
 | 
			
		||||
				Ok(RpcConfirmationResponse::Signature(signature)) => ready.complete(Ok(signature)),
 | 
			
		||||
					Ok(RpcConfirmationResponse::Signature(sig)) => ready.complete(Ok(sig)),
 | 
			
		||||
					Err(e) => ready.complete(Err(e)),
 | 
			
		||||
					e => ready.complete(Err(errors::internal("Unexpected result.", e))),
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			p.then(|result| futures::done(result.expect("Ready is never dropped nor canceled."))).boxed()
 | 
			
		||||
		}).boxed()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn send_transaction(&self, meta: Metadata, request: RpcTransactionRequest) -> BoxFuture<RpcH256, Error> {
 | 
			
		||||
		let res = self.dispatch(RpcConfirmationPayload::SendTransaction(request), meta.into());
 | 
			
		||||
 | 
			
		||||
		let (ready, p) = futures::oneshot();
 | 
			
		||||
		self.handle_dispatch(res, |response| {
 | 
			
		||||
 | 
			
		||||
		res.then(move |res| {
 | 
			
		||||
			handle_dispatch(res, move |response| {
 | 
			
		||||
				match response {
 | 
			
		||||
					Ok(RpcConfirmationResponse::SendTransaction(hash)) => ready.complete(Ok(hash)),
 | 
			
		||||
					Err(e) => ready.complete(Err(e)),
 | 
			
		||||
@ -217,13 +217,16 @@ impl<C: 'static, M: 'static> EthSigning for SigningQueueClient<C, M> where
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			p.then(|result| futures::done(result.expect("Ready is never dropped nor canceled."))).boxed()
 | 
			
		||||
		}).boxed()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn sign_transaction(&self, meta: Metadata, request: RpcTransactionRequest) -> BoxFuture<RpcRichRawTransaction, Error> {
 | 
			
		||||
		let res = self.dispatch(RpcConfirmationPayload::SignTransaction(request), meta.into());
 | 
			
		||||
 | 
			
		||||
		let (ready, p) = futures::oneshot();
 | 
			
		||||
		self.handle_dispatch(res, |response| {
 | 
			
		||||
 | 
			
		||||
		res.then(move |res| {
 | 
			
		||||
			handle_dispatch(res, move |response| {
 | 
			
		||||
				match response {
 | 
			
		||||
					Ok(RpcConfirmationResponse::SignTransaction(tx)) => ready.complete(Ok(tx)),
 | 
			
		||||
					Err(e) => ready.complete(Err(e)),
 | 
			
		||||
@ -232,5 +235,6 @@ impl<C: 'static, M: 'static> EthSigning for SigningQueueClient<C, M> where
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			p.then(|result| futures::done(result.expect("Ready is never dropped nor canceled."))).boxed()
 | 
			
		||||
		}).boxed()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -22,9 +22,10 @@ use ethcore::account_provider::AccountProvider;
 | 
			
		||||
use ethcore::miner::MinerService;
 | 
			
		||||
use ethcore::client::MiningBlockChainClient;
 | 
			
		||||
 | 
			
		||||
use futures::{self, BoxFuture, Future};
 | 
			
		||||
use futures::{self, future, BoxFuture, Future};
 | 
			
		||||
use jsonrpc_core::Error;
 | 
			
		||||
use v1::helpers::{errors, dispatch, DefaultAccount};
 | 
			
		||||
use v1::helpers::{errors, DefaultAccount};
 | 
			
		||||
use v1::helpers::dispatch::{self, Dispatcher};
 | 
			
		||||
use v1::metadata::Metadata;
 | 
			
		||||
use v1::traits::{EthSigning, ParitySigning};
 | 
			
		||||
use v1::types::{
 | 
			
		||||
@ -38,106 +39,100 @@ use v1::types::{
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// Implementation of functions that require signing when no trusted signer is used.
 | 
			
		||||
pub struct SigningUnsafeClient<C, M> where
 | 
			
		||||
	C: MiningBlockChainClient,
 | 
			
		||||
	M: MinerService,
 | 
			
		||||
{
 | 
			
		||||
pub struct SigningUnsafeClient<D> {
 | 
			
		||||
	accounts: Weak<AccountProvider>,
 | 
			
		||||
	client: Weak<C>,
 | 
			
		||||
	miner: Weak<M>,
 | 
			
		||||
	dispatcher: D,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<C, M> SigningUnsafeClient<C, M> where
 | 
			
		||||
	C: MiningBlockChainClient,
 | 
			
		||||
	M: MinerService,
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
impl<D: Dispatcher> SigningUnsafeClient<D> {
 | 
			
		||||
	/// Creates new SigningUnsafeClient.
 | 
			
		||||
	pub fn new(client: &Arc<C>, accounts: &Arc<AccountProvider>, miner: &Arc<M>)
 | 
			
		||||
		-> Self {
 | 
			
		||||
	pub fn new(accounts: &Arc<AccountProvider>, dispatcher: D) -> Self {
 | 
			
		||||
		SigningUnsafeClient {
 | 
			
		||||
			client: Arc::downgrade(client),
 | 
			
		||||
			miner: Arc::downgrade(miner),
 | 
			
		||||
			accounts: Arc::downgrade(accounts),
 | 
			
		||||
			dispatcher: dispatcher,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn handle(&self, payload: RpcConfirmationPayload, account: DefaultAccount) -> Result<RpcConfirmationResponse, Error> {
 | 
			
		||||
		let client = take_weak!(self.client);
 | 
			
		||||
		let miner = take_weak!(self.miner);
 | 
			
		||||
	fn handle(&self, payload: RpcConfirmationPayload, account: DefaultAccount) -> BoxFuture<RpcConfirmationResponse, Error> {
 | 
			
		||||
		let setup = move || {
 | 
			
		||||
			let accounts = take_weak!(self.accounts);
 | 
			
		||||
 | 
			
		||||
			let default_account = match account {
 | 
			
		||||
				DefaultAccount::Provided(acc) => acc,
 | 
			
		||||
				DefaultAccount::ForDapp(dapp) => accounts.default_address(dapp).ok().unwrap_or_default(),
 | 
			
		||||
			};
 | 
			
		||||
		let payload = dispatch::from_rpc(payload, default_account, &*client, &*miner);
 | 
			
		||||
		dispatch::execute(&*client, &*miner, &*accounts, payload, dispatch::SignWith::Nothing)
 | 
			
		||||
 | 
			
		||||
			(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)
 | 
			
		||||
					})
 | 
			
		||||
					.map(|v| v.into_value())
 | 
			
		||||
			})
 | 
			
		||||
			.boxed()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<C: 'static, M: 'static> EthSigning for SigningUnsafeClient<C, M> where
 | 
			
		||||
	C: MiningBlockChainClient,
 | 
			
		||||
	M: MinerService,
 | 
			
		||||
impl<D: Dispatcher + 'static> EthSigning for SigningUnsafeClient<D>
 | 
			
		||||
{
 | 
			
		||||
	type Metadata = Metadata;
 | 
			
		||||
 | 
			
		||||
	fn sign(&self, address: RpcH160, data: RpcBytes) -> BoxFuture<RpcH520, Error> {
 | 
			
		||||
		let result = match self.handle(RpcConfirmationPayload::Signature((address.clone(), data).into()), address.into()) {
 | 
			
		||||
		self.handle(RpcConfirmationPayload::Signature((address.clone(), data).into()), address.into())
 | 
			
		||||
			.then(|res| match res {
 | 
			
		||||
				Ok(RpcConfirmationResponse::Signature(signature)) => Ok(signature),
 | 
			
		||||
				Err(e) => Err(e),
 | 
			
		||||
				e => Err(errors::internal("Unexpected result", e)),
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		futures::done(result).boxed()
 | 
			
		||||
			})
 | 
			
		||||
			.boxed()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn send_transaction(&self, meta: Metadata, request: RpcTransactionRequest) -> BoxFuture<RpcH256, Error> {
 | 
			
		||||
		let result = match self.handle(RpcConfirmationPayload::SendTransaction(request), meta.into()) {
 | 
			
		||||
		self.handle(RpcConfirmationPayload::SendTransaction(request), meta.into())
 | 
			
		||||
			.then(|res| match res {
 | 
			
		||||
				Ok(RpcConfirmationResponse::SendTransaction(hash)) => Ok(hash),
 | 
			
		||||
				Err(e) => Err(e),
 | 
			
		||||
				e => Err(errors::internal("Unexpected result", e)),
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		futures::done(result).boxed()
 | 
			
		||||
			})
 | 
			
		||||
			.boxed()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn sign_transaction(&self, meta: Metadata, request: RpcTransactionRequest) -> BoxFuture<RpcRichRawTransaction, Error> {
 | 
			
		||||
		let result = match self.handle(RpcConfirmationPayload::SignTransaction(request), meta.into()) {
 | 
			
		||||
		self.handle(RpcConfirmationPayload::SignTransaction(request), meta.into())
 | 
			
		||||
			.then(|res| match res {
 | 
			
		||||
				Ok(RpcConfirmationResponse::SignTransaction(tx)) => Ok(tx),
 | 
			
		||||
				Err(e) => Err(e),
 | 
			
		||||
				e => Err(errors::internal("Unexpected result", e)),
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		futures::done(result).boxed()
 | 
			
		||||
			})
 | 
			
		||||
			.boxed()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<C: 'static, M: 'static> ParitySigning for SigningUnsafeClient<C, M> where
 | 
			
		||||
	C: MiningBlockChainClient,
 | 
			
		||||
	M: MinerService,
 | 
			
		||||
{
 | 
			
		||||
impl<D: Dispatcher + 'static> ParitySigning for SigningUnsafeClient<D> {
 | 
			
		||||
	type Metadata = Metadata;
 | 
			
		||||
 | 
			
		||||
	fn decrypt_message(&self, address: RpcH160, data: RpcBytes) -> BoxFuture<RpcBytes, Error> {
 | 
			
		||||
		let result = match self.handle(RpcConfirmationPayload::Decrypt((address.clone(), data).into()), address.into()) {
 | 
			
		||||
		self.handle(RpcConfirmationPayload::Decrypt((address.clone(), data).into()), address.into())
 | 
			
		||||
			.then(|res| match res {
 | 
			
		||||
				Ok(RpcConfirmationResponse::Decrypt(data)) => Ok(data),
 | 
			
		||||
				Err(e) => Err(e),
 | 
			
		||||
				e => Err(errors::internal("Unexpected result", e)),
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		futures::done(result).boxed()
 | 
			
		||||
			})
 | 
			
		||||
			.boxed()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn post_sign(&self, _: RpcH160, _: RpcBytes) -> Result<RpcEither<RpcU256, RpcConfirmationResponse>, Error> {
 | 
			
		||||
	fn post_sign(&self, _: RpcH160, _: RpcBytes) -> BoxFuture<RpcEither<RpcU256, RpcConfirmationResponse>, Error> {
 | 
			
		||||
		// We don't support this in non-signer mode.
 | 
			
		||||
		Err(errors::signer_disabled())
 | 
			
		||||
		future::err(errors::signer_disabled()).boxed()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn post_transaction(&self, _: Metadata, _: RpcTransactionRequest) -> BoxFuture<RpcEither<RpcU256, RpcConfirmationResponse>, Error> {
 | 
			
		||||
		// We don't support this in non-signer mode.
 | 
			
		||||
		futures::done(Err(errors::signer_disabled())).boxed()
 | 
			
		||||
		future::err((errors::signer_disabled())).boxed()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn check_request(&self, _: RpcU256) -> Result<Option<RpcConfirmationResponse>, Error> {
 | 
			
		||||
 | 
			
		||||
@ -18,6 +18,15 @@
 | 
			
		||||
//!
 | 
			
		||||
//! Compliant with ethereum rpc.
 | 
			
		||||
 | 
			
		||||
macro_rules! take_weak {
 | 
			
		||||
	($weak: expr) => {
 | 
			
		||||
		match $weak.upgrade() {
 | 
			
		||||
			Some(arc) => arc,
 | 
			
		||||
			None => return Err(Error::internal_error())
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[macro_use]
 | 
			
		||||
mod helpers;
 | 
			
		||||
mod impls;
 | 
			
		||||
 | 
			
		||||
@ -27,8 +27,8 @@ build_rpc_trait! {
 | 
			
		||||
 | 
			
		||||
		/// Posts sign request asynchronously.
 | 
			
		||||
		/// Will return a confirmation ID for later use with check_transaction.
 | 
			
		||||
		#[rpc(name = "parity_postSign")]
 | 
			
		||||
		fn post_sign(&self, H160, Bytes) -> Result<Either<U256, ConfirmationResponse>, Error>;
 | 
			
		||||
		#[rpc(async, name = "parity_postSign")]
 | 
			
		||||
		fn post_sign(&self, H160, Bytes) -> BoxFuture<Either<U256, ConfirmationResponse>, Error>;
 | 
			
		||||
 | 
			
		||||
		/// Posts transaction asynchronously.
 | 
			
		||||
		/// Will return a transaction ID for later use with check_transaction.
 | 
			
		||||
 | 
			
		||||
@ -164,7 +164,7 @@ mod tests {
 | 
			
		||||
			logs_bloom: H2048::default(),
 | 
			
		||||
			timestamp: U256::default(),
 | 
			
		||||
			difficulty: U256::default(),
 | 
			
		||||
			total_difficulty: U256::default(),
 | 
			
		||||
			total_difficulty: Some(U256::default()),
 | 
			
		||||
			seal_fields: vec![Bytes::default(), Bytes::default()],
 | 
			
		||||
			uncles: vec![],
 | 
			
		||||
			transactions: BlockTransactions::Hashes(vec![].into()),
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user