request definitions

This commit is contained in:
Robert Habermeier 2016-11-04 17:19:01 +01:00
parent 1bc124f980
commit eef9a355af
3 changed files with 156 additions and 115 deletions

View File

@ -27,18 +27,19 @@ use block_import_error::BlockImportError;
use block_status::BlockStatus; use block_status::BlockStatus;
use verification::queue::{Config as QueueConfig, HeaderQueue, QueueInfo, Status}; use verification::queue::{Config as QueueConfig, HeaderQueue, QueueInfo, Status};
use transaction::SignedTransaction; use transaction::SignedTransaction;
use types::blockchain_info::BlockChainInfo;
use super::provider::{CHTProofRequest, Provider, ProofRequest}; use super::provider::{CHTProofRequest, Provider, ProofRequest};
use io::IoChannel; use io::IoChannel;
use util::hash::H256; use util::hash::H256;
use util::Bytes; use util::{Bytes, Mutex};
/// Light client implementation. /// Light client implementation.
pub struct Client { pub struct Client {
engine: Arc<Engine>, engine: Arc<Engine>,
header_queue: HeaderQueue, header_queue: HeaderQueue,
message_channel: IoChannel<ClientIoMessage>, message_channel: Mutex<IoChannel<ClientIoMessage>>,
} }
impl Client { impl Client {
@ -70,11 +71,12 @@ impl Client {
} }
/// Get the chain info. /// Get the chain info.
pub fn chain_info(&self) -> ChainInfo { pub fn chain_info(&self) -> BlockChainInfo {
unimplemented!()
} }
} }
// dummy implementation -- may draw from canonical cache further on.
impl Provider for Client { impl Provider for Client {
fn block_headers(&self, block: H256, skip: usize, max: usize, reverse: bool) -> Vec<Bytes> { fn block_headers(&self, block: H256, skip: usize, max: usize, reverse: bool) -> Vec<Bytes> {
Vec::new() Vec::new()

View File

@ -29,6 +29,10 @@ use parking_lot::{Mutex, RwLock};
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
use self::request::Request;
mod request;
const TIMEOUT: TimerToken = 0; const TIMEOUT: TimerToken = 0;
const TIMEOUT_INTERVAL_MS: u64 = 1000; const TIMEOUT_INTERVAL_MS: u64 = 1000;
@ -87,11 +91,9 @@ mod packet {
pub const TRANSACTION_PROOFS: u8 = 0x13; pub const TRANSACTION_PROOFS: u8 = 0x13;
} }
struct Request;
struct Requested { struct Requested {
timestamp: usize, timestamp: usize,
total: Request, req: Request,
} }
// data about each peer. // data about each peer.
@ -172,7 +174,7 @@ impl Chain {
unimplemented!() unimplemented!()
} }
fn status(&self, peer: &PeerId, io: &NetworkContext) { fn status(&self, peer: &PeerId, io: &NetworkContext, data: UntrustedRlp) {
unimplemented!() unimplemented!()
} }
@ -205,6 +207,16 @@ impl Chain {
unimplemented!() unimplemented!()
} }
// Handle a request for receipts.
fn get_receipts(&self, peer: &PeerId, io: &NetworkContext, data: UntrustedRlp) {
unimplemented!()
}
// Receive a response for receipts.
fn receipts(&self, peer: &PeerId, io: &NetworkContext, data: UntrustedRlp) {
unimplemented!()
}
// Handle a request for proofs. // Handle a request for proofs.
fn get_proofs(&self, peer: &PeerId, io: &NetworkContext, data: UntrustedRlp) { fn get_proofs(&self, peer: &PeerId, io: &NetworkContext, data: UntrustedRlp) {
unimplemented!() unimplemented!()
@ -284,7 +296,7 @@ impl NetworkProtocolHandler for Chain {
packet::BLOCK_BODIES => self.block_bodies(peer, io, rlp), packet::BLOCK_BODIES => self.block_bodies(peer, io, rlp),
packet::GET_RECEIPTS => self.get_receipts(peer, io, rlp), packet::GET_RECEIPTS => self.get_receipts(peer, io, rlp),
packet::RECEIPTS => self.receipt(peer, io, rlp), packet::RECEIPTS => self.receipts(peer, io, rlp),
packet::GET_PROOFS => self.get_proofs(peer, io, rlp), packet::GET_PROOFS => self.get_proofs(peer, io, rlp),
packet::PROOFS => self.proofs(peer, io, rlp), packet::PROOFS => self.proofs(peer, io, rlp),
@ -311,7 +323,7 @@ impl NetworkProtocolHandler for Chain {
} }
fn disconnected(&self, io: &NetworkContext, peer: &PeerId) { fn disconnected(&self, io: &NetworkContext, peer: &PeerId) {
self.on_disconnect(peer, io); self.on_disconnect(*peer, io);
} }
fn timeout(&self, io: &NetworkContext, timer: TimerToken) { fn timeout(&self, io: &NetworkContext, timer: TimerToken) {

View File

@ -14,125 +14,152 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! LES request types. /// LES request types.
use util::bigint::prelude::*; use ethcore::transaction::Transaction;
use rlp::*; use util::{Address, H256};
/// An LES request. This defines its data format, and the format of its response type. /// A request for block headers.
pub trait Request: Sized { #[derive(Debug, Clone, PartialEq, Eq)]
/// The response type of this request. pub struct Headers {
type Response: Response; /// Block information for the request being made.
pub block: (u64, H256),
/// The error type when decoding a response. /// The maximum amount of headers which can be returned.
type Error; pub max: u64,
/// The amount of headers to skip between each response entry.
/// Whether this request is empty. pub skip: u64,
fn is_empty(&self) -> bool; /// Whether the headers should proceed in falling number from the initial block.
pub reverse: 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 /// A request for specific block bodies.
/// in one response with data from another. #[derive(Debug, Clone, PartialEq, Eq)]
pub trait Response: Sized { pub struct Bodies {
/// Combine the two responses into one. This can only be relied on to behave correctly /// Hashes which bodies are being requested for.
/// if `other` is a response to a sub-request of the request this response was pub block_hashes: Vec<H256>
/// produced from.
fn combine(&mut self, other: Self);
} }
/// A request for block bodies. /// A request for transaction receipts.
pub struct BlockBodies { ///
hashes: Vec<H256>, /// This request is answered with a list of transaction receipts for each block
/// requested.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Receipts {
/// Block hashes to return receipts for.
pub block_hashes: Vec<H256>,
} }
/// A response for block bodies. /// A request for state proofs.
pub struct BlockBodiesResponse { #[derive(Debug, Clone, PartialEq, Eq)]
bodies: Vec<(H256, Vec<u8>)>, pub struct StateProofs {
/// Block hash to query state from.
pub block: H256,
/// Key of the state trie -- corresponds to account hash.
pub key1: H256,
/// Key in that account's storage trie; if empty, then the account RLP should be
/// returned.
pub key2: Option<H256>,
/// if greater than zero, trie nodes beyond this level may be omitted.
pub from_level: u32, // could even safely be u8; trie w/ 32-byte key can be at most 64-levels deep.
} }
impl Request for BlockBodies { /// A request for contract code.
type Response = BlockBodiesResponse; #[derive(Debug, Clone, PartialEq, Eq)]
type Error = ::rlp::DecoderError; pub struct ContractCodes {
/// Block hash and account key (== sha3(address)) pairs to fetch code for.
fn is_empty(&self) -> bool { self.hashes.is_empty() } pub code_requests: Vec<(H256, H256)>,
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 { /// A request for header proofs from the Canonical Hash Trie.
fn identity() -> Self { #[derive(Debug, Clone, PartialEq, Eq)]
BlockBodiesResponse { pub struct HeaderProofs {
bodies: Vec::new(), /// Number of the CHT.
} pub cht_number: u64,
} /// Block number requested.
pub block_number: u64,
/// If greater than zero, trie nodes beyond this level may be omitted.
pub from_level: u32,
}
fn combine(&mut self, other: Self) { /// A request for block deltas -- merkle proofs of all changed trie nodes and code.
let other_iter = other.bodies.into_iter(); #[derive(Debug, Clone, PartialEq, Eq)]
pub struct BlockDeltas {
/// Block hashes deltas are being requested for.
pub block_hashes: Vec<H256>,
}
'a: /// A request for a single transaction merkle proof.
for &mut (ref my_hash, ref mut my_body) in self.bodies.iter_mut() { #[derive(Debug, Clone, PartialEq, Eq)]
loop { pub struct TransactionProof {
match other_iter.next() { /// The block hash to use the initial state from.
Some((hash, body)) if hash == my_hash && !body.is_empty() => { pub block_hash: H256,
*my_body = body.to_owned(); /// The address to treat as the sender of the transaction.
break pub sender: Address,
} /// The raw transaction request itself.
Some(_) => continue, pub transaction: Transaction,
None => break 'a, }
}
} /// A request for transaction merkle proofs.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TransactionProofs {
/// Transaction proof requests.
pub tx_reqs: Vec<TransactionProof>,
}
/// Kinds of requests.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Kind {
/// Requesting headers.
Headers,
/// Requesting block bodies.
Bodies,
/// Requesting transaction receipts.
Receipts,
/// Requesting proofs of state trie nodes.
StateProofs,
/// Requesting contract code by hash.
Codes,
/// Requesting header proofs (from the CHT).
HeaderProofs,
/// Requesting block deltas.
Deltas,
/// Requesting merkle proofs for transactions.
TransactionProofs,
}
/// Encompasses all possible types of requests in a single structure.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Request {
/// Requesting headers.
Headers(Headers),
/// Requesting block bodies.
Bodies(Bodies),
/// Requesting transaction receipts.
Receipts(Receipts),
/// Requesting state proofs.
StateProofs(StateProofs),
/// Requesting contract codes.
Codes(ContractCodes),
/// Requesting header proofs.
HeaderProofs(HeaderProofs),
/// Requesting block deltas.
Deltas(BlockDeltas),
/// Requesting transaction proofs.
TransactionProofs(TransactionProofs),
}
impl Request {
/// Get the kind of request this is.
pub fn kind(&self) -> Kind {
match *self {
Request::Headers(_) => Kind::Headers,
Request::Bodies(_) => Kind::Bodies,
Request::Receipts(_) => Kind::Receipts,
Request::StateProofs(_) => Kind::StateProofs,
Request::Codes(_) => Kind::Codes,
Request::HeaderProofs(_) => Kind::HeaderProofs,
Request::Deltas(_) => Kind::Deltas,
Request::TransactionProofs(_) => Kind::TransactionProofs,
} }
} }
} }