@@ -30,14 +30,15 @@ use bytes::Bytes;
30
30
use parking_lot:: { Mutex , RwLock } ;
31
31
use stats:: Corpus ;
32
32
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 ;
36
36
use ethcore:: client:: BlockChainClient ;
37
+ use ethcore:: ids:: BlockId ;
37
38
use 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 } ;
41
42
42
43
use jsonrpc_core:: { BoxFuture , Result , Error } ;
43
44
use jsonrpc_core:: futures:: { future, Future , Poll , Async } ;
@@ -218,7 +219,6 @@ pub fn fetch_gas_price_corpus(
218
219
for t in block. transaction_views ( ) . iter ( ) {
219
220
v. push ( t. gas_price ( ) )
220
221
}
221
-
222
222
v
223
223
} )
224
224
} )
@@ -302,40 +302,42 @@ impl LightDispatcher {
302
302
)
303
303
}
304
304
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 > > {
313
307
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 {
316
309
header : best_header. into ( ) ,
317
310
address : addr,
318
311
} ) . expect ( "no back-references; therefore all back-references valid; qed" ) ) ;
319
312
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 ( ) ) ) ,
326
316
}
327
317
}
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
+ }
328
328
}
329
329
330
330
impl 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 )
332
335
-> BoxFuture < FilledTransactionRequest >
333
336
{
334
337
const DEFAULT_GAS_PRICE : U256 = U256 ( [ 0 , 0 , 0 , 21_000_000 ] ) ;
335
338
336
339
let gas_limit = self . client . best_block_header ( ) . gas_limit ( ) ;
337
340
let request_gas_price = request. gas_price . clone ( ) ;
338
- let request_nonce = request. nonce . clone ( ) ;
339
341
let from = request. from . unwrap_or ( default_sender) ;
340
342
341
343
let with_gas_price = move |gas_price| {
@@ -368,39 +370,37 @@ impl Dispatcher for LightDispatcher {
368
370
} ) . map ( with_gas_price) )
369
371
} ;
370
372
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
+ } ) )
384
396
}
385
397
386
398
fn sign ( & self , accounts : Arc < AccountProvider > , filled : FilledTransactionRequest , password : SignWith )
387
399
-> BoxFuture < WithToken < SignedTransaction > >
388
400
{
389
401
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) ) )
404
404
}
405
405
406
406
fn enrich ( & self , signed_transaction : SignedTransaction ) -> RpcRichRawTransaction {
0 commit comments