RLP encoding and decoding for requests
This commit is contained in:
parent
bbb50caa89
commit
41effadb94
@ -24,7 +24,6 @@
|
||||
//! - It stores only headers (and a pruned subset of them)
|
||||
//! - To allow for flexibility in the database layout once that's incorporated.
|
||||
// TODO: use DB instead of memory. DB Layout: just the contents of `candidates`/`headers`
|
||||
//
|
||||
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
|
||||
|
@ -26,7 +26,7 @@
|
||||
//! use-cases like sending transactions from a personal account.
|
||||
//!
|
||||
//! The light client performs a header-only sync, doing verification and pruning
|
||||
//! historical blocks. Upon pruning, batches of 2048 blocks have a number => hash
|
||||
//! historical blocks. Upon pruning, batches of 2048 blocks have a number => (hash, TD)
|
||||
//! mapping sealed into "canonical hash tries" which can later be used to verify
|
||||
//! historical block queries from peers.
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use ethcore::transaction::Action;
|
||||
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream};
|
||||
use util::{Address, H256, U256, Uint};
|
||||
|
||||
// re-exports of request types.
|
||||
@ -77,6 +78,32 @@ impl From<T> for Field<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Decodable> Decodable for Field<T> {
|
||||
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
||||
let rlp = decoder.as_rlp();
|
||||
|
||||
match rlp.val_at::<u8>(0)? {
|
||||
0 => Ok(Field::Scalar(rlp.val_at::<T>(1)?)),
|
||||
1 => Ok({
|
||||
let inner_rlp = rlp.at(1)?;
|
||||
Field::BackReference(inner_rlp.val_at(0)?, inner_rlp.val_at(1)?)
|
||||
})
|
||||
_ => Err(DecoderError::Custom("Unknown discriminant for PIP field.")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Encodable> Encodable for Field<T> {
|
||||
fn rlp_append(&self, s: &mut RlpStream) {
|
||||
s.begin_list(2);
|
||||
match *self {
|
||||
Field::Scalar(ref data) => s.append(&0u8).append(data),
|
||||
Field::BackReference(ref req, ref idx) =>
|
||||
s.append(&1u8).begin_list(2).append(req).append(idx),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Request outputs which can be reused as inputs.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Output {
|
||||
@ -117,6 +144,114 @@ impl From<u64> for HashOrNumber {
|
||||
}
|
||||
}
|
||||
|
||||
/// All request types, as they're sent over the network.
|
||||
pub enum Request {
|
||||
/// A request for block headers.
|
||||
Headers(IncompleteHeadersRequest),
|
||||
/// A request for a header proof (from a CHT)
|
||||
HeaderProof(IncompleteHeaderProofRequest),
|
||||
// TransactionIndex,
|
||||
/// A request for a block's receipts.
|
||||
Receipts(IncompleteReceiptsRequest),
|
||||
/// A request for a block body.
|
||||
Body(IncompleteBodyRequest),
|
||||
/// A request for a merkle proof of an account.
|
||||
Account(IncompleteAccountRequest),
|
||||
/// A request for a merkle proof of contract storage.
|
||||
Storage(IncompleteStorageRequest),
|
||||
/// A request for contract code.
|
||||
Code(IncompleteCodeRequest),
|
||||
// Transaction proof.
|
||||
}
|
||||
|
||||
impl Request {
|
||||
fn kind(&self) -> RequestKind {
|
||||
match *self {
|
||||
Request::Headers(_) => RequestKind::Headers,
|
||||
Request::HeaderProof(_) => RequestKind::HeaderProof,
|
||||
Request::Receipts(_) => RequestKind::Receipts,
|
||||
Request::Body(_) => RequestKind::Body,
|
||||
Request::Account(_) => RequestKind::Account,
|
||||
Request::Storage(_) => RequestKind::Storage,
|
||||
Request::Code(_) => RequestKind::Code,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Decodable for Request {
|
||||
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
||||
let rlp = decoder.as_rlp();
|
||||
|
||||
match rlp.val_at::<RequestKind>(0)? {
|
||||
RequestKind::Headers => Ok(Request::Headers(rlp.val_at(1)?)),
|
||||
RequestKind::HeaderProof => Ok(Request::HeaderProof(rlp.val_at(1)?)),
|
||||
RequestKind::Receipts => Ok(Request::Receipts(rlp.val_at(1)?)),
|
||||
RequestKind::Body => Ok(Request::Body(rlp.val_at(1)?)),
|
||||
RequestKind::Account => Ok(Request::Account(rlp.val_at(1)?)),
|
||||
RequestKind::Storage => Ok(Request::Storage(rlp.val_at(1)?)),
|
||||
RequestKind::Code => Ok(Request::Code(rlp.val_at(1)?)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Encodable for Request {
|
||||
fn rlp_append(&self, s: &mut RlpStream) {
|
||||
s.begin_list(2).append(&self.kind());
|
||||
|
||||
match *self {
|
||||
Request::Headers(ref req) => s.append(req),
|
||||
Request::HeaderProof(ref req) => s.append(req),
|
||||
Request::Receipts(ref req) => s.append(req),
|
||||
Request::Body(ref req) => s.append(req),
|
||||
Request::Account(ref req) => s.append(req),
|
||||
Request::Storage(ref req) => s.append(req),
|
||||
Request::Code(ref req) => s.append(req),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Kinds of requests.
|
||||
/// Doubles as the "ID" field of the request.
|
||||
#[repr(u8)]
|
||||
pub enum RequestKind {
|
||||
/// A request for headers.
|
||||
Headers = 0,
|
||||
HeaderProof = 1,
|
||||
// TransactionIndex = 2,
|
||||
Receipts = 3,
|
||||
Body = 4,
|
||||
Account = 5,
|
||||
Storage = 6,
|
||||
Code = 7,
|
||||
// TransactionProof = 8,
|
||||
}
|
||||
|
||||
impl Decodable for RequestKind {
|
||||
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
||||
let rlp = decoder.as_rlp();
|
||||
|
||||
match rlp.as_val::<u8>()? {
|
||||
0 => Ok(RequestKind::Headers),
|
||||
1 => Ok(RequestKind::HeaderProof),
|
||||
// 2 => Ok(RequestKind::TransactionIndex,
|
||||
3 => Ok(RequestKind::Receipts),
|
||||
4 => Ok(RequestKind::Body),
|
||||
5 => Ok(RequestKind::Account),
|
||||
6 => Ok(RequestKind::Storage),
|
||||
7 => Ok(RequestKind::Code),
|
||||
// 8 => Ok(RequestKind::TransactionProof),
|
||||
_ => Err(DecoderError::Custom("Unknown PIP request ID.")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Encodable for RequestKind {
|
||||
fn rlp_append(&self, s: &mut RlpStream) {
|
||||
s.append(self as &u8);
|
||||
}
|
||||
}
|
||||
|
||||
/// A potentially incomplete request.
|
||||
pub trait IncompleteRequest: Sized {
|
||||
type Complete;
|
||||
@ -144,6 +279,7 @@ pub trait IncompleteRequest: Sized {
|
||||
pub mod header {
|
||||
use super::{Field, HashOrNumber, NoSuchOutput, OutputKind, Output};
|
||||
use ethcore::encoded;
|
||||
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream};
|
||||
use util::U256;
|
||||
|
||||
/// Potentially incomplete headers request.
|
||||
@ -159,6 +295,28 @@ pub mod header {
|
||||
pub reverse: bool,
|
||||
}
|
||||
|
||||
impl Decodable for Incomplete {
|
||||
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
||||
let rlp = decoder.as_rlp();
|
||||
Ok(Incomplete {
|
||||
start: rlp.val_at(0)?,
|
||||
skip: rlp.val_at(1)?,
|
||||
max: rlp.val_at(2)?,
|
||||
reverse: rlp.val_at(3)?
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Encodable for Incomplete {
|
||||
fn rlp_append(&self, s: &mut RlpStream) {
|
||||
s.begin_list(4)
|
||||
.append(&self.start)
|
||||
.append(&self.skip)
|
||||
.append(&self.max)
|
||||
.append(&self.reverse);
|
||||
}
|
||||
}
|
||||
|
||||
impl super::IncompleteRequest for Incomplete {
|
||||
type Complete = Complete;
|
||||
|
||||
@ -223,6 +381,7 @@ pub mod header {
|
||||
/// Request and response for header proofs.
|
||||
pub mod header_proof {
|
||||
use super::{Field, NoSuchOutput, OutputKind, Output};
|
||||
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream};
|
||||
use util::{Bytes, U256, H256};
|
||||
|
||||
/// Potentially incomplete header proof request.
|
||||
@ -232,6 +391,21 @@ pub mod header_proof {
|
||||
pub num: Field<u64>,
|
||||
}
|
||||
|
||||
impl Decodable for Incomplete {
|
||||
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
||||
let rlp = decoder.as_rlp();
|
||||
Ok(Incomplete {
|
||||
num: rlp.val_at(0)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Encodable for Incomplete {
|
||||
fn rlp_append(&self, s: &mut RlpStream) {
|
||||
s.begin_list(1).append(&self.num);
|
||||
}
|
||||
}
|
||||
|
||||
impl super::IncompleteRequest for Incomplete {
|
||||
type Complete = Complete;
|
||||
|
||||
@ -295,6 +469,7 @@ pub mod header_proof {
|
||||
/// Request and response for block receipts
|
||||
pub mod block_receipts {
|
||||
use super::{Field, NoSuchOutput, OutputKind, Output};
|
||||
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream};
|
||||
use util::{Bytes, U256, H256};
|
||||
|
||||
/// Potentially incomplete block receipts request.
|
||||
@ -304,6 +479,21 @@ pub mod block_receipts {
|
||||
pub hash: Field<H256>,
|
||||
}
|
||||
|
||||
impl Decodable for Incomplete {
|
||||
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
||||
let rlp = decoder.as_rlp();
|
||||
Ok(Incomplete {
|
||||
hash: rlp.val_at(0)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Encodable for Incomplete {
|
||||
fn rlp_append(&self, s: &mut RlpStream) {
|
||||
s.begin_list(1).append(&self.hash);
|
||||
}
|
||||
}
|
||||
|
||||
impl super::IncompleteRequest for Incomplete {
|
||||
type Complete = Complete;
|
||||
|
||||
@ -360,6 +550,7 @@ pub mod block_receipts {
|
||||
pub mod block_body {
|
||||
use super::{Field, NoSuchOutput, OutputKind, Output};
|
||||
use ethcore::encoded;
|
||||
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream};
|
||||
use util::{Bytes, U256, H256};
|
||||
|
||||
/// Potentially incomplete block body request.
|
||||
@ -369,6 +560,21 @@ pub mod block_body {
|
||||
pub hash: Field<H256>,
|
||||
}
|
||||
|
||||
impl Decodable for Incomplete {
|
||||
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
||||
let rlp = decoder.as_rlp();
|
||||
Ok(Incomplete {
|
||||
hash: rlp.val_at(0)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Encodable for Incomplete {
|
||||
fn rlp_append(&self, s: &mut RlpStream) {
|
||||
s.begin_list(1).append(&self.hash);
|
||||
}
|
||||
}
|
||||
|
||||
impl super::IncompleteRequest for Incomplete {
|
||||
type Complete = Complete;
|
||||
|
||||
@ -425,6 +631,7 @@ pub mod block_body {
|
||||
pub mod account {
|
||||
use super::{Field, NoSuchOutput, OutputKind, Output};
|
||||
use ethcore::encoded;
|
||||
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream};
|
||||
use util::{Bytes, U256, H256};
|
||||
|
||||
/// Potentially incomplete request for an account proof.
|
||||
@ -436,6 +643,24 @@ pub mod account {
|
||||
pub address_hash: Field<H256>,
|
||||
}
|
||||
|
||||
impl Decodable for Incomplete {
|
||||
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
||||
let rlp = decoder.as_rlp();
|
||||
Ok(Incomplete {
|
||||
block_hash: rlp.val_at(0)?,
|
||||
address_hash: rlp.val_at(1)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Encodable for Incomplete {
|
||||
fn rlp_append(&self, s: &mut RlpStream) {
|
||||
s.begin_list(2)
|
||||
.append(&self.block_hash)
|
||||
.append(&self.address_hash);
|
||||
}
|
||||
}
|
||||
|
||||
impl super::IncompleteRequest for Incomplete {
|
||||
type Complete = Complete;
|
||||
|
||||
@ -522,6 +747,7 @@ pub mod account {
|
||||
pub mod storage {
|
||||
use super::{Field, NoSuchOutput, OutputKind, Output};
|
||||
use ethcore::encoded;
|
||||
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream};
|
||||
use util::{Bytes, U256, H256};
|
||||
|
||||
/// Potentially incomplete request for an storage proof.
|
||||
@ -535,6 +761,26 @@ pub mod storage {
|
||||
pub key_hash: Field<H256>,
|
||||
}
|
||||
|
||||
impl Decodable for Incomplete {
|
||||
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
||||
let rlp = decoder.as_rlp();
|
||||
Ok(Incomplete {
|
||||
block_hash: rlp.val_at(0)?,
|
||||
address_hash: rlp.val_at(1)?,
|
||||
key_hash: rlp.val_at(2)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Encodable for Incomplete {
|
||||
fn rlp_append(&self, s: &mut RlpStream) {
|
||||
s.begin_list(3)
|
||||
.append(&self.block_hash)
|
||||
.append(&self.address_hash)
|
||||
.append(&self.key_hash);
|
||||
}
|
||||
}
|
||||
|
||||
impl super::IncompleteRequest for Incomplete {
|
||||
type Complete = Complete;
|
||||
|
||||
@ -628,6 +874,7 @@ pub mod storage {
|
||||
pub mod contract_code {
|
||||
use super::{Field, NoSuchOutput, OutputKind, Output};
|
||||
use ethcore::encoded;
|
||||
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream};
|
||||
use util::{Bytes, U256, H256};
|
||||
|
||||
/// Potentially incomplete _ request.
|
||||
@ -639,6 +886,24 @@ pub mod contract_code {
|
||||
pub code_hash: Field<H256>,
|
||||
}
|
||||
|
||||
impl Decodable for Incomplete {
|
||||
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
||||
let rlp = decoder.as_rlp();
|
||||
Ok(Incomplete {
|
||||
block_hash: rlp.val_at(0)?,
|
||||
code_hash: rlp.val_at(1)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Encodable for Incomplete {
|
||||
fn rlp_append(&self, s: &mut RlpStream) {
|
||||
s.begin_list(2)
|
||||
.append(&self.block_hash)
|
||||
.append(&self.code_hash);
|
||||
}
|
||||
}
|
||||
|
||||
impl super::IncompleteRequest for Incomplete {
|
||||
type Complete = Complete;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user