@@ -41,11 +41,11 @@ use types::basic_account::BasicAccount;
41
41
use types:: ids:: BlockId ;
42
42
43
43
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 } ;
45
45
use jsonrpc_core:: futures:: future:: Either ;
46
46
use v1:: helpers:: { errors, nonce, TransactionRequest , FilledTransactionRequest , ConfirmationPayload } ;
47
47
use v1:: types:: {
48
- H256 as RpcH256 , H520 as RpcH520 , Bytes as RpcBytes ,
48
+ H520 as RpcH520 , Bytes as RpcBytes ,
49
49
RichRawTransaction as RpcRichRawTransaction ,
50
50
ConfirmationPayload as RpcConfirmationPayload ,
51
51
ConfirmationResponse ,
@@ -69,12 +69,20 @@ pub trait Dispatcher: Send + Sync + Clone {
69
69
fn fill_optional_fields ( & self , request : TransactionRequest , default_sender : Address , force_nonce : bool )
70
70
-> BoxFuture < FilledTransactionRequest > ;
71
71
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 ;
75
83
76
84
/// Converts a `SignedTransaction` into `RichRawTransaction`
77
- fn enrich ( & self , SignedTransaction ) -> RpcRichRawTransaction ;
85
+ fn enrich ( & self , signed : SignedTransaction ) -> RpcRichRawTransaction ;
78
86
79
87
/// "Dispatch" a local transaction.
80
88
fn dispatch_transaction ( & self , signed_transaction : PendingTransaction )
@@ -164,19 +172,30 @@ impl<C: miner::BlockChainClient + BlockChainClient, M: MinerService> Dispatcher
164
172
} ) )
165
173
}
166
174
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
169
185
{
170
186
let chain_id = self . client . signing_chain_id ( ) ;
171
187
172
188
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) ;
178
196
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
+ }
180
199
}
181
200
182
201
fn enrich ( & self , signed_transaction : SignedTransaction ) -> RpcRichRawTransaction {
@@ -396,12 +415,24 @@ impl Dispatcher for LightDispatcher {
396
415
} ) )
397
416
}
398
417
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
401
428
{
402
429
let chain_id = self . client . signing_chain_id ( ) ;
403
430
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)
405
436
}
406
437
407
438
fn enrich ( & self , signed_transaction : SignedTransaction ) -> RpcRichRawTransaction {
@@ -449,28 +480,60 @@ fn sign_transaction(
449
480
#[ derive( Debug , Clone , Copy ) ]
450
481
enum ProspectiveSignerState {
451
482
TryProspectiveSign ,
483
+ WaitForPostSign ,
452
484
WaitForNonce ,
453
- Finish ,
454
485
}
455
486
456
- struct ProspectiveSigner {
487
+ struct ProspectiveSigner < P : PostSign > {
457
488
accounts : Arc < AccountProvider > ,
458
489
filled : FilledTransactionRequest ,
459
490
chain_id : Option < u64 > ,
460
491
reserved : nonce:: Reserved ,
461
492
password : SignWith ,
462
493
state : ProspectiveSignerState ,
463
- prospective : Option < Result < WithToken < SignedTransaction > > > ,
494
+ prospective : Option < WithToken < SignedTransaction > > ,
464
495
ready : Option < nonce:: Ready > ,
496
+ post_sign : Option < P > ,
497
+ post_sign_future : Option < <P :: Out as IntoFuture >:: Future >
465
498
}
466
499
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 > {
468
530
pub fn new (
469
531
accounts : Arc < AccountProvider > ,
470
532
filled : FilledTransactionRequest ,
471
533
chain_id : Option < u64 > ,
472
534
reserved : nonce:: Reserved ,
473
535
password : SignWith ,
536
+ post_sign : P
474
537
) -> Self {
475
538
// If the account is permanently unlocked we can try to sign
476
539
// using prospective nonce. This should speed up sending
@@ -491,6 +554,8 @@ impl ProspectiveSigner {
491
554
} ,
492
555
prospective : None ,
493
556
ready : None ,
557
+ post_sign : Some ( post_sign) ,
558
+ post_sign_future : None
494
559
}
495
560
}
496
561
@@ -509,8 +574,8 @@ impl ProspectiveSigner {
509
574
}
510
575
}
511
576
512
- impl Future for ProspectiveSigner {
513
- type Item = WithToken < SignedTransaction > ;
577
+ impl < P : PostSign > Future for ProspectiveSigner < P > {
578
+ type Item = P :: Item ;
514
579
type Error = Error ;
515
580
516
581
fn poll ( & mut self ) -> Poll < Self :: Item , Self :: Error > {
@@ -523,32 +588,45 @@ impl Future for ProspectiveSigner {
523
588
match self . poll_reserved ( ) ? {
524
589
Async :: NotReady => {
525
590
self . state = WaitForNonce ;
526
- self . prospective = Some ( self . sign ( self . reserved . prospective_value ( ) ) ) ;
591
+ self . prospective = Some ( self . sign ( self . reserved . prospective_value ( ) ) ? ) ;
527
592
} ,
528
593
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 ( ) ) ;
531
599
self . ready = Some ( nonce) ;
532
600
} ,
533
601
}
534
602
} ,
535
603
WaitForNonce => {
536
604
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 ( ) ) {
538
606
( Some ( prospective) , true ) => prospective,
539
- _ => self . sign ( nonce. value ( ) ) ,
607
+ _ => self . sign ( nonce. value ( ) ) ? ,
540
608
} ;
541
- self . state = Finish ;
542
- self . prospective = Some ( result) ;
543
609
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 ( ) ) ;
544
615
} ,
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
+ }
552
630
} else {
553
631
panic ! ( "Poll after ready." ) ;
554
632
}
@@ -655,19 +733,21 @@ pub fn execute<D: Dispatcher + 'static>(
655
733
match payload {
656
734
ConfirmationPayload :: SendTransaction ( request) => {
657
735
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)
668
748
} ,
669
749
ConfirmationPayload :: SignTransaction ( request) => {
670
- Box :: new ( dispatcher. sign ( accounts, request, pass)
750
+ Box :: new ( dispatcher. sign ( accounts, request, pass, ( ) )
671
751
. map ( move |result| result
672
752
. map ( move |tx| dispatcher. enrich ( tx) )
673
753
. map ( ConfirmationResponse :: SignTransaction )
0 commit comments