light: search for common ancestor with peers

This commit is contained in:
Robert Habermeier 2016-12-13 21:09:57 +01:00
parent 8c64400654
commit 6fb71527e4
5 changed files with 53 additions and 27 deletions

View File

@ -276,7 +276,7 @@ mod tests {
header.set_timestamp(rolling_timestamp); header.set_timestamp(rolling_timestamp);
header.set_difficulty(*genesis_header.difficulty() * i.into()); header.set_difficulty(*genesis_header.difficulty() * i.into());
chain.insert(::rlp::encode(&header).to_vec()); chain.insert(::rlp::encode(&header).to_vec()).unwrap();
parent_hash = header.hash(); parent_hash = header.hash();
rolling_timestamp += 10; rolling_timestamp += 10;

View File

@ -18,6 +18,7 @@
use ethcore::block_import_error::BlockImportError; use ethcore::block_import_error::BlockImportError;
use ethcore::block_status::BlockStatus; use ethcore::block_status::BlockStatus;
use ethcore::ids::BlockId;
use ethcore::verification::queue::{self, HeaderQueue}; use ethcore::verification::queue::{self, HeaderQueue};
use ethcore::transaction::SignedTransaction; use ethcore::transaction::SignedTransaction;
use ethcore::blockchain_info::BlockChainInfo; use ethcore::blockchain_info::BlockChainInfo;
@ -33,7 +34,7 @@ use request;
use self::header_chain::HeaderChain; use self::header_chain::HeaderChain;
mod cht; pub mod cht;
mod header_chain; mod header_chain;
/// Configuration for the light client. /// Configuration for the light client.
@ -84,16 +85,8 @@ impl Client {
} }
} }
/// Get the header queue info. /// Get the chain info.
pub fn queue_info(&self) -> queue::QueueInfo { pub fn chain_info(&self) -> BlockChainInfo {
self.queue.queue_info()
}
}
// dummy implementation -- may draw from canonical cache further on.
impl Provider for Client {
fn chain_info(&self) -> BlockChainInfo {
let best_block = self.chain.best_block(); let best_block = self.chain.best_block();
let first_block = self.chain.first_block(); let first_block = self.chain.first_block();
let genesis_hash = self.chain.genesis_hash(); let genesis_hash = self.chain.genesis_hash();
@ -111,6 +104,28 @@ impl Provider for Client {
} }
} }
/// Get the header queue info.
pub fn queue_info(&self) -> queue::QueueInfo {
self.queue.queue_info()
}
/// Get a block header by Id.
pub fn get_header(&self, id: BlockId) -> Option<Bytes> {
self.chain.get_header(id)
}
/// Get the `i`th CHT root.
pub fn cht_root(&self, i: usize) -> Option<H256> {
self.chain.cht_root(i)
}
}
// dummy implementation -- may draw from canonical cache further on.
impl Provider for Client {
fn chain_info(&self) -> BlockChainInfo {
Client::chain_info(self)
}
fn reorg_depth(&self, _a: &H256, _b: &H256) -> Option<u64> { fn reorg_depth(&self, _a: &H256, _b: &H256) -> Option<u64> {
None None
} }

View File

@ -38,7 +38,7 @@ use request::{self, HashOrNumber, Request};
use self::buffer_flow::{Buffer, FlowParams}; use self::buffer_flow::{Buffer, FlowParams};
use self::context::Ctx; use self::context::Ctx;
use self::error::{Error, Punishment}; use self::error::Punishment;
mod buffer_flow; mod buffer_flow;
mod context; mod context;
@ -48,6 +48,7 @@ mod status;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
pub use self::error::Error;
pub use self::context::{EventContext, IoContext}; pub use self::context::{EventContext, IoContext};
pub use self::status::{Status, Capabilities, Announcement}; pub use self::status::{Status, Capabilities, Announcement};

View File

@ -54,6 +54,7 @@ extern crate ethcore_ipc as ipc;
mod chain; mod chain;
mod blocks; mod blocks;
mod block_sync; mod block_sync;
mod light_sync;
mod sync_io; mod sync_io;
mod snapshot; mod snapshot;
mod transactions_stats; mod transactions_stats;

View File

@ -28,12 +28,14 @@ use std::collections::{BinaryHeap, HashMap};
use std::fmt; use std::fmt;
use std::sync::Arc; use std::sync::Arc;
use light::client::{Client, BlockDescriptor}; use ethcore::header::Header;
use light::net::{Error as NetError, Handler, EventContext, Capabilities, ReqId};
use light::client::Client;
use light::net::{Announcement, Error as NetError, Handler, EventContext, Capabilities, ReqId, Status};
use light::request; use light::request;
use network::PeerId; use network::PeerId;
use rlp::{UntrustedRlp, View}; use rlp::{UntrustedRlp, View};
use util::{U256, H256}; use util::{Bytes, U256, H256, Mutex, RwLock};
// How many headers we request at a time when searching for best // How many headers we request at a time when searching for best
// common ancestor with peer. // common ancestor with peer.
@ -53,6 +55,12 @@ enum Error {
ProtocolLevel(NetError), ProtocolLevel(NetError),
} }
impl From<NetError> for Error {
fn from(net_error: NetError) -> Self {
Error::ProtocolLevel(net_error)
}
}
impl fmt::Display for Error { impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self { match *self {
@ -87,13 +95,13 @@ impl UnconfirmedPeer {
fn create(ctx: &EventContext, chain_info: ChainInfo, best_num: u64) -> Result<Self, Error> { fn create(ctx: &EventContext, chain_info: ChainInfo, best_num: u64) -> Result<Self, Error> {
let this = ctx.peer(); let this = ctx.peer();
if ctx.max_requests(this, request::Kind::Headers) < UNCONFIRMED_SEARCH_SIZE { if ctx.max_requests(this, request::Kind::Headers) < UNCONFIRMED_SEARCH_SIZE as usize {
return Err(Error::UselessPeer); // a peer which allows this few header reqs isn't useful anyway. return Err(Error::UselessPeer); // a peer which allows this few header reqs isn't useful anyway.
} }
let req_id = try!(ctx.request_from(this, request::Request::Headers(request::Headers { let req_id = try!(ctx.request_from(this, request::Request::Headers(request::Headers {
start: best_num.into(), start: best_num.into(),
max: ::std::cmp::min(best_num, UNCONFIRMED_SEARCH_SIZE), max: ::std::cmp::min(best_num, UNCONFIRMED_SEARCH_SIZE) as usize,
skip: 0, skip: 0,
reverse: true, reverse: true,
}))); })));
@ -101,7 +109,7 @@ impl UnconfirmedPeer {
Ok(UnconfirmedPeer { Ok(UnconfirmedPeer {
chain_info: chain_info, chain_info: chain_info,
last_batched: best_num, last_batched: best_num,
req_id: ReqId, req_id: req_id,
}) })
} }
@ -142,13 +150,15 @@ impl UnconfirmedPeer {
// nothing found, nothing prehistoric. // nothing found, nothing prehistoric.
// send the next request. // send the next request.
let req_id = try!(ctx.request_from(this, request::Request::Headers(request::Headers { let req_id = try!(ctx.request_from(this, request::Request::Headers(request::Headers {
start: cur_num, start: cur_num.into(),
max: ::std::cmp::min(cur_num, UNCONFIRMED_SEARCH_SIZE), max: ::std::cmp::min(cur_num, UNCONFIRMED_SEARCH_SIZE) as usize,
skip: 0, skip: 0,
reverse: true, reverse: true,
}))); })));
self.req_id = req_id; self.req_id = req_id;
Ok(None)
} }
} }
@ -168,13 +178,13 @@ pub struct LightSync {
best_seen: Mutex<Option<(H256, U256)>>, // best seen block on the network. best_seen: Mutex<Option<(H256, U256)>>, // best seen block on the network.
peers: RwLock<HashMap<PeerId, Peer>>, // peers which are relevant to synchronization. peers: RwLock<HashMap<PeerId, Peer>>, // peers which are relevant to synchronization.
client: Arc<Client>, client: Arc<Client>,
downloader: Downloader,
assigned_requests: HashMap<ReqId, HeaderRequest>,
} }
impl Handler for LightSync { impl Handler for LightSync {
fn on_connect(&self, ctx: &EventContext, status: &Status, capabilities: &Capabilities) { fn on_connect(&self, ctx: &EventContext, status: &Status, capabilities: &Capabilities) {
if !capabilities.serve_headers || status.head_num <= self.client.best_block().number { let our_best = self.client.chain_info().best_block_number;
if !capabilities.serve_headers || status.head_num <= our_best {
trace!(target: "sync", "Ignoring irrelevant peer: {}", ctx.peer()); trace!(target: "sync", "Ignoring irrelevant peer: {}", ctx.peer());
return; return;
} }
@ -184,7 +194,6 @@ impl Handler for LightSync {
head_hash: status.head_hash, head_hash: status.head_hash,
head_num: status.head_num, head_num: status.head_num,
}; };
let our_best = self.client.chain_info().best_block_number;
let unconfirmed = match UnconfirmedPeer::create(ctx, chain_info, our_best) { let unconfirmed = match UnconfirmedPeer::create(ctx, chain_info, our_best) {
Ok(unconfirmed) => unconfirmed, Ok(unconfirmed) => unconfirmed,
Err(e) => { Err(e) => {
@ -193,7 +202,7 @@ impl Handler for LightSync {
} }
}; };
self.peers.write().insert(ctx.peer(), Mutex::new(unconfirmed)); self.peers.write().insert(ctx.peer(), Peer::SearchCommon(Mutex::new(unconfirmed)));
} }
} }
@ -206,7 +215,7 @@ impl LightSync {
pub fn new(client: Arc<Client>) -> Self { pub fn new(client: Arc<Client>) -> Self {
LightSync { LightSync {
best_seen: Mutex::new(None), best_seen: Mutex::new(None),
peers: HashMap::new(), peers: RwLock::new(HashMap::new()),
client: client, client: client,
} }
} }