Skip to content
This repository was archived by the owner on Nov 6, 2020. It is now read-only.

Commit c35abe4

Browse files
seunlanlegetomusdrw
authored andcommitted
import rpc transactions sequentially (#10051)
* import rpc transactions sequentially * use impl trait in argument position, renamed ProspectiveDispatcher to WithPostSign * grouped imports * integrates PostSign with ProspectiveSigner * fix spaces, removed unnecessary type cast and duplicate polling * clean up code style * Apply suggestions from code review
1 parent a9a278a commit c35abe4

File tree

2 files changed

+159
-65
lines changed

2 files changed

+159
-65
lines changed

rpc/src/v1/helpers/dispatch.rs

Lines changed: 128 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@ use types::basic_account::BasicAccount;
4141
use types::ids::BlockId;
4242

4343
use jsonrpc_core::{BoxFuture, Result, Error};
44-
use jsonrpc_core::futures::{future, Future, Poll, Async};
44+
use jsonrpc_core::futures::{future, Future, Poll, Async, IntoFuture};
4545
use jsonrpc_core::futures::future::Either;
4646
use v1::helpers::{errors, nonce, TransactionRequest, FilledTransactionRequest, ConfirmationPayload};
4747
use v1::types::{
48-
H256 as RpcH256, H520 as RpcH520, Bytes as RpcBytes,
48+
H520 as RpcH520, Bytes as RpcBytes,
4949
RichRawTransaction as RpcRichRawTransaction,
5050
ConfirmationPayload as RpcConfirmationPayload,
5151
ConfirmationResponse,
@@ -69,12 +69,20 @@ pub trait Dispatcher: Send + Sync + Clone {
6969
fn fill_optional_fields(&self, request: TransactionRequest, default_sender: Address, force_nonce: bool)
7070
-> BoxFuture<FilledTransactionRequest>;
7171

72-
/// Sign the given transaction request without dispatching, fetching appropriate nonce.
73-
fn sign(&self, accounts: Arc<AccountProvider>, filled: FilledTransactionRequest, password: SignWith)
74-
-> BoxFuture<WithToken<SignedTransaction>>;
72+
/// Sign the given transaction request, fetching appropriate nonce and executing the PostSign action
73+
fn sign<P>(
74+
&self,
75+
accounts: Arc<AccountProvider>,
76+
filled: FilledTransactionRequest,
77+
password: SignWith,
78+
post_sign: P
79+
) -> BoxFuture<P::Item>
80+
where
81+
P: PostSign + 'static,
82+
<P::Out as futures::future::IntoFuture>::Future: Send;
7583

7684
/// Converts a `SignedTransaction` into `RichRawTransaction`
77-
fn enrich(&self, SignedTransaction) -> RpcRichRawTransaction;
85+
fn enrich(&self, signed: SignedTransaction) -> RpcRichRawTransaction;
7886

7987
/// "Dispatch" a local transaction.
8088
fn dispatch_transaction(&self, signed_transaction: PendingTransaction)
@@ -164,19 +172,30 @@ impl<C: miner::BlockChainClient + BlockChainClient, M: MinerService> Dispatcher
164172
}))
165173
}
166174

167-
fn sign(&self, accounts: Arc<AccountProvider>, filled: FilledTransactionRequest, password: SignWith)
168-
-> BoxFuture<WithToken<SignedTransaction>>
175+
fn sign<P>(
176+
&self,
177+
accounts: Arc<AccountProvider>,
178+
filled: FilledTransactionRequest,
179+
password: SignWith,
180+
post_sign: P
181+
) -> BoxFuture<P::Item>
182+
where
183+
P: PostSign + 'static,
184+
<P::Out as futures::future::IntoFuture>::Future: Send
169185
{
170186
let chain_id = self.client.signing_chain_id();
171187

172188
if let Some(nonce) = filled.nonce {
173-
return Box::new(future::done(sign_transaction(&*accounts, filled, chain_id, nonce, password)));
174-
}
175-
176-
let state = self.state_nonce(&filled.from);
177-
let reserved = self.nonces.lock().reserve(filled.from, state);
189+
let future = sign_transaction(&*accounts, filled, chain_id, nonce, password)
190+
.into_future()
191+
.and_then(move |signed| post_sign.execute(signed));
192+
Box::new(future)
193+
} else {
194+
let state = self.state_nonce(&filled.from);
195+
let reserved = self.nonces.lock().reserve(filled.from, state);
178196

179-
Box::new(ProspectiveSigner::new(accounts, filled, chain_id, reserved, password))
197+
Box::new(ProspectiveSigner::new(accounts, filled, chain_id, reserved, password, post_sign))
198+
}
180199
}
181200

182201
fn enrich(&self, signed_transaction: SignedTransaction) -> RpcRichRawTransaction {
@@ -396,12 +415,24 @@ impl Dispatcher for LightDispatcher {
396415
}))
397416
}
398417

399-
fn sign(&self, accounts: Arc<AccountProvider>, filled: FilledTransactionRequest, password: SignWith)
400-
-> BoxFuture<WithToken<SignedTransaction>>
418+
fn sign<P>(
419+
&self,
420+
accounts: Arc<AccountProvider>,
421+
filled: FilledTransactionRequest,
422+
password: SignWith,
423+
post_sign: P
424+
) -> BoxFuture<P::Item>
425+
where
426+
P: PostSign + 'static,
427+
<P::Out as futures::future::IntoFuture>::Future: Send
401428
{
402429
let chain_id = self.client.signing_chain_id();
403430
let nonce = filled.nonce.expect("nonce is always provided; qed");
404-
Box::new(future::done(sign_transaction(&*accounts, filled, chain_id, nonce, password)))
431+
432+
let future = sign_transaction(&*accounts, filled, chain_id, nonce, password)
433+
.into_future()
434+
.and_then(move |signed| post_sign.execute(signed));
435+
Box::new(future)
405436
}
406437

407438
fn enrich(&self, signed_transaction: SignedTransaction) -> RpcRichRawTransaction {
@@ -449,28 +480,60 @@ fn sign_transaction(
449480
#[derive(Debug, Clone, Copy)]
450481
enum ProspectiveSignerState {
451482
TryProspectiveSign,
483+
WaitForPostSign,
452484
WaitForNonce,
453-
Finish,
454485
}
455486

456-
struct ProspectiveSigner {
487+
struct ProspectiveSigner<P: PostSign> {
457488
accounts: Arc<AccountProvider>,
458489
filled: FilledTransactionRequest,
459490
chain_id: Option<u64>,
460491
reserved: nonce::Reserved,
461492
password: SignWith,
462493
state: ProspectiveSignerState,
463-
prospective: Option<Result<WithToken<SignedTransaction>>>,
494+
prospective: Option<WithToken<SignedTransaction>>,
464495
ready: Option<nonce::Ready>,
496+
post_sign: Option<P>,
497+
post_sign_future: Option<<P::Out as IntoFuture>::Future>
465498
}
466499

467-
impl ProspectiveSigner {
500+
/// action to execute after signing
501+
/// e.g importing a transaction into the chain
502+
pub trait PostSign: Send {
503+
/// item that this PostSign returns
504+
type Item: Send;
505+
/// incase you need to perform async PostSign actions
506+
type Out: IntoFuture<Item = Self::Item, Error = Error> + Send;
507+
/// perform an action with the signed transaction
508+
fn execute(self, signer: WithToken<SignedTransaction>) -> Self::Out;
509+
}
510+
511+
impl PostSign for () {
512+
type Item = WithToken<SignedTransaction>;
513+
type Out = Result<Self::Item>;
514+
fn execute(self, signed: WithToken<SignedTransaction>) -> Self::Out {
515+
Ok(signed)
516+
}
517+
}
518+
519+
impl<F: Send, T: Send> PostSign for F
520+
where F: FnOnce(WithToken<SignedTransaction>) -> Result<T>
521+
{
522+
type Item = T;
523+
type Out = Result<Self::Item>;
524+
fn execute(self, signed: WithToken<SignedTransaction>) -> Self::Out {
525+
(self)(signed)
526+
}
527+
}
528+
529+
impl<P: PostSign> ProspectiveSigner<P> {
468530
pub fn new(
469531
accounts: Arc<AccountProvider>,
470532
filled: FilledTransactionRequest,
471533
chain_id: Option<u64>,
472534
reserved: nonce::Reserved,
473535
password: SignWith,
536+
post_sign: P
474537
) -> Self {
475538
// If the account is permanently unlocked we can try to sign
476539
// using prospective nonce. This should speed up sending
@@ -491,6 +554,8 @@ impl ProspectiveSigner {
491554
},
492555
prospective: None,
493556
ready: None,
557+
post_sign: Some(post_sign),
558+
post_sign_future: None
494559
}
495560
}
496561

@@ -509,8 +574,8 @@ impl ProspectiveSigner {
509574
}
510575
}
511576

512-
impl Future for ProspectiveSigner {
513-
type Item = WithToken<SignedTransaction>;
577+
impl<P: PostSign> Future for ProspectiveSigner<P> {
578+
type Item = P::Item;
514579
type Error = Error;
515580

516581
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
@@ -523,32 +588,45 @@ impl Future for ProspectiveSigner {
523588
match self.poll_reserved()? {
524589
Async::NotReady => {
525590
self.state = WaitForNonce;
526-
self.prospective = Some(self.sign(self.reserved.prospective_value()));
591+
self.prospective = Some(self.sign(self.reserved.prospective_value())?);
527592
},
528593
Async::Ready(nonce) => {
529-
self.state = Finish;
530-
self.prospective = Some(self.sign(nonce.value()));
594+
self.state = WaitForPostSign;
595+
self.post_sign_future = Some(self.post_sign.take()
596+
.expect("post_sign is set on creation; qed")
597+
.execute(self.sign(nonce.value())?)
598+
.into_future());
531599
self.ready = Some(nonce);
532600
},
533601
}
534602
},
535603
WaitForNonce => {
536604
let nonce = try_ready!(self.poll_reserved());
537-
let result = match (self.prospective.take(), nonce.matches_prospective()) {
605+
let prospective = match (self.prospective.take(), nonce.matches_prospective()) {
538606
(Some(prospective), true) => prospective,
539-
_ => self.sign(nonce.value()),
607+
_ => self.sign(nonce.value())?,
540608
};
541-
self.state = Finish;
542-
self.prospective = Some(result);
543609
self.ready = Some(nonce);
610+
self.state = WaitForPostSign;
611+
self.post_sign_future = Some(self.post_sign.take()
612+
.expect("post_sign is set on creation; qed")
613+
.execute(prospective)
614+
.into_future());
544615
},
545-
Finish => {
546-
if let (Some(result), Some(nonce)) = (self.prospective.take(), self.ready.take()) {
547-
// Mark nonce as used on successful signing
548-
return result.map(move |tx| {
549-
nonce.mark_used();
550-
Async::Ready(tx)
551-
})
616+
WaitForPostSign => {
617+
if let Some(mut fut) = self.post_sign_future.as_mut() {
618+
match fut.poll()? {
619+
Async::Ready(item) => {
620+
let nonce = self.ready
621+
.take()
622+
.expect("nonce is set before state transitions to WaitForPostSign; qed");
623+
nonce.mark_used();
624+
return Ok(Async::Ready(item))
625+
},
626+
Async::NotReady => {
627+
return Ok(Async::NotReady)
628+
}
629+
}
552630
} else {
553631
panic!("Poll after ready.");
554632
}
@@ -655,19 +733,21 @@ pub fn execute<D: Dispatcher + 'static>(
655733
match payload {
656734
ConfirmationPayload::SendTransaction(request) => {
657735
let condition = request.condition.clone().map(Into::into);
658-
Box::new(dispatcher.sign(accounts, request, pass)
659-
.map(move |v| v.map(move |tx| PendingTransaction::new(tx, condition)))
660-
.map(WithToken::into_tuple)
661-
.map(|(tx, token)| (tx, token, dispatcher))
662-
.and_then(|(tx, tok, dispatcher)| {
663-
dispatcher.dispatch_transaction(tx)
664-
.map(RpcH256::from)
665-
.map(ConfirmationResponse::SendTransaction)
666-
.map(move |h| WithToken::from((h, tok)))
667-
}))
736+
let cloned_dispatcher = dispatcher.clone();
737+
let post_sign = move |with_token_signed: WithToken<SignedTransaction>| {
738+
let (signed, token) = with_token_signed.into_tuple();
739+
let signed_transaction = PendingTransaction::new(signed, condition);
740+
cloned_dispatcher.dispatch_transaction(signed_transaction)
741+
.map(|hash| (hash, token))
742+
};
743+
let future = dispatcher.sign(accounts, request, pass, post_sign)
744+
.map(|(hash, token)| {
745+
WithToken::from((ConfirmationResponse::SendTransaction(hash.into()), token))
746+
});
747+
Box::new(future)
668748
},
669749
ConfirmationPayload::SignTransaction(request) => {
670-
Box::new(dispatcher.sign(accounts, request, pass)
750+
Box::new(dispatcher.sign(accounts, request, pass, ())
671751
.map(move |result| result
672752
.map(move |tx| dispatcher.enrich(tx))
673753
.map(ConfirmationResponse::SignTransaction)

rpc/src/v1/impls/personal.rs

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
use std::sync::Arc;
1919
use std::time::Duration;
2020

21-
use bytes::{Bytes, ToPretty};
21+
use bytes::Bytes;
2222
use ethcore::account_provider::AccountProvider;
2323
use types::transaction::PendingTransaction;
2424
use ethereum_types::{H520, U128, Address};
@@ -27,7 +27,7 @@ use ethkey::{public_to_address, recover, Signature};
2727
use jsonrpc_core::{BoxFuture, Result};
2828
use jsonrpc_core::futures::{future, Future};
2929
use v1::helpers::{errors, eip191};
30-
use v1::helpers::dispatch::{self, eth_data_hash, Dispatcher, SignWith};
30+
use v1::helpers::dispatch::{self, eth_data_hash, Dispatcher, SignWith, PostSign, WithToken};
3131
use v1::traits::Personal;
3232
use v1::types::{
3333
H160 as RpcH160, H256 as RpcH256, H520 as RpcH520, U128 as RpcU128,
@@ -41,6 +41,7 @@ use v1::types::{
4141
use v1::metadata::Metadata;
4242
use eip_712::{EIP712, hash_structured_data};
4343
use jsonrpc_core::types::Value;
44+
use transaction::SignedTransaction;
4445

4546
/// Account management (personal) rpc implementation.
4647
pub struct PersonalClient<D: Dispatcher> {
@@ -68,7 +69,16 @@ impl<D: Dispatcher> PersonalClient<D> {
6869
}
6970

7071
impl<D: Dispatcher + 'static> PersonalClient<D> {
71-
fn do_sign_transaction(&self, _meta: Metadata, request: TransactionRequest, password: String) -> BoxFuture<(PendingTransaction, D)> {
72+
fn do_sign_transaction<P>(
73+
&self,
74+
_meta: Metadata,
75+
request: TransactionRequest,
76+
password: String,
77+
post_sign: P
78+
) -> BoxFuture<P::Item>
79+
where P: PostSign + 'static,
80+
<P::Out as futures::future::IntoFuture>::Future: Send
81+
{
7282
let dispatcher = self.dispatcher.clone();
7383
let accounts = self.accounts.clone();
7484

@@ -86,11 +96,7 @@ impl<D: Dispatcher + 'static> PersonalClient<D> {
8696

8797
Box::new(dispatcher.fill_optional_fields(request.into(), default, false)
8898
.and_then(move |filled| {
89-
let condition = filled.condition.clone().map(Into::into);
90-
dispatcher.sign(accounts, filled, SignWith::Password(password.into()))
91-
.map(|tx| tx.into_value())
92-
.map(move |tx| PendingTransaction::new(tx, condition))
93-
.map(move |tx| (tx, dispatcher))
99+
dispatcher.sign(accounts, filled, SignWith::Password(password.into()), post_sign)
94100
})
95101
)
96102
}
@@ -223,18 +229,26 @@ impl<D: Dispatcher + 'static> Personal for PersonalClient<D> {
223229
}
224230

225231
fn sign_transaction(&self, meta: Metadata, request: TransactionRequest, password: String) -> BoxFuture<RpcRichRawTransaction> {
226-
Box::new(self.do_sign_transaction(meta, request, password)
227-
.map(|(pending_tx, dispatcher)| dispatcher.enrich(pending_tx.transaction)))
232+
let condition = request.condition.clone().map(Into::into);
233+
let dispatcher = self.dispatcher.clone();
234+
Box::new(self.do_sign_transaction(meta, request, password, ())
235+
.map(move |tx| PendingTransaction::new(tx.into_value(), condition))
236+
.map(move |pending_tx| dispatcher.enrich(pending_tx.transaction)))
228237
}
229238

230239
fn send_transaction(&self, meta: Metadata, request: TransactionRequest, password: String) -> BoxFuture<RpcH256> {
231-
Box::new(self.do_sign_transaction(meta, request, password)
232-
.and_then(|(pending_tx, dispatcher)| {
233-
let chain_id = pending_tx.chain_id();
234-
trace!(target: "miner", "send_transaction: dispatching tx: {} for chain ID {:?}",
235-
::rlp::encode(&*pending_tx).pretty(), chain_id);
236-
237-
dispatcher.dispatch_transaction(pending_tx).map(Into::into)
240+
let condition = request.condition.clone().map(Into::into);
241+
let dispatcher = self.dispatcher.clone();
242+
Box::new(self.do_sign_transaction(meta, request, password, move |signed: WithToken<SignedTransaction>| {
243+
dispatcher.dispatch_transaction(
244+
PendingTransaction::new(
245+
signed.into_value(),
246+
condition
247+
)
248+
)
249+
})
250+
.and_then(|hash| {
251+
Ok(RpcH256::from(hash))
238252
})
239253
)
240254
}

0 commit comments

Comments
 (0)