Light client RPCs (#7603)
* Implement registrar. * Implement eth_getCode * Don't wait for providers. * Don't wait for providers. * Fix linting and wasm tests.
This commit is contained in:
parent
d4861f0a29
commit
99dbc68276
@ -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);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -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<Vec<u8>> {
|
||||
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<T, F>(&self, reqs: Vec<OnDemandRequest>, parse_response: F) -> BoxFuture<T> where
|
||||
F: FnOnce(Vec<OnDemandResponse>) -> 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)]
|
||||
|
@ -349,8 +349,8 @@ impl<T: LightChainClient + 'static> Eth for EthClient<T> {
|
||||
}))
|
||||
}
|
||||
|
||||
fn code_at(&self, _address: RpcH160, _num: Trailing<BlockNumber>) -> BoxFuture<Bytes> {
|
||||
Box::new(future::err(errors::unimplemented(None)))
|
||||
fn code_at(&self, address: RpcH160, num: Trailing<BlockNumber>) -> BoxFuture<Bytes> {
|
||||
Box::new(self.fetcher().code(address.into(), num.unwrap_or_default().into()).map(Into::into))
|
||||
}
|
||||
|
||||
fn send_raw_transaction(&self, raw: Bytes) -> Result<RpcH256> {
|
||||
|
@ -208,7 +208,12 @@ impl Parity for ParityClient {
|
||||
}
|
||||
|
||||
fn registry_address(&self) -> Result<Option<H160>> {
|
||||
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<RpcSettings> {
|
||||
|
Loading…
Reference in New Issue
Block a user