diff --git a/ethcore/light/src/lib.rs b/ethcore/light/src/lib.rs index b6e06a02b..ebf5f4f08 100644 --- a/ethcore/light/src/lib.rs +++ b/ethcore/light/src/lib.rs @@ -57,7 +57,7 @@ mod types; pub use self::provider::Provider; pub use self::transaction_queue::TransactionQueue; -pub use types::les_request as request; +pub use types::request as request; #[macro_use] extern crate log; diff --git a/ethcore/light/src/types/les_request.rs b/ethcore/light/src/types/les_request.rs deleted file mode 100644 index dbff19eb5..000000000 --- a/ethcore/light/src/types/les_request.rs +++ /dev/null @@ -1,228 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (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 . - -//! LES request types. - -use ethcore::transaction::Action; -use util::{Address, H256, U256, Uint}; - -/// Either a hash or a number. -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "ipc", binary)] -pub enum HashOrNumber { - /// Block hash variant. - Hash(H256), - /// Block number variant. - Number(u64), -} - -impl From for HashOrNumber { - fn from(hash: H256) -> Self { - HashOrNumber::Hash(hash) - } -} - -impl From for HashOrNumber { - fn from(num: u64) -> Self { - HashOrNumber::Number(num) - } -} - -/// A request for block headers. -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "ipc", binary)] -pub struct Headers { - /// Starting block number or hash. - pub start: HashOrNumber, - /// The maximum amount of headers which can be returned. - pub max: usize, - /// The amount of headers to skip between each response entry. - pub skip: u64, - /// Whether the headers should proceed in falling number from the initial block. - pub reverse: bool, -} - -/// A request for specific block bodies. -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "ipc", binary)] -pub struct Bodies { - /// Hashes which bodies are being requested for. - pub block_hashes: Vec -} - -/// A request for transaction receipts. -/// -/// This request is answered with a list of transaction receipts for each block -/// requested. -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "ipc", binary)] -pub struct Receipts { - /// Block hashes to return receipts for. - pub block_hashes: Vec, -} - -/// A request for a state proof -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "ipc", binary)] -pub struct StateProof { - /// 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, - /// 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. -} - -/// A request for state proofs. -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "ipc", binary)] -pub struct StateProofs { - /// All the proof requests. - pub requests: Vec, -} - -/// A request for contract code. -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "ipc", binary)] -pub struct ContractCode { - /// Block hash - pub block_hash: H256, - /// Account key (== sha3(address)) - pub account_key: H256, -} - -/// A request for contract code. -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "ipc", binary)] -pub struct ContractCodes { - /// Block hash and account key (== sha3(address)) pairs to fetch code for. - pub code_requests: Vec, -} - -/// A request for a header proof from the Canonical Hash Trie. -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "ipc", binary)] -pub struct HeaderProof { - /// Number of the CHT. - pub cht_number: u64, - /// Block number requested. May not be 0: genesis isn't included in any CHT. - pub block_number: u64, - /// If greater than zero, trie nodes beyond this level may be omitted. - pub from_level: u32, -} - -/// A request for header proofs from the CHT. -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "ipc", binary)] -pub struct HeaderProofs { - /// All the proof requests. - pub requests: Vec, -} - -/// A request for proof of (simulated) transaction execution. -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "ipc", binary)] -pub struct TransactionProof { - /// Block hash to request for. - pub at: H256, - /// Address to treat as the caller. - pub from: Address, - /// Action to take: either a call or a create. - pub action: Action, - /// Amount of gas to request proof-of-execution for. - pub gas: U256, - /// Price for each gas. - pub gas_price: U256, - /// Value to simulate sending. - pub value: U256, - /// Transaction data. - pub data: Vec, -} - -/// Kinds of requests. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "ipc", binary)] -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 proof of transaction execution. - TransactionProof, -} - -/// Encompasses all possible types of requests in a single structure. -#[derive(Debug, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "ipc", binary)] -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 proof of transaction execution. - TransactionProof(TransactionProof), -} - -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::TransactionProof(_) => Kind::TransactionProof, - } - } - - /// Get the amount of requests being made. - /// In the case of `TransactionProof`, this is the amount of gas being requested. - pub fn amount(&self) -> usize { - match *self { - Request::Headers(ref req) => req.max, - Request::Bodies(ref req) => req.block_hashes.len(), - Request::Receipts(ref req) => req.block_hashes.len(), - Request::StateProofs(ref req) => req.requests.len(), - Request::Codes(ref req) => req.code_requests.len(), - Request::HeaderProofs(ref req) => req.requests.len(), - Request::TransactionProof(ref req) => match req.gas > usize::max_value().into() { - true => usize::max_value(), - false => req.gas.low_u64() as usize, - } - } - } -} diff --git a/ethcore/light/src/types/mod.rs.in b/ethcore/light/src/types/mod.rs.in index 0adfbf0e4..eba551b53 100644 --- a/ethcore/light/src/types/mod.rs.in +++ b/ethcore/light/src/types/mod.rs.in @@ -14,4 +14,4 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -pub mod les_request; \ No newline at end of file +pub mod request; diff --git a/ethcore/light/src/types/request.rs b/ethcore/light/src/types/request.rs new file mode 100644 index 000000000..279296cf8 --- /dev/null +++ b/ethcore/light/src/types/request.rs @@ -0,0 +1,707 @@ +// Copyright 2015-2017 Parity Technologies (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 . + +//! Light protocol request types. + +use std::collections::HashMap; + +use ethcore::transaction::Action; +use util::{Address, H256, U256, Uint}; + +// re-exports of request types. +pub use self::header::{ + Complete as CompleteHeadersRequest, + Incomplete as IncompleteHeadersRequest, + Response as HeadersResponse +}; +pub use self::header_proof::{ + Complete as CompleteHeaderProofRequest, + Incomplete as IncompleteHeaderProofRequest, + Response as HeaderProofResponse +}; +pub use self::block_body::{ + Complete as CompleteBodyRequest, + Incomplete as IncompleteBodyRequest, + Response as BodyResponse +}; +pub use self::receipts::{ + Complete as CompleteReceiptsRequest, + Incomplete as IncompleteReceiptsRequest + Response as ReceiptsResponse +}; +pub use self::account::{ + Complete as CompleteAccountRequest, + Incomplete as IncompleteAccountRequest, + Response as AccountResponse, +}; +pub use self::storage::{ + Complete as CompleteStorageRequest, + Incomplete as IncompleteStorageRequest, + Response as StorageResponse +}; +pub use self::contract_code::{ + Complete as CompleteCodeRequest, + Incomplete as IncompleteCodeRequest, + Response as CodeResponse, +}; + +/// Error indicating a reference to a non-existent or wrongly-typed output. +pub struct NoSuchOutput; + +/// An input to a request. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Field { + /// A pre-specified input. + Scalar(T), + /// An input which can be resolved later on. + /// (Request index, output index) + BackReference(usize, usize), +} + +impl From for Field { + fn from(val: T) -> Self { + Field::Scalar(val) + } +} + +/// Request outputs which can be reused as inputs. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Output { + /// A 32-byte hash output. + Hash(H256), + /// An unsigned-integer output. + Number(u64), +} + +/// Response output kinds which can be used as back-references. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum OutputKind { + /// A 32-byte hash output. + Hash, + /// An unsigned-integer output. + Number, +} + +/// Either a hash or a number. +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "ipc", binary)] +pub enum HashOrNumber { + /// Block hash variant. + Hash(H256), + /// Block number variant. + Number(u64), +} + +impl From for HashOrNumber { + fn from(hash: H256) -> Self { + HashOrNumber::Hash(hash) + } +} + +impl From for HashOrNumber { + fn from(num: u64) -> Self { + HashOrNumber::Number(num) + } +} + +/// A potentially incomplete request. +pub trait IncompleteRequest: Sized { + type Complete; + + /// Check prior outputs against the needed inputs. + /// + /// This is called to ensure consistency of this request with + /// others in the same packet. + fn check_outputs(&self, f: F) -> Result<(), NoSuchOutput> + where F: FnMut(usize, usize, OutputKind) -> Result<(), NoSuchOutput>; + + /// Note that this request will produce the following outputs. + fn note_outputs(&self, f: F) where F: FnMut(usize, OutputKind); + + /// Fill the request. + /// + /// This function is provided an "output oracle" which allows fetching of + /// prior request outputs. + /// Only outputs previously checked with `check_outputs` will be available. + fn fill(self, oracle: F) -> Result + where F: Fn(usize, usize) -> Result; +} + +/// Header request. +pub mod header { + use super::{Field, HashOrNumber, NoSuchOutput, OutputKind, Output}; + use ethcore::encoded; + use util::U256; + + /// Potentially incomplete headers request. + #[derive(Debug, Clone, PartialEq, Eq)] + pub struct Incomplete { + /// Start block. + pub start: Field, + /// Skip between. + pub skip: U256, + /// Maximum to return. + pub max: U256, + /// Whether to reverse from start. + pub reverse: bool, + } + + impl super::IncompleteRequest for Incomplete { + type Complete = Complete; + + fn check_outputs(&self, mut f: F) -> Result<(), NoSuchOutput> + where F: FnMut(usize, usize, OutputKind) -> Result<(), NoSuchOutput> + { + match self.start { + Field::Scalar(_) => Ok(()), + Field::BackReference(req, idx) => + f(req, idx, OutputKind::Hash).or_else(|| f(req, idx, OutputKind::Number)) + } + } + + fn note_outputs(&self, _: F) where F: FnMut(usize, OutputKind) { } + + fn fill(self, oracle: F) -> Result + where F: Fn(usize, usize) -> Result + { + let start = match self.start { + Field::Scalar(start) => start, + Field::BackReference(req, idx) => match oracle(req, idx)? { + Output::Hash(hash) => hash.into(), + Output::Number(num) => num.into(), + } + }; + + Ok(Complete { + start: start, + skip: self.skip, + max: self.max, + reverse: self.reverse, + }) + } + + } + + /// A complete header request. + #[derive(Debug, Clone, PartialEq, Eq)] + pub struct Complete { + /// Start block. + pub start: HashOrNumber, + /// Skip between. + pub skip: U256, + /// Maximum to return. + pub max: U256, + /// Whether to reverse from start. + pub reverse: bool, + } + + /// The output of a request for headers. + #[derive(Debug, Clone, PartialEq, Eq)] + pub struct Response { + header: Vec, + } + + impl Response { + /// Fill reusable outputs by writing them into the function. + pub fn fill_outputs(&self, _: F) where F: FnMut(usize, Output) { } + } +} + +/// Request and response for header proofs. +pub mod header_proof { + use super::{Field, NoSuchOutput, OutputKind, Output}; + use util::{Bytes, U256, H256}; + + /// Potentially incomplete header proof request. + #[derive(Debug, Clone, PartialEq, Eq)] + pub struct Incomplete { + /// Block number. + pub num: Field, + } + + impl super::IncompleteRequest for Incomplete { + type Complete = Complete; + + fn check_outputs(&self, mut f: F) -> Result<(), NoSuchOutput> + where F: FnMut(usize, usize, OutputKind) -> Result<(), NoSuchOutput> + { + match self.num { + Field::Scalar(_) => Ok(()), + Field::BackReference(req, idx) => f(req, idx, OutputKind::Number), + } + } + + fn note_outputs(&self, mut note: F) where F: FnMut(usize, OutputKind) { + note(1, OutputKind::Hash); + } + + fn fill(self, oracle: F) -> Result + where F: Fn(usize, usize) -> Result + { + let num = match self.num { + Field::Scalar(num) => num, + Field::BackReference(req, idx) => match oracle(req, idx)? { + Output::Number(num) => num, + _ => return Err(NoSuchOutput), + } + }; + + Ok(Complete { + num: num, + }) + } + + } + + /// A complete header proof request. + #[derive(Debug, Clone, PartialEq, Eq)] + pub struct Complete { + /// The number to get a header proof for. + pub num: u64, + } + + /// The output of a request for a header proof. + #[derive(Debug, Clone, PartialEq, Eq)] + pub struct Response { + /// Inclusion proof of the header and total difficulty in the CHT. + pub proof: Vec, + /// The proved header's hash. + pub hash: H256, + /// The proved header's total difficulty. + pub td: U256, + } + + impl Response { + /// Fill reusable outputs by providing them to the function. + pub fn fill_outputs(&self, mut f: F) where F: FnMut(usize, Output) { + f(1, Output::Hash(self.hash)); + } + } +} + +/// Request and response for block receipts +pub mod block_receipts { + use super::{Field, NoSuchOutput, OutputKind, Output}; + use util::{Bytes, U256, H256}; + + /// Potentially incomplete block receipts request. + #[derive(Debug, Clone, PartialEq, Eq)] + pub struct Incomplete { + /// Block hash to get receipts for. + pub hash: Field, + } + + impl super::IncompleteRequest for Incomplete { + type Complete = Complete; + + fn check_outputs(&self, mut f: F) -> Result<(), NoSuchOutput> + where F: FnMut(usize, usize, OutputKind) -> Result<(), NoSuchOutput> + { + match self.num { + Field::Scalar(_) => Ok(()), + Field::BackReference(req, idx) => f(req, idx, OutputKind::Hash), + } + } + + fn note_outputs(&self, _: F) where F: FnMut(usize, OutputKind) {} + + fn fill(self, oracle: F) -> Result + where F: Fn(usize, usize) -> Result + { + let hash = match self.hash { + Field::Scalar(hash) => hash, + Field::BackReference(req, idx) => match oracle(req, idx)? { + Output::Hash(hash) => hash, + _ => return Err(NoSuchOutput), + } + }; + + Ok(Complete { + hash: hash, + }) + } + + } + + /// A complete block receipts request. + #[derive(Debug, Clone, PartialEq, Eq)] + pub struct Complete { + /// The number to get block receipts for. + pub hash: H256, + } + + /// The output of a request for block receipts. + #[derive(Debug, Clone, PartialEq, Eq)] + pub struct Response { + /// The block receipts. + pub receipts: Vec + } + + impl Response { + /// Fill reusable outputs by providing them to the function. + pub fn fill_outputs(&self, _: F) where F: FnMut(usize, Output) {} + } +} + +/// Request and response for a block body +pub mod block_body { + use super::{Field, NoSuchOutput, OutputKind, Output}; + use ethcore::encoded; + use util::{Bytes, U256, H256}; + + /// Potentially incomplete block body request. + #[derive(Debug, Clone, PartialEq, Eq)] + pub struct Incomplete { + /// Block hash to get receipts for. + pub hash: Field, + } + + impl super::IncompleteRequest for Incomplete { + type Complete = Complete; + + fn check_outputs(&self, mut f: F) -> Result<(), NoSuchOutput> + where F: FnMut(usize, usize, OutputKind) -> Result<(), NoSuchOutput> + { + match self.num { + Field::Scalar(_) => Ok(()), + Field::BackReference(req, idx) => f(req, idx, OutputKind::Hash), + } + } + + fn note_outputs(&self, _: F) where F: FnMut(usize, OutputKind) {} + + fn fill(self, oracle: F) -> Result + where F: Fn(usize, usize) -> Result + { + let hash = match self.hash { + Field::Scalar(hash) => hash, + Field::BackReference(req, idx) => match oracle(req, idx)? { + Output::Hash(hash) => hash, + _ => return Err(NoSuchOutput), + } + }; + + Ok(Complete { + hash: hash, + }) + } + + } + + /// A complete block body request. + #[derive(Debug, Clone, PartialEq, Eq)] + pub struct Complete { + /// The hash to get a block body for. + pub hash: H256, + } + + /// The output of a request for block body. + #[derive(Debug, Clone, PartialEq, Eq)] + pub struct Response { + /// The block body. + pub body: encoded::Body, + } + + impl Response { + /// Fill reusable outputs by providing them to the function. + pub fn fill_outputs(&self, _: F) where F: FnMut(usize, Output) {} + } +} + +/// A request for an account proof. +pub mod account { + use super::{Field, NoSuchOutput, OutputKind, Output}; + use ethcore::encoded; + use util::{Bytes, U256, H256}; + + /// Potentially incomplete request for an account proof. + #[derive(Debug, Clone, PartialEq, Eq)] + pub struct Incomplete { + /// Block hash to request state proof for. + pub block_hash: Field, + /// Hash of the account's address. + pub address_hash: Field, + } + + impl super::IncompleteRequest for Incomplete { + type Complete = Complete; + + fn check_outputs(&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)? + } + + if let Field::BackReference(req, idx) = self.address_hash { + f(req, idx, OutputKind::Hash)? + } + + Ok(()) + } + + fn note_outputs(&self, mut f: F) where F: FnMut(usize, OutputKind) { + f(0, OutputKind::Hash); + f(1, OutputKind::Hash); + } + + fn fill(self, oracle: F) -> Result + where F: Fn(usize, usize) -> Result + { + 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)?, + } + }; + + let address_hash = match self.address_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, + address_hash: address_hash, + }) + } + + } + + /// A complete request for an account. + #[derive(Debug, Clone, PartialEq, Eq)] + pub struct Complete { + /// Block hash to request state proof for. + pub block_hash: H256, + /// Hash of the account's address. + pub address_hash: H256, + } + + /// The output of a request for an account state proof. + #[derive(Debug, Clone, PartialEq, Eq)] + pub struct Response { + /// Inclusion/exclusion proof + pub proof: Vec, + /// Account nonce. + pub nonce: U256, + /// Account balance. + pub balance: U256, + /// Account's code hash. + pub code_hash: H256, + /// Account's storage trie root. + pub storage_root: H256, + } + + impl Response { + /// Fill reusable outputs by providing them to the function. + pub fn fill_outputs(&self, mut f: F) where F: FnMut(usize, Output) { + f(0, Output::Hash(self.code_hash)); + f(1, Output::Hash(self.storage_root)); + } + } +} + +/// A request for a storage proof. +pub mod storage { + use super::{Field, NoSuchOutput, OutputKind, Output}; + use ethcore::encoded; + use util::{Bytes, U256, H256}; + + /// Potentially incomplete request for an storage proof. + #[derive(Debug, Clone, PartialEq, Eq)] + pub struct Incomplete { + /// Block hash to request state proof for. + pub block_hash: Field, + /// Hash of the account's address. + pub address_hash: Field, + /// Hash of the storage key. + pub key_hash: Field, + } + + impl super::IncompleteRequest for Incomplete { + type Complete = Complete; + + fn check_outputs(&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)? + } + + if let Field::BackReference(req, idx) = self.address_hash { + f(req, idx, OutputKind::Hash)? + } + + if let Field::BackReference(req, idx) = self.key_hash { + f(req, idx, OutputKind::Hash)? + } + + Ok(()) + } + + fn note_outputs(&self, mut f: F) where F: FnMut(usize, OutputKind) { + f(0, OutputKind::Hash); + } + + fn fill(self, oracle: F) -> Result + where F: Fn(usize, usize) -> Result + { + 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)?, + } + }; + + let address_hash = match self.address_hash { + Field::Scalar(hash) => hash, + Field::BackReference(req, idx) => match oracle(req, idx)? { + Output::Hash(hash) => hash, + _ => return Err(NoSuchOutput)?, + } + }; + + let key_hash = match self.key_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, + address_hash: address_hash, + key_hash: key_hash + }) + } + + } + + /// A complete request for a storage proof. + #[derive(Debug, Clone, PartialEq, Eq)] + pub struct Complete { + /// Block hash to request state proof for. + pub block_hash: H256, + /// Hash of the account's address. + pub address_hash: H256, + /// Storage key hash. + pub key_hash: H256, + } + + /// The output of a request for an account state proof. + #[derive(Debug, Clone, PartialEq, Eq)] + pub struct Response { + /// Inclusion/exclusion proof + pub proof: Vec, + /// Storage value. + pub value: H256, + } + + impl Response { + /// Fill reusable outputs by providing them to the function. + pub fn fill_outputs(&self, mut f: F) where F: FnMut(usize, Output) { + f(0, Output::Hash(self.value)); + } + } +} + +/// A request for contract code. +pub mod contract_code { + use super::{Field, NoSuchOutput, OutputKind, Output}; + use ethcore::encoded; + use util::{Bytes, U256, H256}; + + /// Potentially incomplete _ request. + #[derive(Debug, Clone, PartialEq, Eq)] + pub struct Incomplete { + /// The block hash to request the state for. + pub block_hash: Field, + /// The code hash. + pub code_hash: Field, + } + + impl super::IncompleteRequest for Incomplete { + type Complete = Complete; + + fn check_outputs(&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)?; + } + if let Field::BackReference(req, idx) = self.code_hash { + f(req, idx, OutputKind::Hash)?; + } + + Ok(()) + } + + fn note_outputs(&self, _: F) where F: FnMut(usize, OutputKind) {} + + fn fill(self, oracle: F) -> Result + where F: Fn(usize, usize) -> Result + { + 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)?, + } + }; + + let code_hash = match self.code_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, + code_hash: code_hash, + }) + } + + } + + /// A complete request. + #[derive(Debug, Clone, PartialEq, Eq)] + pub struct Complete { + /// The block hash to request the state for. + pub block_hash: H256, + /// The code hash. + pub code_hash: H256, + } + + /// The output of a request for + #[derive(Debug, Clone, PartialEq, Eq)] + pub struct Response { + /// The requested code. + pub code: Bytes, + } + + impl Response { + /// Fill reusable outputs by providing them to the function. + pub fn fill_outputs(&self, _: F) where F: FnMut(usize, Output) {} + } +}