From e53d023a8accbee859be3ba5fa92b05816fb23e9 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Thu, 9 Feb 2017 21:12:28 +0100 Subject: [PATCH] implement light dispatcher --- rpc/src/v1/helpers/dispatch.rs | 92 ++++++++++++++++++++++++++++-- rpc/src/v1/helpers/errors.rs | 9 +++ rpc/src/v1/impls/personal.rs | 2 +- rpc/src/v1/impls/signer.rs | 4 +- rpc/src/v1/impls/signing.rs | 2 +- rpc/src/v1/impls/signing_unsafe.rs | 2 +- 6 files changed, 100 insertions(+), 11 deletions(-) diff --git a/rpc/src/v1/helpers/dispatch.rs b/rpc/src/v1/helpers/dispatch.rs index 447456992..a27193cfc 100644 --- a/rpc/src/v1/helpers/dispatch.rs +++ b/rpc/src/v1/helpers/dispatch.rs @@ -29,6 +29,7 @@ use util::sha3::Hashable; use ethkey::Signature; use ethsync::LightSync; +use ethcore::ids::BlockId; use ethcore::miner::MinerService; use ethcore::client::MiningBlockChainClient; use ethcore::transaction::{Action, SignedTransaction, PendingTransaction, Transaction}; @@ -58,7 +59,7 @@ pub trait Dispatcher: Send + Sync + Clone { -> BoxFuture; /// Sign the given transaction request without dispatching, fetching appropriate nonce. - fn sign(&self, accounts: &AccountProvider, filled: FilledTransactionRequest, password: SignWith) + fn sign(&self, accounts: Arc, filled: FilledTransactionRequest, password: SignWith) -> BoxFuture, Error>; /// "Dispatch" a local transaction. @@ -111,7 +112,7 @@ impl Dispatcher for FullDispatcher, filled: FilledTransactionRequest, password: SignWith) -> BoxFuture, Error> { let (client, miner) = (take_weakf!(self.client), take_weakf!(self.miner)); @@ -133,7 +134,7 @@ impl Dispatcher for FullDispatcher BoxFuture + { + let request = request; + let gas_limit = self.client.block_header(BlockId::Latest) + .expect("Best block header always kept; qed").gas_limit(); + + future::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(|| 21_000_000.into()), // TODO: fetch corpus from network. + gas: request.gas.unwrap_or_else(|| gas_limit / 3.into()), + value: request.value.unwrap_or_else(|| 0.into()), + data: request.data.unwrap_or_else(Vec::new), + condition: request.condition, + }).boxed() + } + + fn sign(&self, accounts: Arc, filled: FilledTransactionRequest, password: SignWith) + -> BoxFuture, Error> + { + let network_id = None; // TODO: fetch from client. + let address = filled.from; + let best_header = self.client.block_header(BlockId::Latest) + .expect("Best block header always kept; qed"); + + let with_nonce = move |filled: FilledTransactionRequest, nonce| { + let t = Transaction { + nonce: nonce, + 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)?; + + Ok(signature.map(|sig| { + SignedTransaction::new(t.with_signature(sig, network_id)) + .expect("Transaction was signed by AccountsProvider; it never produces invalid signatures; qed") + })) + }; + + // fast path where we don't go to network; nonce provided or can be gotten from queue. + let maybe_nonce = filled.nonce.or_else(|| self.transaction_queue.read().next_nonce(&address)); + if let Some(nonce) = maybe_nonce { + return future::done(with_nonce(filled, nonce)).boxed() + } + + let nonce_future = self.sync.with_context(|ctx| self.on_demand.account(ctx, request::Account { + header: best_header, + address: address, + })); + + let nonce_future = match nonce_future { + Some(x) => x, + None => return future::err(errors::no_light_peers()).boxed() + }; + + nonce_future + .map_err(|_| errors::no_light_peers()) + .and_then(move |acc| with_nonce(filled, acc.nonce + U256::one())) + .boxed() + } + + fn dispatch_transaction(&self, signed_transaction: PendingTransaction) -> Result { + let hash = signed_transaction.transaction.hash(); + + self.transaction_queue.write().import(signed_transaction) + .map_err(Into::into) + .map_err(errors::from_transaction_error) + .map(|_| hash) + } +} + /// default MAC to use. pub const DEFAULT_MAC: [u8; 2] = [0, 0]; @@ -264,7 +344,7 @@ impl From<(T, Option)> for WithToken { /// Execute a confirmation payload. pub fn execute( dispatcher: D, - accounts: &AccountProvider, + accounts: Arc, payload: ConfirmationPayload, pass: SignWith ) -> BoxFuture, Error> { @@ -294,7 +374,7 @@ pub fn execute( format!("\x19Ethereum Signed Message:\n{}", data.len()) .into_bytes(); message_data.append(&mut data); - let res = signature(accounts, address, message_data.sha3(), pass) + let res = signature(&accounts, address, message_data.sha3(), pass) .map(|result| result .map(|rsv| { let mut vrs = [0u8; 65]; @@ -310,7 +390,7 @@ pub fn execute( future::done(res).boxed() }, ConfirmationPayload::Decrypt(address, data) => { - let res = decrypt(accounts, address, data, pass) + let res = decrypt(&accounts, address, data, pass) .map(|result| result .map(RpcBytes) .map(ConfirmationResponse::Decrypt) diff --git a/rpc/src/v1/helpers/errors.rs b/rpc/src/v1/helpers/errors.rs index e1074c598..b58999f84 100644 --- a/rpc/src/v1/helpers/errors.rs +++ b/rpc/src/v1/helpers/errors.rs @@ -49,6 +49,7 @@ mod codes { pub const COMPILATION_ERROR: i64 = -32050; pub const ENCRYPTION_ERROR: i64 = -32055; pub const FETCH_ERROR: i64 = -32060; + pub const NO_LIGHT_PEERS: i64 = -32065; } pub fn unimplemented(details: Option) -> Error { @@ -308,3 +309,11 @@ pub fn unknown_block() -> Error { data: None, } } + +pub fn no_light_peers() -> Error { + Error { + code: ErrorCode::ServerError(codes::NO_LIGHT_PEERS), + message: "No light peers who can serve data".into(), + data: None, + } +} diff --git a/rpc/src/v1/impls/personal.rs b/rpc/src/v1/impls/personal.rs index 03ce5ffeb..bf0745259 100644 --- a/rpc/src/v1/impls/personal.rs +++ b/rpc/src/v1/impls/personal.rs @@ -113,7 +113,7 @@ impl Personal for PersonalClient { dispatcher.fill_optional_fields(request.into(), default) .and_then(move |filled| { let condition = filled.condition.clone().map(Into::into); - dispatcher.sign(&accounts, filled, SignWith::Password(password)) + dispatcher.sign(accounts, filled, SignWith::Password(password)) .map(|tx| tx.into_value()) .map(move |tx| PendingTransaction::new(tx, condition)) .map(move |tx| (tx, dispatcher)) diff --git a/rpc/src/v1/impls/signer.rs b/rpc/src/v1/impls/signer.rs index a94db94a0..ffd9f4108 100644 --- a/rpc/src/v1/impls/signer.rs +++ b/rpc/src/v1/impls/signer.rs @@ -52,7 +52,7 @@ impl SignerClient { } fn confirm_internal(&self, id: U256, modification: TransactionModification, f: F) -> BoxFuture, Error> where - F: FnOnce(D, &AccountProvider, ConfirmationPayload) -> T, + F: FnOnce(D, Arc, ConfirmationPayload) -> T, T: IntoFuture, Error=Error>, T::Future: Send + 'static { @@ -87,7 +87,7 @@ impl SignerClient { request.condition = condition.clone().map(Into::into); } } - let fut = f(dispatcher, &*accounts, payload); + let fut = f(dispatcher, accounts, payload); fut.into_future().then(move |result| { // Execute if let Ok(ref response) = result { diff --git a/rpc/src/v1/impls/signing.rs b/rpc/src/v1/impls/signing.rs index 6bf2155ed..106852d82 100644 --- a/rpc/src/v1/impls/signing.rs +++ b/rpc/src/v1/impls/signing.rs @@ -94,7 +94,7 @@ impl SigningQueueClient { .and_then(move |payload| { let sender = payload.sender(); if accounts.is_unlocked(sender) { - dispatch::execute(dispatcher, &accounts, payload, dispatch::SignWith::Nothing) + dispatch::execute(dispatcher, accounts, payload, dispatch::SignWith::Nothing) .map(|v| v.into_value()) .map(DispatchResult::Value) .boxed() diff --git a/rpc/src/v1/impls/signing_unsafe.rs b/rpc/src/v1/impls/signing_unsafe.rs index 333b823f9..c588313ec 100644 --- a/rpc/src/v1/impls/signing_unsafe.rs +++ b/rpc/src/v1/impls/signing_unsafe.rs @@ -61,7 +61,7 @@ impl SigningUnsafeClient { let dis = self.dispatcher.clone(); dispatch::from_rpc(payload, default, &dis) .and_then(move |payload| { - dispatch::execute(dis, &accounts, payload, dispatch::SignWith::Nothing) + dispatch::execute(dis, accounts, payload, dispatch::SignWith::Nothing) }) .map(|v| v.into_value()) .boxed()