return default accounts from on_demand

This commit is contained in:
Robert Habermeier 2017-03-28 18:42:45 +02:00
parent 73fa0cdc31
commit 1b0a369889
5 changed files with 30 additions and 17 deletions

View File

@ -35,7 +35,7 @@ use futures::sync::oneshot::{self, Sender, Receiver};
use network::PeerId; use network::PeerId;
use rlp::RlpStream; use rlp::RlpStream;
use util::{Bytes, RwLock, Mutex, U256, H256}; use util::{Bytes, RwLock, Mutex, U256, H256};
use util::sha3::{SHA3_NULL_RLP, SHA3_EMPTY_LIST_RLP}; use util::sha3::{SHA3_NULL_RLP, SHA3_EMPTY, SHA3_EMPTY_LIST_RLP};
use net::{self, Handler, Status, Capabilities, Announcement, EventContext, BasicContext, ReqId}; use net::{self, Handler, Status, Capabilities, Announcement, EventContext, BasicContext, ReqId};
use cache::Cache; use cache::Cache;
@ -83,7 +83,7 @@ enum Pending {
HeaderByHash(request::HeaderByHash, Sender<encoded::Header>), HeaderByHash(request::HeaderByHash, Sender<encoded::Header>),
Block(request::Body, Sender<encoded::Block>), Block(request::Body, Sender<encoded::Block>),
BlockReceipts(request::BlockReceipts, Sender<Vec<Receipt>>), BlockReceipts(request::BlockReceipts, Sender<Vec<Receipt>>),
Account(request::Account, Sender<Option<BasicAccount>>), Account(request::Account, Sender<BasicAccount>),
Code(request::Code, Sender<Bytes>), Code(request::Code, Sender<Bytes>),
TxProof(request::TransactionProof, Sender<Result<Executed, ExecutionError>>), TxProof(request::TransactionProof, Sender<Result<Executed, ExecutionError>>),
} }
@ -136,18 +136,20 @@ pub struct OnDemand {
pending_requests: RwLock<HashMap<ReqId, Pending>>, pending_requests: RwLock<HashMap<ReqId, Pending>>,
cache: Arc<Mutex<Cache>>, cache: Arc<Mutex<Cache>>,
orphaned_requests: RwLock<Vec<Pending>>, orphaned_requests: RwLock<Vec<Pending>>,
start_nonce: U256,
} }
const RECEIVER_IN_SCOPE: &'static str = "Receiver is still in scope, so it's not dropped; qed"; const RECEIVER_IN_SCOPE: &'static str = "Receiver is still in scope, so it's not dropped; qed";
impl OnDemand { impl OnDemand {
/// Create a new `OnDemand` service with the given cache. /// Create a new `OnDemand` service with the given cache.
pub fn new(cache: Arc<Mutex<Cache>>) -> Self { pub fn new(cache: Arc<Mutex<Cache>>, account_start_nonce: U256) -> Self {
OnDemand { OnDemand {
peers: RwLock::new(HashMap::new()), peers: RwLock::new(HashMap::new()),
pending_requests: RwLock::new(HashMap::new()), pending_requests: RwLock::new(HashMap::new()),
cache: cache, cache: cache,
orphaned_requests: RwLock::new(Vec::new()), orphaned_requests: RwLock::new(Vec::new()),
start_nonce: account_start_nonce,
} }
} }
@ -268,7 +270,7 @@ impl OnDemand {
/// Request an account by address and block header -- which gives a hash to query and a state root /// Request an account by address and block header -- which gives a hash to query and a state root
/// to verify against. /// to verify against.
pub fn account(&self, ctx: &BasicContext, req: request::Account) -> Receiver<Option<BasicAccount>> { pub fn account(&self, ctx: &BasicContext, req: request::Account) -> Receiver<BasicAccount> {
let (sender, receiver) = oneshot::channel(); let (sender, receiver) = oneshot::channel();
self.dispatch(ctx, Pending::Account(req, sender)); self.dispatch(ctx, Pending::Account(req, sender));
receiver receiver
@ -279,7 +281,7 @@ impl OnDemand {
let (sender, receiver) = oneshot::channel(); let (sender, receiver) = oneshot::channel();
// fast path for no code. // fast path for no code.
if req.code_hash == ::util::sha3::SHA3_EMPTY { if req.code_hash == SHA3_EMPTY {
sender.send(Vec::new()).expect(RECEIVER_IN_SCOPE) sender.send(Vec::new()).expect(RECEIVER_IN_SCOPE)
} else { } else {
self.dispatch(ctx, Pending::Code(req, sender)); self.dispatch(ctx, Pending::Code(req, sender));
@ -497,10 +499,19 @@ impl Handler for OnDemand {
Pending::Account(req, sender) => { Pending::Account(req, sender) => {
if let NetworkResponse::Account(ref response) = *response { if let NetworkResponse::Account(ref response) = *response {
match req.check_response(&response.proof) { match req.check_response(&response.proof) {
Ok(maybe_account) => { Ok(account) => {
let account = account.unwrap_or_else(|| {
BasicAccount {
balance: 0.into(),
nonce: self.start_nonce,
code_hash: SHA3_EMPTY,
storage_root: SHA3_NULL_RLP
}
});
// TODO: validate against request outputs. // TODO: validate against request outputs.
// needs engine + env info as part of request. // needs engine + env info as part of request.
let _ = sender.send(maybe_account); let _ = sender.send(account);
return return
} }
Err(e) => warn!(target: "on_demand", "Error handling response for state request: {:?}", e), Err(e) => warn!(target: "on_demand", "Error handling response for state request: {:?}", e),
@ -572,7 +583,7 @@ mod tests {
#[test] #[test]
fn detects_hangup() { fn detects_hangup() {
let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6)))); let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::hours(6))));
let on_demand = OnDemand::new(cache); let on_demand = OnDemand::new(cache, 0.into());
let result = on_demand.header_by_hash(&FakeContext, request::HeaderByHash(H256::default())); let result = on_demand.header_by_hash(&FakeContext, request::HeaderByHash(H256::default()));
assert!(on_demand.orphaned_requests.read().len() == 1); assert!(on_demand.orphaned_requests.read().len() == 1);

View File

@ -67,7 +67,6 @@ impl IoHandler<ClientIoMessage> for QueueCull {
let (sync, on_demand, txq) = (self.sync.clone(), self.on_demand.clone(), self.txq.clone()); let (sync, on_demand, txq) = (self.sync.clone(), self.on_demand.clone(), self.txq.clone());
let best_header = self.client.best_block_header(); let best_header = self.client.best_block_header();
let start_nonce = self.client.engine().account_start_nonce();
info!(target: "cull", "Attempting to cull queued transactions from {} senders.", senders.len()); info!(target: "cull", "Attempting to cull queued transactions from {} senders.", senders.len());
self.remote.spawn_with_timeout(move || { self.remote.spawn_with_timeout(move || {
@ -75,8 +74,7 @@ impl IoHandler<ClientIoMessage> for QueueCull {
// fetch the nonce of each sender in the queue. // fetch the nonce of each sender in the queue.
let nonce_futures = senders.iter() let nonce_futures = senders.iter()
.map(|&address| request::Account { header: best_header.clone(), address: address }) .map(|&address| request::Account { header: best_header.clone(), address: address })
.map(|request| on_demand.account(ctx, request)) .map(|request| on_demand.account(ctx, request).map(|acc| acc.nonce))
.map(move |fut| fut.map(move |x| x.map(|acc| acc.nonce).unwrap_or(start_nonce)))
.zip(senders.iter()) .zip(senders.iter())
.map(|(fut, &addr)| fut.map(move |nonce| (addr, nonce))); .map(|(fut, &addr)| fut.map(move |nonce| (addr, nonce)));

View File

@ -225,7 +225,8 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) ->
let cache = Arc::new(::util::Mutex::new(cache)); let cache = Arc::new(::util::Mutex::new(cache));
// start on_demand service. // start on_demand service.
let on_demand = Arc::new(::light::on_demand::OnDemand::new(cache.clone())); let account_start_nonce = service.client().engine().account_start_nonce();
let on_demand = Arc::new(::light::on_demand::OnDemand::new(cache.clone(), account_start_nonce));
// set network path. // set network path.
net_conf.net_config_path = Some(db_dirs.network_path().to_string_lossy().into_owned()); net_conf.net_config_path = Some(db_dirs.network_path().to_string_lossy().into_owned());

View File

@ -268,7 +268,7 @@ impl LightDispatcher {
match nonce_future { match nonce_future {
Some(x) => Some(x) =>
x.map(|acc| acc.map_or_else(Default::default, |acc| acc.nonce)) x.map(|acc| acc.nonce)
.map_err(|_| errors::no_light_peers()) .map_err(|_| errors::no_light_peers())
.boxed(), .boxed(),
None => future::err(errors::network_disabled()).boxed() None => future::err(errors::network_disabled()).boxed()

View File

@ -173,12 +173,15 @@ impl EthClient {
Some(hdr) => hdr, Some(hdr) => hdr,
}; };
sync.with_context(|ctx| on_demand.account(ctx, request::Account { let maybe_fut = sync.with_context(|ctx| on_demand.account(ctx, request::Account {
header: header, header: header,
address: address, address: address,
})) }));
.map(|x| x.map_err(err_premature_cancel).boxed())
.unwrap_or_else(|| future::err(errors::network_disabled()).boxed()) match maybe_fut {
Some(fut) => fut.map(Some).map_err(err_premature_cancel).boxed(),
None => future::err(errors::network_disabled()).boxed(),
}
}).boxed() }).boxed()
} }