fix(light): make OnDemand
generic instead of using the concrete type (#10514)
* ethcore: add clique engine (#9981) * fix broken sync * correct seal fields * ethcore: fix comment * parity: remove duplicate params * clique: fix whitespaces * ethcore: fix goerli chain spec * refactor signer_snapshot into pending/finalized state * move close_block_extra_data after seal is applied * refactor most of the logic into the signer_snapshot * clique: refactor locking logic out of the consensus engine interface * Fix jsonspec and add an unittest * Replace space with tabs * Unbroke sync * Fix broken sync * 1/2 state tracking without votes * 2/2 implement vote tracking * ci: use travis for goerli * ci: setup a clique network * ci: sync a görli node * add clique deploy script * ci: fix paths in clique deploy script * ci: use docker compose * ci: fix travis job names * ci: fix build deps * ci: massively reduce tests * Revert "ci: massively reduce tests" This reverts commit 6369f0b069ed2607a7e9f2e1d85489bacdc43384. * ci: run cargo test directly * ci: separate build and test stages * ci: cache rust installation * ci: simplify ci stages * ci: make clique deploy script executable * ci: shutdown goerli sync after 20min * ci: remove slow sync stage * ci: use timeout to finish jobs * ci: fix build path * ci: use absolute paths to end this confusion * ci: add geth and parity to path * ci: be more verbose * ci: allow for more relaxed caching timeout * ci: update repositories for custom ppa * ci: fix typo in file name * ci: fix docker compose file * ci: add ethkey to docker * ci: make sure deploy script is up to date with upstream * ci: stop docker container after certain time * ci: force superuser to update permissions on docker files * ci: reduce run time of script to ~30 min * ci: remove duplicate caching in travis * remove trace statements * clique: add more validation involving the recent signer list * ethcore: enable constantinople for rinkeby * ethcore: fix whitespaces in rinkeby spec * ethcore: reformat goerli.json * Revert "ci: remove duplicate caching in travis" This reverts commit a562838d3d194d37f9871dcbe00b783637978f89. * tmp commit * another tmp commit * it builds! * add sealing capabilities * add seal_header hook to allow separation of block seal/importing code paths * clique: remove populate_from_parent. * add panic * make turn delay random * initialize OpenBlock properly in 'enact' * misc: remove duplicate lines * misc: fix license headers * misc: convert spaces to tabs * misc: fix tabs * Update Cargo.toml * Update Cargo.toml * Update Cargo.toml * clique: ensure validator restores state before trying to seal * clique: make 'state' return an Error. Make some error messages more clear * Fix compile error after rebase & toolchain upgrade * fix a bunch of import warnings * Refactor code * Fix permissions * Refactoring syncing * Implement full validator checks * Refactor util functions to seperate file * mining 1 * ethcore: add chainspec for kotti * ethcore: rename pre-goerli configs * ethcore: load kotti chain spec * cli: add kotti to params * Implement working local sealing * making sealing & syncing work together * Relax timestamp checking * ethcore: prepare for the real goerli to launch * Implement NOTURN wiggle properly & cleanupnup warnings * Implement vote casting * Update docs & skip signing if no signer * Optimize step-service interval * Record state on local sealed block * Fix script filemode * Cleaning up codebase * restore enact trace logging * Delete clique.sh and move sync.sh * remove travis.yml * Remove dead code * Cleanup compile warning * address review comments * adding more comments and removing unwrap() * ci: remove sync script * Address review comments * fix compile error * adding better debugging for timing * Implement an dedicated thread for sealing timing * fix(add helper for timestamp overflows) (#10330) * fix(add helper timestamp overflows) * fix(simplify code) * fix(make helper private) * snap: official image / test (#10168) * official image / test * fix / test * bit more necromancy * fix paths * add source bin/df /test * add source bin/df /test2 * something w paths /test * something w paths /test * add source-type /test * show paths /test * copy plugin /test * plugin -> nil * install rhash * no questions while installing rhash * publish snap only for release * fix(docker): fix not receives SIGINT (#10059) * fix(docker): fix not receives SIGINT * fix: update with reviews * update with review * update * update * Don't add discovery initiators to the node table (#10305) * Don't add discovery initiators to the node table * Use enums for tracking state of the nodes in discovery * Dont try to ping ourselves * Fix minor nits * Update timeouts when observing an outdated node * Extracted update_bucket_record from update_node * Fixed typo * Fix two final nits from @todr * change docker image based on debian instead of ubuntu due to the chan… (#10336) * change docker image based on debian instead of ubuntu due to the changes of the build container * role back docker build image and docker deploy image to ubuntu:xenial based (#10338) * Bundle protocol and packet_id together in chain sync (#10315) Define a new `enum` where devp2p subprotocol packet ids (currently eth and par) are defined. Additionally provide functionality to query id value and protocol of a given id object. * snap: prefix version and populate candidate channel (#10343) * snap: populate candidate releases with beta snaps to avoid stale channel * snap: prefix version with v* * addressing review comments * engine: fix copyright header * scripts: restore permissions on sign command * ethcore: enforce tabs * ethcore: enforce tabs * ethcore: enforce tabs * addressing comments * addressing comments * addressing more comments * addressing more comments * addressing more comments * addressing more comments * addressing more comments * json-spec: fix clique epoch to non-zero u64 * ci: enable travis for parity goerli * ci: don't separate build and test step * ci: don't run c++ tests on travis * ci: simplify cargo test to squeeze into travis timeout * ci: don't run tests on travis at all * style(fixes) * fix(add tests) * fix(recent_signer bug) * fix(complete all tests) * fix(nits) * fix(simplify asserts) * fix(cliqueState): simplify code * fix(nits) * docs(comments what's need to fixed) * fix(revert unintended changes) * fix(tests) * fix(logs): voting logs * fix(readability + more logs) * fix(sync) * docs(add missing licens header) * fix(log): info! -> trace! * docs(fix nits) + fix(remove assert) * perf(use counter instead of vec) * fix(remove needless block in match) * fix(faulty comment) * grumbles(docs for tests) * fix(nits) * fix(revert_vote): only remove vote when votes == 0 * fix(vote counter): checked arithmetics * fix(simplify tests) * fix(nits) * fix(clique): err types * fix(clique utils): make use of errors * fix(cleanup nits) * fix(clique sealing): don't read state no signer * fix(replace Vec<Signers> with BTreeSet<Signers>) * fix(tests): BTreeSet and more generic helpers * fix(nits) * fix(ethcore_block_seal): remove needless `Box` * fix(faulty log): info -> trace * fix(checked SystemTime): prevent SystemTime panics * style(chain cfg): space after `:` * style(fn enact): fix whitespace * docs(clique): StepService * docs(nit): fix faulty comment * docs(fix typo) * style(fix bad indentation) * fix(bad regex match) * grumble(on_seal_block): make `&mut` to avoid clone * docs(on_seal_block): fix faulty documentation * Delete .travis.yml * docs: remove eth hf references in spec * Update client.rs * fix(nits) * fix(clique step): `RwLock` -> `AtomicBool` * fix(clique): use `Duration::as_millis` * Clean up some Clique documentation * Add trace information to eth_estimateGas (#10519) * Add trace information to eth_estimateGas * replace unwrap better version * change vm::Error formatter to more user-friendly * remove extra error format * use map_or instead sequence of map/unwrap_or * fix(light/on_demand): extract as a trait * fix(grumble): OnDemand remove needless trait bound
This commit is contained in:
parent
7d26a82232
commit
407de5e8c4
@ -94,6 +94,24 @@ pub mod error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Public interface for performing network requests `OnDemand`
|
||||||
|
pub trait OnDemandRequester: Send + Sync {
|
||||||
|
/// Submit a strongly-typed batch of requests.
|
||||||
|
///
|
||||||
|
/// Fails if back-reference are not coherent.
|
||||||
|
fn request<T>(&self, ctx: &BasicContext, requests: T) -> Result<OnResponses<T>, basic_request::NoSuchOutput>
|
||||||
|
where
|
||||||
|
T: request::RequestAdapter;
|
||||||
|
|
||||||
|
/// Submit a vector of requests to be processed together.
|
||||||
|
///
|
||||||
|
/// Fails if back-references are not coherent.
|
||||||
|
/// The returned vector of responses will correspond to the requests exactly.
|
||||||
|
fn request_raw(&self, ctx: &BasicContext, requests: Vec<Request>)
|
||||||
|
-> Result<Receiver<PendingResponse>, basic_request::NoSuchOutput>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// relevant peer info.
|
// relevant peer info.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
struct Peer {
|
struct Peer {
|
||||||
@ -355,6 +373,74 @@ pub struct OnDemand {
|
|||||||
request_number_of_consecutive_errors: usize
|
request_number_of_consecutive_errors: usize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl OnDemandRequester for OnDemand {
|
||||||
|
fn request_raw(&self, ctx: &BasicContext, requests: Vec<Request>)
|
||||||
|
-> Result<Receiver<PendingResponse>, basic_request::NoSuchOutput>
|
||||||
|
{
|
||||||
|
let (sender, receiver) = oneshot::channel();
|
||||||
|
if requests.is_empty() {
|
||||||
|
assert!(sender.send(Ok(Vec::new())).is_ok(), "receiver still in scope; qed");
|
||||||
|
return Ok(receiver);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut builder = basic_request::Builder::default();
|
||||||
|
|
||||||
|
let responses = Vec::with_capacity(requests.len());
|
||||||
|
|
||||||
|
let mut header_producers = HashMap::new();
|
||||||
|
for (i, request) in requests.into_iter().enumerate() {
|
||||||
|
let request = CheckedRequest::from(request);
|
||||||
|
|
||||||
|
// ensure that all requests needing headers will get them.
|
||||||
|
if let Some((idx, field)) = request.needs_header() {
|
||||||
|
// a request chain with a header back-reference is valid only if it both
|
||||||
|
// points to a request that returns a header and has the same back-reference
|
||||||
|
// for the block hash.
|
||||||
|
match header_producers.get(&idx) {
|
||||||
|
Some(ref f) if &field == *f => {}
|
||||||
|
_ => return Err(basic_request::NoSuchOutput),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let CheckedRequest::HeaderByHash(ref req, _) = request {
|
||||||
|
header_producers.insert(i, req.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.push(request)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let requests = builder.build();
|
||||||
|
let net_requests = requests.clone().map_requests(|req| req.into_net_request());
|
||||||
|
let capabilities = guess_capabilities(requests.requests());
|
||||||
|
|
||||||
|
self.submit_pending(ctx, Pending {
|
||||||
|
requests,
|
||||||
|
net_requests,
|
||||||
|
required_capabilities: capabilities,
|
||||||
|
responses,
|
||||||
|
sender,
|
||||||
|
request_guard: RequestGuard::new(
|
||||||
|
self.request_number_of_consecutive_errors as u32,
|
||||||
|
self.request_backoff_rounds_max,
|
||||||
|
self.request_backoff_start,
|
||||||
|
self.request_backoff_max,
|
||||||
|
),
|
||||||
|
response_guard: ResponseGuard::new(self.response_time_window),
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(receiver)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request<T>(&self, ctx: &BasicContext, requests: T) -> Result<OnResponses<T>, basic_request::NoSuchOutput>
|
||||||
|
where T: request::RequestAdapter
|
||||||
|
{
|
||||||
|
self.request_raw(ctx, requests.make_requests()).map(|recv| OnResponses {
|
||||||
|
receiver: recv,
|
||||||
|
_marker: PhantomData,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
impl OnDemand {
|
impl OnDemand {
|
||||||
|
|
||||||
/// Create a new `OnDemand` service with the given cache.
|
/// Create a new `OnDemand` service with the given cache.
|
||||||
@ -415,77 +501,6 @@ impl OnDemand {
|
|||||||
me
|
me
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Submit a vector of requests to be processed together.
|
|
||||||
///
|
|
||||||
/// Fails if back-references are not coherent.
|
|
||||||
/// The returned vector of responses will correspond to the requests exactly.
|
|
||||||
pub fn request_raw(&self, ctx: &BasicContext, requests: Vec<Request>)
|
|
||||||
-> Result<Receiver<PendingResponse>, basic_request::NoSuchOutput>
|
|
||||||
{
|
|
||||||
let (sender, receiver) = oneshot::channel();
|
|
||||||
if requests.is_empty() {
|
|
||||||
assert!(sender.send(Ok(Vec::new())).is_ok(), "receiver still in scope; qed");
|
|
||||||
return Ok(receiver);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut builder = basic_request::Builder::default();
|
|
||||||
|
|
||||||
let responses = Vec::with_capacity(requests.len());
|
|
||||||
|
|
||||||
let mut header_producers = HashMap::new();
|
|
||||||
for (i, request) in requests.into_iter().enumerate() {
|
|
||||||
let request = CheckedRequest::from(request);
|
|
||||||
|
|
||||||
// ensure that all requests needing headers will get them.
|
|
||||||
if let Some((idx, field)) = request.needs_header() {
|
|
||||||
// a request chain with a header back-reference is valid only if it both
|
|
||||||
// points to a request that returns a header and has the same back-reference
|
|
||||||
// for the block hash.
|
|
||||||
match header_producers.get(&idx) {
|
|
||||||
Some(ref f) if &field == *f => {}
|
|
||||||
_ => return Err(basic_request::NoSuchOutput),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let CheckedRequest::HeaderByHash(ref req, _) = request {
|
|
||||||
header_producers.insert(i, req.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.push(request)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let requests = builder.build();
|
|
||||||
let net_requests = requests.clone().map_requests(|req| req.into_net_request());
|
|
||||||
let capabilities = guess_capabilities(requests.requests());
|
|
||||||
|
|
||||||
self.submit_pending(ctx, Pending {
|
|
||||||
requests,
|
|
||||||
net_requests,
|
|
||||||
required_capabilities: capabilities,
|
|
||||||
responses,
|
|
||||||
sender,
|
|
||||||
request_guard: RequestGuard::new(
|
|
||||||
self.request_number_of_consecutive_errors as u32,
|
|
||||||
self.request_backoff_rounds_max,
|
|
||||||
self.request_backoff_start,
|
|
||||||
self.request_backoff_max,
|
|
||||||
),
|
|
||||||
response_guard: ResponseGuard::new(self.response_time_window),
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(receiver)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Submit a strongly-typed batch of requests.
|
|
||||||
///
|
|
||||||
/// Fails if back-reference are not coherent.
|
|
||||||
pub fn request<T>(&self, ctx: &BasicContext, requests: T) -> Result<OnResponses<T>, basic_request::NoSuchOutput>
|
|
||||||
where T: request::RequestAdapter
|
|
||||||
{
|
|
||||||
self.request_raw(ctx, requests.make_requests()).map(|recv| OnResponses {
|
|
||||||
receiver: recv,
|
|
||||||
_marker: PhantomData,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// maybe dispatch pending requests.
|
// maybe dispatch pending requests.
|
||||||
// sometimes
|
// sometimes
|
||||||
|
@ -29,7 +29,7 @@ use std::sync::Arc;
|
|||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
||||||
use super::{request, OnDemand, Peer, HeaderRef};
|
use super::{request, OnDemand, OnDemandRequester, Peer, HeaderRef};
|
||||||
|
|
||||||
// useful contexts to give the service.
|
// useful contexts to give the service.
|
||||||
enum Context {
|
enum Context {
|
||||||
|
@ -27,7 +27,7 @@ use futures::{future, Future};
|
|||||||
use futures::future::Either;
|
use futures::future::Either;
|
||||||
|
|
||||||
use light::client::fetch::ChainDataFetcher;
|
use light::client::fetch::ChainDataFetcher;
|
||||||
use light::on_demand::{request, OnDemand};
|
use light::on_demand::{request, OnDemand, OnDemandRequester};
|
||||||
|
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use ethereum_types::H256;
|
use ethereum_types::H256;
|
||||||
|
@ -24,7 +24,7 @@ use sync::{LightSync, LightNetworkDispatcher};
|
|||||||
use io::{IoContext, IoHandler, TimerToken};
|
use io::{IoContext, IoHandler, TimerToken};
|
||||||
|
|
||||||
use light::client::LightChainClient;
|
use light::client::LightChainClient;
|
||||||
use light::on_demand::{request, OnDemand};
|
use light::on_demand::{request, OnDemand, OnDemandRequester};
|
||||||
use light::TransactionQueue;
|
use light::TransactionQueue;
|
||||||
|
|
||||||
use futures::{future, Future};
|
use futures::{future, Future};
|
||||||
|
@ -20,7 +20,7 @@ use ethereum_types::{H256, Address, U256};
|
|||||||
use light::TransactionQueue as LightTransactionQueue;
|
use light::TransactionQueue as LightTransactionQueue;
|
||||||
use light::cache::Cache as LightDataCache;
|
use light::cache::Cache as LightDataCache;
|
||||||
use light::client::LightChainClient;
|
use light::client::LightChainClient;
|
||||||
use light::on_demand::{request, OnDemand};
|
use light::on_demand::{request, OnDemandRequester};
|
||||||
use parking_lot::{Mutex, RwLock};
|
use parking_lot::{Mutex, RwLock};
|
||||||
use stats::Corpus;
|
use stats::Corpus;
|
||||||
use sync::{LightSyncProvider, LightNetworkDispatcher, ManageNetwork};
|
use sync::{LightSyncProvider, LightNetworkDispatcher, ManageNetwork};
|
||||||
@ -37,13 +37,17 @@ use v1::types::{RichRawTransaction as RpcRichRawTransaction,};
|
|||||||
use super::{Dispatcher, Accounts, SignWith, PostSign};
|
use super::{Dispatcher, Accounts, SignWith, PostSign};
|
||||||
|
|
||||||
/// Dispatcher for light clients -- fetches default gas price, next nonce, etc. from network.
|
/// Dispatcher for light clients -- fetches default gas price, next nonce, etc. from network.
|
||||||
pub struct LightDispatcher<S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static> {
|
pub struct LightDispatcher<S, OD>
|
||||||
|
where
|
||||||
|
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static,
|
||||||
|
OD: OnDemandRequester + 'static
|
||||||
|
{
|
||||||
/// Sync service.
|
/// Sync service.
|
||||||
pub sync: Arc<S>,
|
pub sync: Arc<S>,
|
||||||
/// Header chain client.
|
/// Header chain client.
|
||||||
pub client: Arc<LightChainClient>,
|
pub client: Arc<LightChainClient>,
|
||||||
/// On-demand request service.
|
/// On-demand request service.
|
||||||
pub on_demand: Arc<OnDemand>,
|
pub on_demand: Arc<OD>,
|
||||||
/// Data cache.
|
/// Data cache.
|
||||||
pub cache: Arc<Mutex<LightDataCache>>,
|
pub cache: Arc<Mutex<LightDataCache>>,
|
||||||
/// Transaction queue.
|
/// Transaction queue.
|
||||||
@ -54,9 +58,10 @@ pub struct LightDispatcher<S: LightSyncProvider + LightNetworkDispatcher + Manag
|
|||||||
pub gas_price_percentile: usize,
|
pub gas_price_percentile: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> LightDispatcher<S>
|
impl<S, OD> LightDispatcher<S, OD>
|
||||||
where
|
where
|
||||||
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static
|
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static,
|
||||||
|
OD: OnDemandRequester + 'static
|
||||||
{
|
{
|
||||||
/// Create a new `LightDispatcher` from its requisite parts.
|
/// Create a new `LightDispatcher` from its requisite parts.
|
||||||
///
|
///
|
||||||
@ -64,7 +69,7 @@ where
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
sync: Arc<S>,
|
sync: Arc<S>,
|
||||||
client: Arc<LightChainClient>,
|
client: Arc<LightChainClient>,
|
||||||
on_demand: Arc<OnDemand>,
|
on_demand: Arc<OD>,
|
||||||
cache: Arc<Mutex<LightDataCache>>,
|
cache: Arc<Mutex<LightDataCache>>,
|
||||||
transaction_queue: Arc<RwLock<LightTransactionQueue>>,
|
transaction_queue: Arc<RwLock<LightTransactionQueue>>,
|
||||||
nonces: Arc<Mutex<nonce::Reservations>>,
|
nonces: Arc<Mutex<nonce::Reservations>>,
|
||||||
@ -117,9 +122,10 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> Clone for LightDispatcher<S>
|
impl<S, OD> Clone for LightDispatcher<S, OD>
|
||||||
where
|
where
|
||||||
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static
|
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static,
|
||||||
|
OD: OnDemandRequester + 'static
|
||||||
{
|
{
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -134,9 +140,10 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> Dispatcher for LightDispatcher<S>
|
impl<S, OD> Dispatcher for LightDispatcher<S, OD>
|
||||||
where
|
where
|
||||||
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static
|
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static,
|
||||||
|
OD: OnDemandRequester + 'static
|
||||||
{
|
{
|
||||||
// Ignore the `force_nonce` flag in order to always query the network when fetching the nonce and
|
// Ignore the `force_nonce` flag in order to always query the network when fetching the nonce and
|
||||||
// the account state. If the nonce is specified in the transaction use that nonce instead but do the
|
// the account state. If the nonce is specified in the transaction use that nonce instead but do the
|
||||||
@ -239,12 +246,16 @@ where
|
|||||||
|
|
||||||
/// Get a recent gas price corpus.
|
/// Get a recent gas price corpus.
|
||||||
// TODO: this could be `impl Trait`.
|
// TODO: this could be `impl Trait`.
|
||||||
pub fn fetch_gas_price_corpus<S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static>(
|
pub fn fetch_gas_price_corpus<S, OD>(
|
||||||
sync: Arc<S>,
|
sync: Arc<S>,
|
||||||
client: Arc<LightChainClient>,
|
client: Arc<LightChainClient>,
|
||||||
on_demand: Arc<OnDemand>,
|
on_demand: Arc<OD>,
|
||||||
cache: Arc<Mutex<LightDataCache>>,
|
cache: Arc<Mutex<LightDataCache>>,
|
||||||
) -> BoxFuture<Corpus<U256>> {
|
) -> BoxFuture<Corpus<U256>>
|
||||||
|
where
|
||||||
|
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static,
|
||||||
|
OD: OnDemandRequester + 'static
|
||||||
|
{
|
||||||
const GAS_PRICE_SAMPLE_SIZE: usize = 100;
|
const GAS_PRICE_SAMPLE_SIZE: usize = 100;
|
||||||
|
|
||||||
if let Some(cached) = { cache.lock().gas_price_corpus() } {
|
if let Some(cached) = { cache.lock().gas_price_corpus() } {
|
||||||
|
@ -35,16 +35,15 @@ use light::cache::Cache;
|
|||||||
use light::client::LightChainClient;
|
use light::client::LightChainClient;
|
||||||
use light::{cht, MAX_HEADERS_PER_REQUEST};
|
use light::{cht, MAX_HEADERS_PER_REQUEST};
|
||||||
use light::on_demand::{
|
use light::on_demand::{
|
||||||
request, OnDemand, HeaderRef, Request as OnDemandRequest,
|
request, OnDemandRequester, HeaderRef, Request as OnDemandRequest,
|
||||||
Response as OnDemandResponse, ExecutionResult,
|
Response as OnDemandResponse, ExecutionResult,
|
||||||
};
|
};
|
||||||
use light::on_demand::error::Error as OnDemandError;
|
use light::on_demand::error::Error as OnDemandError;
|
||||||
use light::request::Field;
|
use light::request::Field;
|
||||||
|
|
||||||
|
|
||||||
use sync::{LightNetworkDispatcher, ManageNetwork, LightSyncProvider};
|
use sync::{LightNetworkDispatcher, ManageNetwork, LightSyncProvider};
|
||||||
|
|
||||||
use ethereum_types::{U256, Address};
|
use ethereum_types::Address;
|
||||||
use hash::H256;
|
use hash::H256;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use fastmap::H256FastMap;
|
use fastmap::H256FastMap;
|
||||||
@ -57,9 +56,10 @@ use v1::types::{BlockNumber, CallRequest, Log, Transaction};
|
|||||||
const NO_INVALID_BACK_REFS_PROOF: &str = "Fails only on invalid back-references; back-references here known to be valid; qed";
|
const NO_INVALID_BACK_REFS_PROOF: &str = "Fails only on invalid back-references; back-references here known to be valid; qed";
|
||||||
const WRONG_RESPONSE_AMOUNT_TYPE_PROOF: &str = "responses correspond directly with requests in amount and type; qed";
|
const WRONG_RESPONSE_AMOUNT_TYPE_PROOF: &str = "responses correspond directly with requests in amount and type; qed";
|
||||||
|
|
||||||
pub fn light_all_transactions<S>(dispatch: &Arc<dispatch::LightDispatcher<S>>) -> impl Iterator<Item=PendingTransaction>
|
pub fn light_all_transactions<S, OD>(dispatch: &Arc<dispatch::LightDispatcher<S, OD>>) -> impl Iterator<Item=PendingTransaction>
|
||||||
where
|
where
|
||||||
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static
|
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static,
|
||||||
|
OD: OnDemandRequester + 'static
|
||||||
{
|
{
|
||||||
let txq = dispatch.transaction_queue.read();
|
let txq = dispatch.transaction_queue.read();
|
||||||
let chain_info = dispatch.client.chain_info();
|
let chain_info = dispatch.client.chain_info();
|
||||||
@ -71,12 +71,15 @@ where
|
|||||||
|
|
||||||
/// Helper for fetching blockchain data either from the light client or the network
|
/// Helper for fetching blockchain data either from the light client or the network
|
||||||
/// as necessary.
|
/// as necessary.
|
||||||
pub struct LightFetch<S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static>
|
pub struct LightFetch<S, OD>
|
||||||
|
where
|
||||||
|
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static,
|
||||||
|
OD: OnDemandRequester + 'static
|
||||||
{
|
{
|
||||||
/// The light client.
|
/// The light client.
|
||||||
pub client: Arc<LightChainClient>,
|
pub client: Arc<LightChainClient>,
|
||||||
/// The on-demand request service.
|
/// The on-demand request service.
|
||||||
pub on_demand: Arc<OnDemand>,
|
pub on_demand: Arc<OD>,
|
||||||
/// Handle to the network.
|
/// Handle to the network.
|
||||||
pub sync: Arc<S>,
|
pub sync: Arc<S>,
|
||||||
/// The light data cache.
|
/// The light data cache.
|
||||||
@ -85,9 +88,10 @@ pub struct LightFetch<S: LightSyncProvider + LightNetworkDispatcher + ManageNetw
|
|||||||
pub gas_price_percentile: usize,
|
pub gas_price_percentile: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> Clone for LightFetch<S>
|
impl<S, OD> Clone for LightFetch<S, OD>
|
||||||
where
|
where
|
||||||
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static
|
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static,
|
||||||
|
OD: OnDemandRequester + 'static
|
||||||
{
|
{
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -136,9 +140,10 @@ fn extract_header(res: &[OnDemandResponse], header: HeaderRef) -> Option<encoded
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> LightFetch<S>
|
impl<S, OD> LightFetch<S, OD>
|
||||||
where
|
where
|
||||||
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static
|
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static,
|
||||||
|
OD: OnDemandRequester + 'static
|
||||||
{
|
{
|
||||||
// push the necessary requests onto the request chain to get the header by the given ID.
|
// push the necessary requests onto the request chain to get the header by the given ID.
|
||||||
// yield a header reference which other requests can use.
|
// yield a header reference which other requests can use.
|
||||||
@ -277,7 +282,7 @@ where
|
|||||||
action: req.to.map_or(Action::Create, Action::Call),
|
action: req.to.map_or(Action::Create, Action::Call),
|
||||||
gas: req.gas.unwrap_or_else(|| START_GAS.into()),
|
gas: req.gas.unwrap_or_else(|| START_GAS.into()),
|
||||||
gas_price,
|
gas_price,
|
||||||
value: req.value.unwrap_or_else(U256::zero),
|
value: req.value.unwrap_or_default(),
|
||||||
data: req.data.unwrap_or_default(),
|
data: req.data.unwrap_or_default(),
|
||||||
}))
|
}))
|
||||||
)
|
)
|
||||||
@ -387,7 +392,7 @@ where
|
|||||||
block_index += 1;
|
block_index += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
future::ok::<_,OnDemandError>(matches)
|
future::ok::<_, OnDemandError>(matches)
|
||||||
})
|
})
|
||||||
.map_err(errors::on_demand_error)
|
.map_err(errors::on_demand_error)
|
||||||
.map(|matches| matches.into_iter().map(|(_, v)| v).collect())
|
.map(|matches| matches.into_iter().map(|(_, v)| v).collect())
|
||||||
@ -657,22 +662,24 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ExecuteParams<S>
|
struct ExecuteParams<S, OD>
|
||||||
where
|
where
|
||||||
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static
|
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static,
|
||||||
|
OD: OnDemandRequester + 'static
|
||||||
{
|
{
|
||||||
from: Address,
|
from: Address,
|
||||||
tx: EthTransaction,
|
tx: EthTransaction,
|
||||||
hdr: encoded::Header,
|
hdr: encoded::Header,
|
||||||
env_info: ::vm::EnvInfo,
|
env_info: ::vm::EnvInfo,
|
||||||
engine: Arc<::ethcore::engines::EthEngine>,
|
engine: Arc<::ethcore::engines::EthEngine>,
|
||||||
on_demand: Arc<OnDemand>,
|
on_demand: Arc<OD>,
|
||||||
sync: Arc<S>,
|
sync: Arc<S>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> Clone for ExecuteParams<S>
|
impl<S, OD> Clone for ExecuteParams<S, OD>
|
||||||
where
|
where
|
||||||
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static
|
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static,
|
||||||
|
OD: OnDemandRequester + 'static
|
||||||
{
|
{
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -689,9 +696,10 @@ where
|
|||||||
|
|
||||||
// Has a peer execute the transaction with given params. If `gas_known` is false, this will set the `gas value` to the
|
// Has a peer execute the transaction with given params. If `gas_known` is false, this will set the `gas value` to the
|
||||||
// `required gas value` unless it exceeds the block gas limit
|
// `required gas value` unless it exceeds the block gas limit
|
||||||
fn execute_read_only_tx<S>(gas_known: bool, params: ExecuteParams<S>) -> impl Future<Item = ExecutionResult, Error = Error> + Send
|
fn execute_read_only_tx<S, OD>(gas_known: bool, params: ExecuteParams<S, OD>) -> impl Future<Item = ExecutionResult, Error = Error> + Send
|
||||||
where
|
where
|
||||||
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static
|
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static,
|
||||||
|
OD: OnDemandRequester + 'static
|
||||||
{
|
{
|
||||||
if !gas_known {
|
if !gas_known {
|
||||||
Box::new(future::loop_fn(params, |mut params| {
|
Box::new(future::loop_fn(params, |mut params| {
|
||||||
|
@ -33,7 +33,7 @@ use ethcore::client::{BlockChainClient, ChainNotify, NewBlocks, ChainRouteType,
|
|||||||
use ethereum_types::H256;
|
use ethereum_types::H256;
|
||||||
use light::cache::Cache;
|
use light::cache::Cache;
|
||||||
use light::client::{LightChainClient, LightChainNotify};
|
use light::client::{LightChainClient, LightChainNotify};
|
||||||
use light::on_demand::OnDemand;
|
use light::on_demand::OnDemandRequester;
|
||||||
use parity_runtime::Executor;
|
use parity_runtime::Executor;
|
||||||
use parking_lot::{RwLock, Mutex};
|
use parking_lot::{RwLock, Mutex};
|
||||||
|
|
||||||
@ -89,14 +89,15 @@ impl<C> EthPubSubClient<C> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> EthPubSubClient<LightFetch<S>>
|
impl<S, OD> EthPubSubClient<LightFetch<S, OD>>
|
||||||
where
|
where
|
||||||
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static
|
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static,
|
||||||
|
OD: OnDemandRequester + 'static
|
||||||
{
|
{
|
||||||
/// Creates a new `EthPubSubClient` for `LightClient`.
|
/// Creates a new `EthPubSubClient` for `LightClient`.
|
||||||
pub fn light(
|
pub fn light(
|
||||||
client: Arc<LightChainClient>,
|
client: Arc<LightChainClient>,
|
||||||
on_demand: Arc<OnDemand>,
|
on_demand: Arc<OD>,
|
||||||
sync: Arc<S>,
|
sync: Arc<S>,
|
||||||
cache: Arc<Mutex<Cache>>,
|
cache: Arc<Mutex<Cache>>,
|
||||||
executor: Executor,
|
executor: Executor,
|
||||||
@ -194,9 +195,10 @@ pub trait LightClient: Send + Sync {
|
|||||||
fn logs(&self, filter: EthFilter) -> BoxFuture<Vec<Log>>;
|
fn logs(&self, filter: EthFilter) -> BoxFuture<Vec<Log>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> LightClient for LightFetch<S>
|
impl<S, OD> LightClient for LightFetch<S, OD>
|
||||||
where
|
where
|
||||||
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static
|
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static,
|
||||||
|
OD: OnDemandRequester + 'static
|
||||||
{
|
{
|
||||||
fn block_header(&self, id: BlockId) -> Option<encoded::Header> {
|
fn block_header(&self, id: BlockId) -> Option<encoded::Header> {
|
||||||
self.client.block_header(id)
|
self.client.block_header(id)
|
||||||
|
@ -26,7 +26,7 @@ use jsonrpc_core::futures::future::Either;
|
|||||||
use light::cache::Cache as LightDataCache;
|
use light::cache::Cache as LightDataCache;
|
||||||
use light::client::LightChainClient;
|
use light::client::LightChainClient;
|
||||||
use light::{cht, TransactionQueue};
|
use light::{cht, TransactionQueue};
|
||||||
use light::on_demand::{request, OnDemand};
|
use light::on_demand::{request, OnDemandRequester};
|
||||||
|
|
||||||
use ethereum_types::{Address, H64, H160, H256, U64, U256};
|
use ethereum_types::{Address, H64, H160, H256, U64, U256};
|
||||||
use hash::{KECCAK_NULL_RLP, KECCAK_EMPTY_LIST_RLP};
|
use hash::{KECCAK_NULL_RLP, KECCAK_EMPTY_LIST_RLP};
|
||||||
@ -54,10 +54,10 @@ use sync::{LightSyncInfo, LightSyncProvider, LightNetworkDispatcher, ManageNetwo
|
|||||||
const NO_INVALID_BACK_REFS: &str = "Fails only on invalid back-references; back-references here known to be valid; qed";
|
const NO_INVALID_BACK_REFS: &str = "Fails only on invalid back-references; back-references here known to be valid; qed";
|
||||||
|
|
||||||
/// Light client `ETH` (and filter) RPC.
|
/// Light client `ETH` (and filter) RPC.
|
||||||
pub struct EthClient<C, S: LightSyncProvider + LightNetworkDispatcher + 'static> {
|
pub struct EthClient<C, S: LightSyncProvider + LightNetworkDispatcher + 'static, OD: OnDemandRequester + 'static> {
|
||||||
sync: Arc<S>,
|
sync: Arc<S>,
|
||||||
client: Arc<C>,
|
client: Arc<C>,
|
||||||
on_demand: Arc<OnDemand>,
|
on_demand: Arc<OD>,
|
||||||
transaction_queue: Arc<RwLock<TransactionQueue>>,
|
transaction_queue: Arc<RwLock<TransactionQueue>>,
|
||||||
accounts: Arc<Fn() -> Vec<Address> + Send + Sync>,
|
accounts: Arc<Fn() -> Vec<Address> + Send + Sync>,
|
||||||
cache: Arc<Mutex<LightDataCache>>,
|
cache: Arc<Mutex<LightDataCache>>,
|
||||||
@ -67,9 +67,10 @@ pub struct EthClient<C, S: LightSyncProvider + LightNetworkDispatcher + 'static>
|
|||||||
deprecation_notice: DeprecationNotice,
|
deprecation_notice: DeprecationNotice,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, S> Clone for EthClient<C, S>
|
impl<C, S, OD> Clone for EthClient<C, S, OD>
|
||||||
where
|
where
|
||||||
S: LightSyncProvider + LightNetworkDispatcher + 'static
|
S: LightSyncProvider + LightNetworkDispatcher + 'static,
|
||||||
|
OD: OnDemandRequester + 'static
|
||||||
{
|
{
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
// each instance should have its own poll manager.
|
// each instance should have its own poll manager.
|
||||||
@ -88,17 +89,18 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, S> EthClient<C, S>
|
impl<C, S, OD> EthClient<C, S, OD>
|
||||||
where
|
where
|
||||||
C: LightChainClient + 'static,
|
C: LightChainClient + 'static,
|
||||||
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static
|
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static,
|
||||||
|
OD: OnDemandRequester + 'static
|
||||||
{
|
{
|
||||||
/// Create a new `EthClient` with a handle to the light sync instance, client,
|
/// Create a new `EthClient` with a handle to the light sync instance, client,
|
||||||
/// and on-demand request service, which is assumed to be attached as a handler.
|
/// and on-demand request service, which is assumed to be attached as a handler.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
sync: Arc<S>,
|
sync: Arc<S>,
|
||||||
client: Arc<C>,
|
client: Arc<C>,
|
||||||
on_demand: Arc<OnDemand>,
|
on_demand: Arc<OD>,
|
||||||
transaction_queue: Arc<RwLock<TransactionQueue>>,
|
transaction_queue: Arc<RwLock<TransactionQueue>>,
|
||||||
accounts: Arc<Fn() -> Vec<Address> + Send + Sync>,
|
accounts: Arc<Fn() -> Vec<Address> + Send + Sync>,
|
||||||
cache: Arc<Mutex<LightDataCache>>,
|
cache: Arc<Mutex<LightDataCache>>,
|
||||||
@ -120,7 +122,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a light data fetcher instance.
|
/// Create a light data fetcher instance.
|
||||||
fn fetcher(&self) -> LightFetch<S>
|
fn fetcher(&self) -> LightFetch<S, OD>
|
||||||
{
|
{
|
||||||
LightFetch {
|
LightFetch {
|
||||||
client: self.client.clone(),
|
client: self.client.clone(),
|
||||||
@ -218,10 +220,11 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, S> Eth for EthClient<C, S>
|
impl<C, S, OD> Eth for EthClient<C, S, OD>
|
||||||
where
|
where
|
||||||
C: LightChainClient + 'static,
|
C: LightChainClient + 'static,
|
||||||
S: LightSyncInfo + LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static
|
S: LightSyncInfo + LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static,
|
||||||
|
OD: OnDemandRequester + 'static
|
||||||
{
|
{
|
||||||
type Metadata = Metadata;
|
type Metadata = Metadata;
|
||||||
|
|
||||||
@ -533,10 +536,11 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This trait implementation triggers a blanked impl of `EthFilter`.
|
// This trait implementation triggers a blanked impl of `EthFilter`.
|
||||||
impl<C, S> Filterable for EthClient<C, S>
|
impl<C, S, OD> Filterable for EthClient<C, S, OD>
|
||||||
where
|
where
|
||||||
C: LightChainClient + 'static,
|
C: LightChainClient + 'static,
|
||||||
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static
|
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static,
|
||||||
|
OD: OnDemandRequester + 'static
|
||||||
{
|
{
|
||||||
fn best_block_number(&self) -> u64 { self.client.chain_info().best_block_number }
|
fn best_block_number(&self) -> u64 { self.client.chain_info().best_block_number }
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ use ethcore_logger::RotatingLogger;
|
|||||||
|
|
||||||
use jsonrpc_core::{Result, BoxFuture};
|
use jsonrpc_core::{Result, BoxFuture};
|
||||||
use jsonrpc_core::futures::{future, Future};
|
use jsonrpc_core::futures::{future, Future};
|
||||||
|
use light::on_demand::OnDemandRequester;
|
||||||
use v1::helpers::{self, errors, ipfs, NetworkSettings, verify_signature};
|
use v1::helpers::{self, errors, ipfs, NetworkSettings, verify_signature};
|
||||||
use v1::helpers::external_signer::{SignerService, SigningQueue};
|
use v1::helpers::external_signer::{SignerService, SigningQueue};
|
||||||
use v1::helpers::dispatch::LightDispatcher;
|
use v1::helpers::dispatch::LightDispatcher;
|
||||||
@ -48,8 +49,12 @@ use v1::types::{
|
|||||||
use Host;
|
use Host;
|
||||||
|
|
||||||
/// Parity implementation for light client.
|
/// Parity implementation for light client.
|
||||||
pub struct ParityClient<S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static> {
|
pub struct ParityClient<S, OD>
|
||||||
light_dispatch: Arc<LightDispatcher<S>>,
|
where
|
||||||
|
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static,
|
||||||
|
OD: OnDemandRequester + 'static
|
||||||
|
{
|
||||||
|
light_dispatch: Arc<LightDispatcher<S, OD>>,
|
||||||
logger: Arc<RotatingLogger>,
|
logger: Arc<RotatingLogger>,
|
||||||
settings: Arc<NetworkSettings>,
|
settings: Arc<NetworkSettings>,
|
||||||
signer: Option<Arc<SignerService>>,
|
signer: Option<Arc<SignerService>>,
|
||||||
@ -57,13 +62,14 @@ pub struct ParityClient<S: LightSyncProvider + LightNetworkDispatcher + ManageNe
|
|||||||
gas_price_percentile: usize,
|
gas_price_percentile: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> ParityClient<S>
|
impl<S, OD> ParityClient<S, OD>
|
||||||
where
|
where
|
||||||
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static
|
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static,
|
||||||
|
OD: OnDemandRequester + 'static
|
||||||
{
|
{
|
||||||
/// Creates new `ParityClient`.
|
/// Creates new `ParityClient`.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
light_dispatch: Arc<LightDispatcher<S>>,
|
light_dispatch: Arc<LightDispatcher<S, OD>>,
|
||||||
logger: Arc<RotatingLogger>,
|
logger: Arc<RotatingLogger>,
|
||||||
settings: Arc<NetworkSettings>,
|
settings: Arc<NetworkSettings>,
|
||||||
signer: Option<Arc<SignerService>>,
|
signer: Option<Arc<SignerService>>,
|
||||||
@ -81,7 +87,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a light blockchain data fetcher.
|
/// Create a light blockchain data fetcher.
|
||||||
fn fetcher(&self) -> LightFetch<S>
|
fn fetcher(&self) -> LightFetch<S, OD>
|
||||||
{
|
{
|
||||||
LightFetch {
|
LightFetch {
|
||||||
client: self.light_dispatch.client.clone(),
|
client: self.light_dispatch.client.clone(),
|
||||||
@ -93,9 +99,10 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> Parity for ParityClient<S>
|
impl<S, OD> Parity for ParityClient<S, OD>
|
||||||
where
|
where
|
||||||
S: LightSyncInfo + LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static
|
S: LightSyncInfo + LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static,
|
||||||
|
OD: OnDemandRequester + 'static
|
||||||
{
|
{
|
||||||
type Metadata = Metadata;
|
type Metadata = Metadata;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user