skeleton and request traits
This commit is contained in:
parent
a7e420d9ec
commit
3a5843c40f
@ -68,6 +68,11 @@ impl Client {
|
|||||||
pub fn queue_info(&self) -> QueueInfo {
|
pub fn queue_info(&self) -> QueueInfo {
|
||||||
self.header_queue.queue_info()
|
self.header_queue.queue_info()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the chain info.
|
||||||
|
pub fn chain_info(&self) -> ChainInfo {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Provider for Client {
|
impl Provider for Client {
|
||||||
|
33
ethcore/src/light/sync.rs
Normal file
33
ethcore/src/light/sync.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! A light sync target.
|
||||||
|
|
||||||
|
use block_import_error::BlockImportError;
|
||||||
|
use client::BlockChainInfo;
|
||||||
|
|
||||||
|
use util::hash::H256;
|
||||||
|
|
||||||
|
pub trait Sync {
|
||||||
|
/// Whether syncing is enabled.
|
||||||
|
fn enabled(&self) -> bool;
|
||||||
|
|
||||||
|
/// Current chain info.
|
||||||
|
fn chain_info(&self) -> BlockChainInfo;
|
||||||
|
|
||||||
|
/// Import a header.
|
||||||
|
fn import_header(&self, header_bytes: Vec<u8>) -> Result<H256, BlockImportError>;
|
||||||
|
}
|
@ -24,8 +24,10 @@ use io::TimerToken;
|
|||||||
use network::{NetworkProtocolHandler, NetworkService, NetworkContext, NetworkError, PeerId};
|
use network::{NetworkProtocolHandler, NetworkService, NetworkContext, NetworkError, PeerId};
|
||||||
use rlp::{DecoderError, RlpStream, Stream, UntrustedRlp, View};
|
use rlp::{DecoderError, RlpStream, Stream, UntrustedRlp, View};
|
||||||
use util::hash::H256;
|
use util::hash::H256;
|
||||||
|
use parking_lot::{Mutex, RwLock};
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
|
||||||
const TIMEOUT: TimerToken = 0;
|
const TIMEOUT: TimerToken = 0;
|
||||||
const TIMEOUT_INTERVAL_MS: u64 = 1000;
|
const TIMEOUT_INTERVAL_MS: u64 = 1000;
|
||||||
@ -84,29 +86,18 @@ mod packet {
|
|||||||
pub const GET_TRANSACTION_PROOFS: u8 = 0x12;
|
pub const GET_TRANSACTION_PROOFS: u8 = 0x12;
|
||||||
pub const TRANSACTION_PROOFS: u8 = 0x13;
|
pub const TRANSACTION_PROOFS: u8 = 0x13;
|
||||||
}
|
}
|
||||||
// which direction a request should go in.
|
|
||||||
enum Direction {
|
|
||||||
Forwards,
|
|
||||||
Reverse,
|
|
||||||
}
|
|
||||||
|
|
||||||
// A request made to a peer.
|
struct Request;
|
||||||
enum Request {
|
|
||||||
// a request for headers:
|
struct Requested {
|
||||||
// (number, hash), maximum, skip, direction.
|
timestamp: usize,
|
||||||
Headers((u64, H256), u64, u64, Direction),
|
total: Request,
|
||||||
// a request for block bodies by hashes.
|
|
||||||
Bodies(Vec<H256>),
|
|
||||||
// a request for tx receipts by hashes.
|
|
||||||
Receipts(Vec<H256>),
|
|
||||||
// a request for contract code by (block hash, address hash).
|
|
||||||
Code(Vec<(H256, H256)>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// data about each peer.
|
// data about each peer.
|
||||||
struct Peer {
|
struct Peer {
|
||||||
pending_requests: HashMap<usize, Request>, // requests pending for peer.
|
|
||||||
buffer: u64, // remaining buffer value.
|
buffer: u64, // remaining buffer value.
|
||||||
|
current_asking: HashSet<usize>, // pending request ids.
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This handles synchronization of the header chain for a light client.
|
/// This handles synchronization of the header chain for a light client.
|
||||||
@ -115,15 +106,25 @@ pub struct Chain {
|
|||||||
genesis_hash: H256,
|
genesis_hash: H256,
|
||||||
mainnet: bool,
|
mainnet: bool,
|
||||||
peers: RwLock<HashMap<PeerId, Peer>>,
|
peers: RwLock<HashMap<PeerId, Peer>>,
|
||||||
|
pending_requests: RwLock<HashMap<usize, Requested>>,
|
||||||
|
req_id: AtomicUsize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Chain {
|
impl Chain {
|
||||||
|
// make a request to a given peer.
|
||||||
|
fn request_from(&self, peer: &PeerId, req: Request) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
// called when a peer connects.
|
// called when a peer connects.
|
||||||
fn on_connect(&self, peer: &PeerId, io: &NetworkContext) {
|
fn on_connect(&self, peer: &PeerId, io: &NetworkContext) {
|
||||||
let peer = *peer;
|
let peer = *peer;
|
||||||
match self.send_status(peer, io) {
|
match self.send_status(peer, io) {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
self.peers.write().insert(peer, Peer);
|
self.peers.write().insert(peer, Peer {
|
||||||
|
buffer: 0,
|
||||||
|
current_asking: HashSet::new(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
trace!(target: "les", "Error while sending status: {}", e);
|
trace!(target: "les", "Error while sending status: {}", e);
|
||||||
@ -133,8 +134,9 @@ impl Chain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// called when a peer disconnects.
|
// called when a peer disconnects.
|
||||||
fn on_disconnect(&self, peer: PeerId) {
|
fn on_disconnect(&self, peer: PeerId, io: &NetworkContext) {
|
||||||
self.peers.write().remove(peer);
|
// TODO: reassign all requests assigned to this peer.
|
||||||
|
self.peers.write().remove(&peer);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_status(&self, peer: PeerId, io: &NetworkContext) -> Result<(), NetworkError> {
|
fn send_status(&self, peer: PeerId, io: &NetworkContext) -> Result<(), NetworkError> {
|
||||||
@ -165,6 +167,11 @@ impl Chain {
|
|||||||
io.send(peer, packet::STATUS, stream.out())
|
io.send(peer, packet::STATUS, stream.out())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check on the status of all pending requests.
|
||||||
|
fn check_pending_requests(&self) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
fn status(&self, peer: &PeerId, io: &NetworkContext) {
|
fn status(&self, peer: &PeerId, io: &NetworkContext) {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
@ -177,7 +184,9 @@ impl Chain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle a request for block headers.
|
// Handle a request for block headers.
|
||||||
fn get_block_headers(&self, peers: &PeerId, io: &NetworkContext, data: UntrustedRlp) {
|
fn get_block_headers(&self, peer: &PeerId, io: &NetworkContext, data: UntrustedRlp) {
|
||||||
|
const MAX_HEADERS: usize = 512;
|
||||||
|
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
138
sync/src/light/request.rs
Normal file
138
sync/src/light/request.rs
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! LES request types.
|
||||||
|
|
||||||
|
use util::bigint::prelude::*;
|
||||||
|
use rlp::*;
|
||||||
|
|
||||||
|
/// An LES request. This defines its data format, and the format of its response type.
|
||||||
|
pub trait Request: Sized {
|
||||||
|
/// The response type of this request.
|
||||||
|
type Response: Response;
|
||||||
|
|
||||||
|
/// The error type when decoding a response.
|
||||||
|
type Error;
|
||||||
|
|
||||||
|
/// Whether this request is empty.
|
||||||
|
fn is_empty(&self) -> bool;
|
||||||
|
|
||||||
|
/// The remainder of this request unfulfilled by the response. Required to return
|
||||||
|
/// an equivalent request when provided with an empty response.
|
||||||
|
fn remainder(&self, res: &Self::Response) -> Self;
|
||||||
|
|
||||||
|
/// Attempt to parse raw data into a response object
|
||||||
|
/// or an error. Behavior undefined if the raw data didn't originate from
|
||||||
|
/// this request.
|
||||||
|
fn parse_response(&self, raw: &[u8]) -> Result<Self::Response, Self::Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Request responses. These must have a combination operation used to fill the gaps
|
||||||
|
/// in one response with data from another.
|
||||||
|
pub trait Response: Sized {
|
||||||
|
/// Combine the two responses into one. This can only be relied on to behave correctly
|
||||||
|
/// if `other` is a response to a sub-request of the request this response was
|
||||||
|
/// produced from.
|
||||||
|
fn combine(&mut self, other: Self);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A request for block bodies.
|
||||||
|
pub struct BlockBodies {
|
||||||
|
hashes: Vec<H256>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A response for block bodies.
|
||||||
|
pub struct BlockBodiesResponse {
|
||||||
|
bodies: Vec<(H256, Vec<u8>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Request for BlockBodies {
|
||||||
|
type Response = BlockBodiesResponse;
|
||||||
|
type Error = ::rlp::DecoderError;
|
||||||
|
|
||||||
|
fn is_empty(&self) -> bool { self.hashes.is_empty() }
|
||||||
|
|
||||||
|
fn remainder(&self, res: &Self::Response) -> Self {
|
||||||
|
let mut remaining = Vec::new();
|
||||||
|
|
||||||
|
let bodies = res.bodies.iter().map(|&(_, ref b) b).chain(::std::iter::repeat(&Vec::new()));
|
||||||
|
for (hash, body) in self.hashes.iter().zip(bodies) {
|
||||||
|
if body.is_empty() {
|
||||||
|
remaining.push(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockBodies {
|
||||||
|
hashes: remaining,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_response(&self, raw: &[u8]) -> Result<Self::Response, Self::Error> {
|
||||||
|
use ethcore::transaction::SignedTransaction;
|
||||||
|
use ethcore::header::Header;
|
||||||
|
|
||||||
|
let rlp = UntrustedRlp::new(raw);
|
||||||
|
|
||||||
|
let mut bodies = Vec::with_capacity(self.hashes.len());
|
||||||
|
|
||||||
|
let items = rlp.iter();
|
||||||
|
for hash in self.hashes.iter().cloned() {
|
||||||
|
let res_bytes = match items.next() {
|
||||||
|
Some(rlp) => {
|
||||||
|
// perform basic block verification.
|
||||||
|
// TODO: custom error type?
|
||||||
|
try!(rlp.val_at::<Vec<SignedTransaction>>(0)
|
||||||
|
.and_then(|_| rlp.val_at::<Vec<Header>>(1)));
|
||||||
|
|
||||||
|
try!(rlp.data()).to_owned()
|
||||||
|
}
|
||||||
|
None => Vec::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
bodies.push((hash, res_bytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(BlockBodiesResponse {
|
||||||
|
bodies: bodies,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Response for BlockBodiesResponse {
|
||||||
|
fn identity() -> Self {
|
||||||
|
BlockBodiesResponse {
|
||||||
|
bodies: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn combine(&mut self, other: Self) {
|
||||||
|
let other_iter = other.bodies.into_iter();
|
||||||
|
|
||||||
|
'a:
|
||||||
|
for &mut (ref my_hash, ref mut my_body) in self.bodies.iter_mut() {
|
||||||
|
loop {
|
||||||
|
match other_iter.next() {
|
||||||
|
Some((hash, body)) if hash == my_hash && !body.is_empty() => {
|
||||||
|
*my_body = body.to_owned();
|
||||||
|
break
|
||||||
|
}
|
||||||
|
Some(_) => continue,
|
||||||
|
None => break 'a,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user