diff --git a/js-old/src/redux/store.js b/js-old/src/redux/store.js index af506b0e9..9627e9ddc 100644 --- a/js-old/src/redux/store.js +++ b/js-old/src/redux/store.js @@ -65,15 +65,15 @@ export default function (api, browserHistory, forEmbed = false) { .then(() => console.log('v1: started Status Provider')) .then(() => console.log('v1: starting Personal Provider...')) - .then(() => PersonalProvider.start()) + .then(() => withTimeoutForLight('personal', PersonalProvider.start(), store)) .then(() => console.log('v1: started Personal Provider')) .then(() => console.log('v1: starting Balances Provider...')) - .then(() => BalancesProvider.start()) + .then(() => withTimeoutForLight('balances', BalancesProvider.start(), store)) .then(() => console.log('v1: started Balances Provider')) .then(() => console.log('v1: starting Tokens Provider...')) - .then(() => TokensProvider.start()) + .then(() => withTimeoutForLight('tokens', TokensProvider.start(), store)) .then(() => console.log('v1: started Tokens Provider')); }; @@ -97,3 +97,39 @@ export default function (api, browserHistory, forEmbed = false) { return store; } + +function withTimeoutForLight (id, promise, store) { + const { nodeKind } = store.getState().nodeStatus; + const isLightNode = nodeKind.capability !== 'full'; + + if (!isLightNode) { + // make sure that no values are passed + return promise.then(() => {}); + } + + return new Promise((resolve, reject) => { + let isResolved = false; + const doResolve = () => { + if (!isResolved) { + isResolved = true; + resolve(); + } + }; + const timeout = setTimeout(() => { + console.warn(`Resolving ${id} by timeout.`); + doResolve(); + }, 1000); + + promise + .then(() => { + clearTimeout(timeout); + doResolve(); + }) + .catch(err => { + clearTimeout(timeout); + if (!isResolved) { + reject(err); + } + }); + }); +} diff --git a/rpc/src/v1/helpers/light_fetch.rs b/rpc/src/v1/helpers/light_fetch.rs index 1099102c3..7746aaef8 100644 --- a/rpc/src/v1/helpers/light_fetch.rs +++ b/rpc/src/v1/helpers/light_fetch.rs @@ -146,19 +146,30 @@ impl LightFetch { Err(e) => return Box::new(future::err(e)), }; - let maybe_future = self.sync.with_context(move |ctx| { - Box::new(self.on_demand.request_raw(ctx, reqs) - .expect("all back-references known to be valid; qed") - .map(|res| extract_header(&res, header_ref) - .expect("these responses correspond to requests that header_ref belongs to. \ - therefore it will not fail; qed")) - .map_err(errors::on_demand_cancel)) - }); - match maybe_future { - Some(recv) => recv, - None => Box::new(future::err(errors::network_disabled())) - } + self.send_requests(reqs, |res| + extract_header(&res, header_ref) + .expect("these responses correspond to requests that header_ref belongs to \ + therefore it will not fail; qed") + ) + } + + /// Helper for getting contract code at a given block. + pub fn code(&self, address: Address, id: BlockId) -> BoxFuture> { + let mut reqs = Vec::new(); + let header_ref = match self.make_header_requests(id, &mut reqs) { + Ok(r) => r, + Err(e) => return Box::new(future::err(e)), + }; + + reqs.push(request::Account { header: header_ref.clone(), address: address }.into()); + let account_idx = reqs.len() - 1; + reqs.push(request::Code { header: header_ref, code_hash: Field::back_ref(account_idx, 0) }.into()); + + self.send_requests(reqs, |mut res| match res.pop() { + Some(OnDemandResponse::Code(code)) => code, + _ => panic!("responses correspond directly with requests in amount and type; qed"), + }) } /// Helper for getting account info at a given block. @@ -172,20 +183,10 @@ impl LightFetch { reqs.push(request::Account { header: header_ref, address: address }.into()); - let maybe_future = self.sync.with_context(move |ctx| { - Box::new(self.on_demand.request_raw(ctx, reqs) - .expect("all back-references known to be valid; qed") - .map(|mut res| match res.pop() { - Some(OnDemandResponse::Account(acc)) => acc, - _ => panic!("responses correspond directly with requests in amount and type; qed"), - }) - .map_err(errors::on_demand_cancel)) - }); - - match maybe_future { - Some(recv) => recv, - None => Box::new(future::err(errors::network_disabled())) - } + self.send_requests(reqs, |mut res|match res.pop() { + Some(OnDemandResponse::Account(acc)) => acc, + _ => panic!("responses correspond directly with requests in amount and type; qed"), + }) } /// Helper for getting proved execution. @@ -276,20 +277,10 @@ impl LightFetch { reqs.push(request::Body(header_ref).into()); - let maybe_future = self.sync.with_context(move |ctx| { - Box::new(self.on_demand.request_raw(ctx, reqs) - .expect(NO_INVALID_BACK_REFS) - .map(|mut res| match res.pop() { - Some(OnDemandResponse::Body(b)) => b, - _ => panic!("responses correspond directly with requests in amount and type; qed"), - }) - .map_err(errors::on_demand_cancel)) - }); - - match maybe_future { - Some(recv) => recv, - None => Box::new(future::err(errors::network_disabled())) - } + self.send_requests(reqs, |mut res| match res.pop() { + Some(OnDemandResponse::Body(b)) => b, + _ => panic!("responses correspond directly with requests in amount and type; qed"), + }) } /// Get the block receipts. Fails on unknown block ID. @@ -302,20 +293,10 @@ impl LightFetch { reqs.push(request::BlockReceipts(header_ref).into()); - let maybe_future = self.sync.with_context(move |ctx| { - Box::new(self.on_demand.request_raw(ctx, reqs) - .expect(NO_INVALID_BACK_REFS) - .map(|mut res| match res.pop() { - Some(OnDemandResponse::Receipts(b)) => b, - _ => panic!("responses correspond directly with requests in amount and type; qed"), - }) - .map_err(errors::on_demand_cancel)) - }); - - match maybe_future { - Some(recv) => recv, - None => Box::new(future::err(errors::network_disabled())) - } + self.send_requests(reqs, |mut res| match res.pop() { + Some(OnDemandResponse::Receipts(b)) => b, + _ => panic!("responses correspond directly with requests in amount and type; qed"), + }) } /// Get transaction logs @@ -432,6 +413,23 @@ impl LightFetch { Either::B(extract_transaction) })) } + + fn send_requests(&self, reqs: Vec, parse_response: F) -> BoxFuture where + F: FnOnce(Vec) -> T + Send + 'static, + T: Send + 'static, + { + let maybe_future = self.sync.with_context(move |ctx| { + Box::new(self.on_demand.request_raw(ctx, reqs) + .expect(NO_INVALID_BACK_REFS) + .map(parse_response) + .map_err(errors::on_demand_cancel)) + }); + + match maybe_future { + Some(recv) => recv, + None => Box::new(future::err(errors::network_disabled())) + } + } } #[derive(Clone)] diff --git a/rpc/src/v1/impls/light/eth.rs b/rpc/src/v1/impls/light/eth.rs index af93b2b49..7a5fb2886 100644 --- a/rpc/src/v1/impls/light/eth.rs +++ b/rpc/src/v1/impls/light/eth.rs @@ -349,8 +349,8 @@ impl Eth for EthClient { })) } - fn code_at(&self, _address: RpcH160, _num: Trailing) -> BoxFuture { - Box::new(future::err(errors::unimplemented(None))) + fn code_at(&self, address: RpcH160, num: Trailing) -> BoxFuture { + Box::new(self.fetcher().code(address.into(), num.unwrap_or_default().into()).map(Into::into)) } fn send_raw_transaction(&self, raw: Bytes) -> Result { diff --git a/rpc/src/v1/impls/light/parity.rs b/rpc/src/v1/impls/light/parity.rs index 925919e5d..060d7288b 100644 --- a/rpc/src/v1/impls/light/parity.rs +++ b/rpc/src/v1/impls/light/parity.rs @@ -208,7 +208,12 @@ impl Parity for ParityClient { } fn registry_address(&self) -> Result> { - Err(errors::light_unimplemented(None)) + let reg = self.light_dispatch.client.engine().params().registrar; + if reg == Default::default() { + Ok(None) + } else { + Ok(Some(reg.into())) + } } fn rpc_settings(&self) -> Result {