@@ -30,14 +30,15 @@ use bytes::Bytes;
3030use parking_lot:: { Mutex , RwLock } ;
3131use stats:: Corpus ;
3232
33- use ethkey :: { Password , Signature } ;
34- use sync :: LightSync ;
35- use ethcore:: ids :: BlockId ;
33+ use crypto :: DEFAULT_MAC ;
34+ use ethcore :: account_provider :: AccountProvider ;
35+ use ethcore:: basic_account :: BasicAccount ;
3636use ethcore:: client:: BlockChainClient ;
37+ use ethcore:: ids:: BlockId ;
3738use ethcore:: miner:: { self , MinerService } ;
38- use ethcore :: account_provider :: AccountProvider ;
39- use crypto :: DEFAULT_MAC ;
40- use transaction:: { Action , SignedTransaction , PendingTransaction , Transaction } ;
39+ use ethkey :: { Password , Signature } ;
40+ use sync :: LightSync ;
41+ use transaction:: { Action , SignedTransaction , PendingTransaction , Transaction , Error as TransactionError } ;
4142
4243use jsonrpc_core:: { BoxFuture , Result , Error } ;
4344use jsonrpc_core:: futures:: { future, Future , Poll , Async } ;
@@ -218,7 +219,6 @@ pub fn fetch_gas_price_corpus(
218219 for t in block. transaction_views ( ) . iter ( ) {
219220 v. push ( t. gas_price ( ) )
220221 }
221-
222222 v
223223 } )
224224 } )
@@ -302,40 +302,42 @@ impl LightDispatcher {
302302 )
303303 }
304304
305- /// Get an account's next nonce.
306- pub fn next_nonce ( & self , addr : Address ) -> BoxFuture < U256 > {
307- // fast path where we don't go to network; nonce provided or can be gotten from queue.
308- let maybe_nonce = self . transaction_queue . read ( ) . next_nonce ( & addr) ;
309- if let Some ( nonce) = maybe_nonce {
310- return Box :: new ( future:: ok ( nonce) )
311- }
312-
305+ /// Get an account's state
306+ fn account ( & self , addr : Address ) -> BoxFuture < Option < BasicAccount > > {
313307 let best_header = self . client . best_block_header ( ) ;
314- let account_start_nonce = self . client . engine ( ) . account_start_nonce ( best_header. number ( ) ) ;
315- let nonce_future = self . sync . with_context ( |ctx| self . on_demand . request ( ctx, request:: Account {
308+ let account_future = self . sync . with_context ( |ctx| self . on_demand . request ( ctx, request:: Account {
316309 header : best_header. into ( ) ,
317310 address : addr,
318311 } ) . expect ( "no back-references; therefore all back-references valid; qed" ) ) ;
319312
320- match nonce_future {
321- Some ( x) => Box :: new (
322- x. map ( move |acc| acc. map_or ( account_start_nonce, |acc| acc. nonce ) )
323- . map_err ( |_| errors:: no_light_peers ( ) )
324- ) ,
325- None => Box :: new ( future:: err ( errors:: network_disabled ( ) ) )
313+ match account_future {
314+ Some ( response) => Box :: new ( response. map_err ( |_| errors:: no_light_peers ( ) ) ) ,
315+ None => Box :: new ( future:: err ( errors:: network_disabled ( ) ) ) ,
326316 }
327317 }
318+
319+ /// Get an account's next nonce.
320+ pub fn next_nonce ( & self , addr : Address ) -> BoxFuture < U256 > {
321+ let account_start_nonce = self . client . engine ( ) . account_start_nonce ( self . client . best_block_header ( ) . number ( ) ) ;
322+ Box :: new ( self . account ( addr)
323+ . and_then ( move |maybe_account| {
324+ future:: ok ( maybe_account. map_or ( account_start_nonce, |account| account. nonce ) )
325+ } )
326+ )
327+ }
328328}
329329
330330impl Dispatcher for LightDispatcher {
331- fn fill_optional_fields ( & self , request : TransactionRequest , default_sender : Address , force_nonce : bool )
331+ // Ignore the `force_nonce` flag in order to always query the network when fetching the nonce and
332+ // the account state. If the nonce is specified in the transaction use that nonce instead but do the
333+ // network request anyway to the account state (balance)
334+ fn fill_optional_fields ( & self , request : TransactionRequest , default_sender : Address , _force_nonce : bool )
332335 -> BoxFuture < FilledTransactionRequest >
333336 {
334337 const DEFAULT_GAS_PRICE : U256 = U256 ( [ 0 , 0 , 0 , 21_000_000 ] ) ;
335338
336339 let gas_limit = self . client . best_block_header ( ) . gas_limit ( ) ;
337340 let request_gas_price = request. gas_price . clone ( ) ;
338- let request_nonce = request. nonce . clone ( ) ;
339341 let from = request. from . unwrap_or ( default_sender) ;
340342
341343 let with_gas_price = move |gas_price| {
@@ -368,39 +370,37 @@ impl Dispatcher for LightDispatcher {
368370 } ) . map ( with_gas_price) )
369371 } ;
370372
371- match ( request_nonce, force_nonce) {
372- ( _, false ) | ( Some ( _) , true ) => Box :: new ( gas_price) ,
373- ( None , true ) => {
374- let next_nonce = self . next_nonce ( from) ;
375- Box :: new ( gas_price. and_then ( move |mut filled| next_nonce
376- . map_err ( |_| errors:: no_light_peers ( ) )
377- . map ( move |nonce| {
378- filled. nonce = Some ( nonce) ;
379- filled
380- } )
381- ) )
382- } ,
383- }
373+ let future_account = self . account ( from) ;
374+
375+ Box :: new ( gas_price. and_then ( move |mut filled| {
376+ future_account
377+ . and_then ( move |maybe_account| {
378+ let cost = filled. value . saturating_add ( filled. gas . saturating_mul ( filled. gas_price ) ) ;
379+ match maybe_account {
380+ Some ( ref account) if cost > account. balance => {
381+ Err ( errors:: transaction ( TransactionError :: InsufficientBalance {
382+ balance : account. balance ,
383+ cost,
384+ } ) )
385+ }
386+ Some ( account) => {
387+ if filled. nonce . is_none ( ) {
388+ filled. nonce = Some ( account. nonce ) ;
389+ }
390+ Ok ( filled)
391+ }
392+ None => Err ( errors:: account ( "Account not found" , "" ) ) ,
393+ }
394+ } )
395+ } ) )
384396 }
385397
386398 fn sign ( & self , accounts : Arc < AccountProvider > , filled : FilledTransactionRequest , password : SignWith )
387399 -> BoxFuture < WithToken < SignedTransaction > >
388400 {
389401 let chain_id = self . client . signing_chain_id ( ) ;
390-
391- // fast path for pre-filled nonce.
392- if let Some ( nonce) = filled. nonce {
393- return Box :: new ( future:: done ( sign_transaction ( & * accounts, filled, chain_id, nonce, password) ) )
394- }
395-
396- let nonces = self . nonces . clone ( ) ;
397- Box :: new ( self . next_nonce ( filled. from )
398- . map_err ( |_| errors:: no_light_peers ( ) )
399- . and_then ( move |nonce| {
400- let reserved = nonces. lock ( ) . reserve ( filled. from , nonce) ;
401-
402- ProspectiveSigner :: new ( accounts, filled, chain_id, reserved, password)
403- } ) )
402+ let nonce = filled. nonce . expect ( "nonce is always provided; qed" ) ;
403+ Box :: new ( future:: done ( sign_transaction ( & * accounts, filled, chain_id, nonce, password) ) )
404404 }
405405
406406 fn enrich ( & self , signed_transaction : SignedTransaction ) -> RpcRichRawTransaction {
0 commit comments