encode and decode responses

This commit is contained in:
Robert Habermeier 2017-03-07 17:18:26 +01:00
parent 87f3d53607
commit b396b56e34
2 changed files with 439 additions and 74 deletions

View File

@ -30,16 +30,9 @@ use cht::{self, BlockInfo};
use client::{LightChainClient, AsLightClient};
use transaction_queue::TransactionQueue;
use request;
/// Defines the operations that a provider for `LES` must fulfill.
///
/// These are defined at [1], but may be subject to change.
/// Requests which can't be fulfilled should return either an empty RLP list
/// or empty vector where appropriate.
///
/// [1]: https://github.com/ethcore/parity/wiki/Light-Ethereum-Subprotocol-(LES)
/// Defines the operations that a provider for the light subprotocol must fulfill.
#[cfg_attr(feature = "ipc", ipc(client_ident="LightProviderClient"))]
pub trait Provider: Send + Sync {
/// Provide current blockchain info.
@ -149,12 +142,12 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
BlockChainClient::block_header(self, id)
}
fn block_body(&self, req: request::CompleteBodyRequest) -> Option<request::BodyResponse>;
fn block_body(&self, req: request::CompleteBodyRequest) -> Option<request::BodyResponse> {
BlockChainClient::block_body(self, id)
.map(|body| ::request::BodyResponse { body: body })
}
fn block_receipts(&self, req: request::CompleteReceiptsRequest) -> Option<request::ReceiptsResponse>;
fn block_receipts(&self, req: request::CompleteReceiptsRequest) -> Option<request::ReceiptsResponse> {
BlockChainClient::block_receipts(self, hash)
.map(|x| ::request::ReceiptsResponse { receipts: ::rlp::decode(&x) })
}
@ -168,7 +161,7 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
code_hash: acc.code_hash,
storage_root: acc.storage_root,
}
}))
})
}
fn storage_proof(&self, req: request::CompleteStorageRequest) -> Option<request::StorageResponse> {
@ -177,7 +170,7 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
proof: proof,
value: item,
}
}))
})
}
fn contract_code(&self, req: request::ContractCode) -> Option<request::CodeResponse> {
@ -185,7 +178,7 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
.map(|code| ::request::CodeResponse { code: code })
}
fn header_proof(&self, req: request::CompleteHeaderProofRequest) -> Option<request::HeaderProofResponse>;
fn header_proof(&self, req: request::CompleteHeaderProofRequest) -> Option<request::HeaderProofResponse> {
let cht_number = match cht::block_to_cht_number(req.num) {
Some(cht_num) => cht_num,
None => {
@ -243,7 +236,7 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
}
}
fn transaction_proof(&self, req: request::TransactionProof) -> Option<Vec<DBValue>> {
fn transaction_proof(&self, req: request::CompleteExecutionRequest) -> Option<request::ExecutionResponse> {
use ethcore::transaction::Transaction;
let id = BlockId::Hash(req.at);
@ -261,6 +254,7 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
}.fake_sign(req.from);
self.prove_transaction(transaction, id)
.map(|proof| ::request::ExecutionResponse { items: proof })
}
fn ready_transactions(&self) -> Vec<PendingTransaction> {

View File

@ -38,9 +38,9 @@ pub use self::block_body::{
Incomplete as IncompleteBodyRequest,
Response as BodyResponse
};
pub use self::receipts::{
pub use self::block_receipts::{
Complete as CompleteReceiptsRequest,
Incomplete as IncompleteReceiptsRequest
Incomplete as IncompleteReceiptsRequest,
Response as ReceiptsResponse
};
pub use self::account::{
@ -58,6 +58,11 @@ pub use self::contract_code::{
Incomplete as IncompleteCodeRequest,
Response as CodeResponse,
};
pub use self::execution::{
Complete as CompleteExecutionRequest,
Incomplete as IncompleteExecutionRequest,
Response as ExecutionResponse,
};
/// Error indicating a reference to a non-existent or wrongly-typed output.
pub struct NoSuchOutput;
@ -87,7 +92,7 @@ impl<T: Decodable> Decodable for Field<T> {
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.")),
}
}
@ -171,7 +176,8 @@ pub enum Request {
Storage(IncompleteStorageRequest),
/// A request for contract code.
Code(IncompleteCodeRequest),
// Transaction proof.
/// A request for proof of execution,
Execution(IncompleteExecutionRequest),
}
/// All request types, as they're sent over the network.
@ -192,19 +198,21 @@ pub enum CompleteRequest {
Storage(CompleteStorageRequest),
/// A request for contract code.
Code(CompleteCodeRequest),
// Transaction proof.
/// A request for proof of execution,
Execution(CompleteExecutionRequest),
}
impl Request {
fn kind(&self) -> RequestKind {
fn kind(&self) -> Kind {
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,
Request::Headers(_) => Kind::Headers,
Request::HeaderProof(_) => Kind::HeaderProof,
Request::Receipts(_) => Kind::Receipts,
Request::Body(_) => Kind::Body,
Request::Account(_) => Kind::Account,
Request::Storage(_) => Kind::Storage,
Request::Code(_) => Kind::Code,
Request::Execution(_) => Kind::Execution,
}
}
}
@ -213,14 +221,15 @@ 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)?)),
match rlp.val_at::<Kind>(0)? {
Kind::Headers => Ok(Request::Headers(rlp.val_at(1)?)),
Kind::HeaderProof => Ok(Request::HeaderProof(rlp.val_at(1)?)),
Kind::Receipts => Ok(Request::Receipts(rlp.val_at(1)?)),
Kind::Body => Ok(Request::Body(rlp.val_at(1)?)),
Kind::Account => Ok(Request::Account(rlp.val_at(1)?)),
Kind::Storage => Ok(Request::Storage(rlp.val_at(1)?)),
Kind::Code => Ok(Request::Code(rlp.val_at(1)?)),
Kind::Execution => Ok(Request::Execution(rlp.val_at(1)?)),
}
}
}
@ -237,6 +246,7 @@ impl Encodable for Request {
Request::Account(ref req) => s.append(req),
Request::Storage(ref req) => s.append(req),
Request::Code(ref req) => s.append(req),
Request::Execution(ref req) => s.append(req),
};
}
}
@ -255,6 +265,7 @@ impl IncompleteRequest for Request {
Request::Account(ref req) => req.check_outputs(f),
Request::Storage(ref req) => req.check_outputs(f),
Request::Code(ref req) => req.check_outputs(f),
Request::Execution(ref req) => req.check_outputs(f),
}
}
@ -267,29 +278,31 @@ impl IncompleteRequest for Request {
Request::Account(ref req) => req.note_outputs(f),
Request::Storage(ref req) => req.note_outputs(f),
Request::Code(ref req) => req.note_outputs(f),
Request::Execution(ref req) => req.note_outputs(f),
}
}
fn fill<F>(self, oracle: F) -> Result<Self::Complete, NoSuchOutput>
where F: Fn(usize, usize) -> Result<Output, NoSuchOutput>
{
match self {
Request::Headers(req) => CompleteRequest::Headers(req.fill(oracle)),
Request::HeaderProof(req) => CompleteRequest::HeaderProof(req.fill(oracle)),
Request::Receipts(req) => CompleteRequest::Receipts(req.fill(oracle)),
Request::Body(req) => CompleteRequest::Body(req.fill(oracle)),
Request::Account(req) => CompleteRequest::Account(req.fill(oracle)),
Request::Storage(req) => CompleteRequest::Storage(req.fill(oracle)),
Request::Code(req) => CompleteRequest::Code(req.fill(oracle)),
}
Ok(match self {
Request::Headers(req) => CompleteRequest::Headers(req.fill(oracle)?),
Request::HeaderProof(req) => CompleteRequest::HeaderProof(req.fill(oracle)?),
Request::Receipts(req) => CompleteRequest::Receipts(req.fill(oracle)?),
Request::Body(req) => CompleteRequest::Body(req.fill(oracle)?),
Request::Account(req) => CompleteRequest::Account(req.fill(oracle)?),
Request::Storage(req) => CompleteRequest::Storage(req.fill(oracle)?),
Request::Code(req) => CompleteRequest::Code(req.fill(oracle)?),
Request::Execution(req) => CompleteRequest::Execution(req.fill(oracle)?),
})
}
}
/// Kinds of requests.
/// Doubles as the "ID" field of the request.
#[repr(u8)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RequestKind {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Kind {
/// A request for headers.
Headers = 0,
HeaderProof = 1,
@ -299,29 +312,29 @@ pub enum RequestKind {
Account = 5,
Storage = 6,
Code = 7,
// TransactionProof = 8,
Execution = 8,
}
impl Decodable for RequestKind {
impl Decodable for Kind {
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),
0 => Ok(Kind::Headers),
1 => Ok(Kind::HeaderProof),
// 2 => Ok(Kind::TransactionIndex,
3 => Ok(Kind::Receipts),
4 => Ok(Kind::Body),
5 => Ok(Kind::Account),
6 => Ok(Kind::Storage),
7 => Ok(Kind::Code),
8 => Ok(Kind::Execution),
_ => Err(DecoderError::Custom("Unknown PIP request ID.")),
}
}
}
impl Encodable for RequestKind {
impl Encodable for Kind {
fn rlp_append(&self, s: &mut RlpStream) {
s.append(self as &u8);
}
@ -345,22 +358,71 @@ pub enum Response {
Storage(StorageResponse),
/// A response for contract code.
Code(CodeResponse),
// Transaction proof.
/// A response for proof of execution,
Execution(ExecutionResponse),
}
impl Response {
/// Fill reusable outputs by writing them into the function.
pub fn fill_outputs<F>(&self, mut f: F) where F: FnMut(usize, Output) {
match *self {
Response::Headers(res) => res.fill_outputs(f)
Response::HeaderProof(res) => res.fill_outputs(f)
Response::Receipts(res) => res.fill_outputs(f)
Response::Body(res) => res.fill_outputs(f)
Response::Account(res) => res.fill_outputs(f)
Response::Storage(res) => res.fill_outputs(f)
Response::Code(res) => res.fill_outputs(f)
Response::Headers(res) => res.fill_outputs(f),
Response::HeaderProof(res) => res.fill_outputs(f),
Response::Receipts(res) => res.fill_outputs(f),
Response::Body(res) => res.fill_outputs(f),
Response::Account(res) => res.fill_outputs(f),
Response::Storage(res) => res.fill_outputs(f),
Response::Code(res) => res.fill_outputs(f),
Response::Execution(res) => res.fill_outputs(f),
}
}
fn kind(&self) -> Kind {
match *self {
Response::Headers(_) => Kind::Headers,
Response::HeaderProof(_) => Kind::HeaderProof,
Response::Receipts(_) => Kind::Receipts,
Response::Body(_) => Kind::Body,
Response::Account(_) => Kind::Account,
Response::Storage(_) => Kind::Storage,
Response::Code(_) => Kind::Code,
Respnse::Execution(_) => Kind::Execution,
}
}
}
impl Decodable for Response {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let rlp = decoder.as_rlp();
match rlp.val_at::<Kind>(0)? {
Kind::Headers => Ok(Response::Headers(rlp.val_at(1)?)),
Kind::HeaderProof => Ok(Response::HeaderProof(rlp.val_at(1)?)),
Kind::Receipts => Ok(Response::Receipts(rlp.val_at(1)?)),
Kind::Body => Ok(Response::Body(rlp.val_at(1)?)),
Kind::Account => Ok(Response::Account(rlp.val_at(1)?)),
Kind::Storage => Ok(Response::Storage(rlp.val_at(1)?)),
Kind::Code => Ok(Response::Code(rlp.val_at(1)?)),
Kind::Execution=> Ok(Response::Execution(rlp.val_at(1)?)),
}
}
}
impl Encodable for Response {
fn rlp_append(&self, s: &mut RlpStream) {
s.begin_list(2).append(&self.kind());
match *self {
Response::Headers(ref res) => s.append(res),
Response::HeaderProof(ref res) => s.append(res),
Response::Receipts(ref res) => s.append(res),
Response::Body(ref res) => s.append(res),
Response::Account(ref res) => s.append(res),
Response::Storage(ref res) => s.append(res),
Response::Code(ref res) => s.append(res),
Response::Execution(ref res) => s.append(res),
};
}
}
/// A potentially incomplete request.
@ -390,7 +452,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 rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream, View};
use util::U256;
/// Potentially incomplete headers request.
@ -488,12 +550,41 @@ pub mod header {
/// Fill reusable outputs by writing them into the function.
pub fn fill_outputs<F>(&self, _: F) where F: FnMut(usize, Output) { }
}
impl Decodable for Response {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
use ethcore::header::Header as FullHeader;
let rlp = decoder.as_rlp();
let mut headers = Vec::new();
for item in rlp.at(0)?.iter() {
// check that it's a valid encoding.
// TODO: just return full headers here?
let _: FullHeader = item.as_val()?;
headers.push(encoded::Header::new(item.as_raw().to_owned()));
}
Ok(Response {
headers: headers,
})
}
}
impl Encodable for Response {
fn rlp_append(&self, s: &mut RlpStream) {
s.begin_list(self.headers.len());
for header in &self.headers {
s.append_raw(header.rlp().as_raw(), 1);
}
}
}
}
/// 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 rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream, View};
use util::{Bytes, U256, H256};
/// Potentially incomplete header proof request.
@ -576,12 +667,34 @@ pub mod header_proof {
f(1, Output::Hash(self.hash));
}
}
impl Decodable for Response {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let rlp = decoder.as_rlp();
Ok(Response {
proof: rlp.val_at(0)?,
hash: rlp.val_at(1)?,
td: rlp.val_at(2)?,
})
}
}
impl Encodable for Response {
fn rlp_append(&self, s: &mut RlpStream) {
s.begin_list(3)
.append(&self.proof)
.append(&self.hash)
.append(&self.td);
}
}
}
/// 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 ethcore::receipt::Receipt;
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream, View};
use util::{Bytes, U256, H256};
/// Potentially incomplete block receipts request.
@ -655,13 +768,29 @@ pub mod block_receipts {
/// Fill reusable outputs by providing them to the function.
pub fn fill_outputs<F>(&self, _: F) where F: FnMut(usize, Output) {}
}
impl Decodable for Response {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let rlp = decoder.as_rlp();
Ok(Response {
receipts: rlp.val_at(0)?,
})
}
}
impl Encodable for Response {
fn rlp_append(&self, s: &mut RlpStream) {
s.append(&self.receipts);
}
}
}
/// Request and response for a block body
pub mod block_body {
use super::{Field, NoSuchOutput, OutputKind, Output};
use ethcore::encoded;
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream};
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream, View};
use util::{Bytes, U256, H256};
/// Potentially incomplete block body request.
@ -736,13 +865,38 @@ pub mod block_body {
/// Fill reusable outputs by providing them to the function.
pub fn fill_outputs<F>(&self, _: F) where F: FnMut(usize, Output) {}
}
impl Decodable for Response {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
use ethcore::header::Header as FullHeader;
use ethcore::transaction::SignedTransaction;
let rlp = decoder.as_rlp();
let body_rlp = rlp.at(0)?;
// check body validity.
let _: Vec<FullHeader> = rlp.val_at(0)?;
let _: Vec<SignedTransaction> = rlp.val_at(1)?;
Ok(Response {
body: encoded::Body::new(body_rlp.as_raw().to_owned()),
})
}
}
impl Encodable for Response {
fn rlp_append(&self, s: &mut RlpStream) {
s.begin_list(2)
.append_raw(&self.body.rlp().as_raw(), 2);
}
}
}
/// A request for an account proof.
pub mod account {
use super::{Field, NoSuchOutput, OutputKind, Output};
use ethcore::encoded;
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream};
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream, View};
use util::{Bytes, U256, H256};
/// Potentially incomplete request for an account proof.
@ -852,13 +1006,38 @@ pub mod account {
f(1, Output::Hash(self.storage_root));
}
}
impl Decodable for Response {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let rlp = decoder.as_rlp();
Ok(Response {
proof: rlp.val_at(0)?,
nonce: rlp.val_at(1)?,
balance: rlp.val_at(2)?,
code_hash: rlp.val_at(3)?,
storage_root: rlp.val_at(4)?
})
}
}
impl Encodable for Response {
fn rlp_append(&self, s: &mut RlpStream) {
s.begin_list(5)
.append(&self.proof)
.append(&self.nonce)
.append(&self.balance)
.append(&self.code_hash)
.append(&self.storage_root)
}
}
}
/// A request for a storage proof.
pub mod storage {
use super::{Field, NoSuchOutput, OutputKind, Output};
use ethcore::encoded;
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream};
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream, View};
use util::{Bytes, U256, H256};
/// Potentially incomplete request for an storage proof.
@ -979,16 +1158,35 @@ pub mod storage {
f(0, Output::Hash(self.value));
}
}
impl Decodable for Response {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let rlp = decoder.as_rlp();
Ok(Response {
proof: rlp.val_at(0)?,
value: rlp.val_at(1)?,
})
}
}
impl Encodable for Response {
fn rlp_append(&self, s: &mut RlpStream) {
s.begin_list(2)
.append(&self.proof)
.append(&self.value);
}
}
}
/// A request for contract code.
pub mod contract_code {
use super::{Field, NoSuchOutput, OutputKind, Output};
use ethcore::encoded;
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream};
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream, View};
use util::{Bytes, U256, H256};
/// Potentially incomplete _ request.
/// Potentially incomplete contract code request.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Incomplete {
/// The block hash to request the state for.
@ -1080,4 +1278,177 @@ pub mod contract_code {
/// Fill reusable outputs by providing them to the function.
pub fn fill_outputs<F>(&self, _: F) where F: FnMut(usize, Output) {}
}
impl Decodable for Response {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let rlp = decoder.as_rlp();
Ok(Response {
code: rlp.val_at(0)?,
})
}
}
impl Encodable for Response {
fn rlp_append(&self, s: &mut RlpStream) {
s.append(&self.code);
}
}
}
/// A request for proof of execution.
pub mod execution {
use super::{Field, NoSuchOutput, OutputKind, Output};
use ethcore::encoded;
use ethcore::transaction::Action;
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream, View};
use util::{Bytes, Address, U256, H256, DBValue};
/// Potentially incomplete execution proof request.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Incomplete {
/// The block hash to request the state for.
pub block_hash: Field<H256>,
/// The address the transaction should be from.
pub from: Address,
/// The action of the transaction.
pub action: Action,
/// The amount of gas to prove.
pub gas: U256,
/// The gas price.
pub gas_price: U256,
/// The value to transfer.
pub value: U256,
/// Call data.
pub data: Bytes,
}
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: rlp.val_at(1)?,
action: rlp.val_at(2)?,
gas: rlp.val_at(3)?,
gas_price: rlp.val_at(4)?,
value: rlp.val_at(5)?,
data: rlp.val_at(6)?,
})
}
}
impl Encodable for Incomplete {
fn rlp_append(&self, s: &mut RlpStream) {
s.begin_list(7)
.append(&self.block_hash)
.append(&self.from);
match *self.action {
Action::Create => s.append_empty_data(),
Action::Call(ref addr) => s.append(addr),
};
s.append(&self.gas)
.append(&self.gas_price)
.append(&self.value)
.append(&self.data);
}
}
impl super::IncompleteRequest for Incomplete {
type Complete = Complete;
fn check_outputs<F>(&self, mut f: F) -> Result<(), NoSuchOutput>
where F: FnMut(usize, usize, OutputKind) -> Result<(), NoSuchOutput>
{
if let Field::BackReference(req, idx) = self.block_hash {
f(req, idx, OutputKind::Hash)?;
}
Ok(())
}
fn note_outputs<F>(&self, _: F) where F: FnMut(usize, OutputKind) {}
fn fill<F>(self, oracle: F) -> Result<Self::Complete, NoSuchOutput>
where F: Fn(usize, usize) -> Result<Output, NoSuchOutput>
{
let block_hash = match self.block_hash {
Field::Scalar(hash) => hash,
Field::BackReference(req, idx) => match oracle(req, idx)? {
Output::Hash(hash) => hash,
_ => return Err(NoSuchOutput)?,
}
};
Ok(Complete {
block_hash: block_hash,
from: self.from,
action: self.action,
gas: self.gas,
gas_price: self.gas_price,
value: self.value,
data: self.data,
})
}
}
/// A complete request.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Complete {
/// The block hash to request the state for.
pub block_hash: H256,
/// The address the transaction should be from.
pub from: Address,
/// The action of the transaction.
pub action: Action,
/// The amount of gas to prove.
pub gas: U256,
/// The gas price.
pub gas_price: U256,
/// The value to transfer.
pub value: U256,
/// Call data.
pub data: Bytes,
}
/// The output of a request for proof of execution
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Response {
/// All state items (trie nodes, code) necessary to re-prove the transaction.
pub items: Vec<DBValue>,
}
impl Response {
/// Fill reusable outputs by providing them to the function.
pub fn fill_outputs<F>(&self, _: F) where F: FnMut(usize, Output) {}
}
impl Decodable for Response {
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
let rlp = decoder.as_rlp();
let mut items = Vec::new();
for raw_item in rlp.at(0)?.iter() {
let mut item = DBValue::new();
item.append_slice(raw_item.data());
items.push(item);
}
Ok(Response {
items: items,
})
}
}
impl Encodable for Response {
fn rlp_append(&self, s: &mut RlpStream) {
s.begin_list(&self.items.len());
for item in &self.items {
s.append(&&**item);
}
}
}
}