complete initial request changes
This commit is contained in:
parent
b396b56e34
commit
04291fe71e
@ -1,5 +1,5 @@
|
|||||||
[package]
|
[package]
|
||||||
description = "Parity LES primitives"
|
description = "Parity Light Client Implementation"
|
||||||
homepage = "http://parity.io"
|
homepage = "http://parity.io"
|
||||||
license = "GPL-3.0"
|
license = "GPL-3.0"
|
||||||
name = "ethcore-light"
|
name = "ethcore-light"
|
||||||
|
@ -35,9 +35,10 @@
|
|||||||
pub mod client;
|
pub mod client;
|
||||||
pub mod cht;
|
pub mod cht;
|
||||||
pub mod net;
|
pub mod net;
|
||||||
pub mod on_demand;
|
//pub mod on_demand;
|
||||||
pub mod transaction_queue;
|
pub mod transaction_queue;
|
||||||
pub mod cache;
|
pub mod cache;
|
||||||
|
pub mod request_builder;
|
||||||
|
|
||||||
#[cfg(not(feature = "ipc"))]
|
#[cfg(not(feature = "ipc"))]
|
||||||
pub mod provider;
|
pub mod provider;
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// 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/>.
|
||||||
|
|
||||||
//! I/O and event context generalizations.
|
//! I/O and event context generalizations.
|
||||||
|
|
||||||
@ -89,10 +89,6 @@ pub trait BasicContext {
|
|||||||
// TODO: maybe just put this on a timer in LightProtocol?
|
// TODO: maybe just put this on a timer in LightProtocol?
|
||||||
fn make_announcement(&self, announcement: Announcement);
|
fn make_announcement(&self, announcement: Announcement);
|
||||||
|
|
||||||
/// Find the maximum number of requests of a specific type which can be made from
|
|
||||||
/// supplied peer.
|
|
||||||
fn max_requests(&self, peer: PeerId, kind: request::Kind) -> usize;
|
|
||||||
|
|
||||||
/// Disconnect a peer.
|
/// Disconnect a peer.
|
||||||
fn disconnect_peer(&self, peer: PeerId);
|
fn disconnect_peer(&self, peer: PeerId);
|
||||||
|
|
||||||
@ -131,10 +127,6 @@ impl<'a> BasicContext for TickCtx<'a> {
|
|||||||
self.proto.make_announcement(self.io, announcement);
|
self.proto.make_announcement(self.io, announcement);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn max_requests(&self, peer: PeerId, kind: request::Kind) -> usize {
|
|
||||||
self.proto.max_requests(peer, kind)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn disconnect_peer(&self, peer: PeerId) {
|
fn disconnect_peer(&self, peer: PeerId) {
|
||||||
self.io.disconnect_peer(peer);
|
self.io.disconnect_peer(peer);
|
||||||
}
|
}
|
||||||
@ -168,10 +160,6 @@ impl<'a> BasicContext for Ctx<'a> {
|
|||||||
self.proto.make_announcement(self.io, announcement);
|
self.proto.make_announcement(self.io, announcement);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn max_requests(&self, peer: PeerId, kind: request::Kind) -> usize {
|
|
||||||
self.proto.max_requests(peer, kind)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn disconnect_peer(&self, peer: PeerId) {
|
fn disconnect_peer(&self, peer: PeerId) {
|
||||||
self.io.disconnect_peer(peer);
|
self.io.disconnect_peer(peer);
|
||||||
}
|
}
|
||||||
|
@ -14,10 +14,9 @@
|
|||||||
// 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 Protocol Version 1 implementation.
|
//! PIP Protocol Version 1 implementation.
|
||||||
//!
|
//!
|
||||||
//! This uses a "Provider" to answer requests.
|
//! This uses a "Provider" to answer requests.
|
||||||
//! See https://github.com/ethcore/parity/wiki/Light-Ethereum-Subprotocol-(LES)
|
|
||||||
|
|
||||||
use ethcore::transaction::{Action, UnverifiedTransaction};
|
use ethcore::transaction::{Action, UnverifiedTransaction};
|
||||||
use ethcore::receipt::Receipt;
|
use ethcore::receipt::Receipt;
|
||||||
@ -35,7 +34,7 @@ use std::sync::Arc;
|
|||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
|
||||||
use provider::Provider;
|
use provider::Provider;
|
||||||
use request::{self, HashOrNumber, Request};
|
use request::{self, HashOrNumber, Request, Response};
|
||||||
|
|
||||||
use self::request_credits::{Credits, FlowParams};
|
use self::request_credits::{Credits, FlowParams};
|
||||||
use self::context::{Ctx, TickCtx};
|
use self::context::{Ctx, TickCtx};
|
||||||
@ -83,43 +82,24 @@ mod packet {
|
|||||||
// announcement of new block hashes or capabilities.
|
// announcement of new block hashes or capabilities.
|
||||||
pub const ANNOUNCE: u8 = 0x01;
|
pub const ANNOUNCE: u8 = 0x01;
|
||||||
|
|
||||||
// request and response for block headers
|
// request and response.
|
||||||
pub const GET_BLOCK_HEADERS: u8 = 0x02;
|
pub const REQUEST: u8 = 0x02;
|
||||||
pub const BLOCK_HEADERS: u8 = 0x03;
|
pub const RESPONSE: u8 = 0x03;
|
||||||
|
|
||||||
// request and response for block bodies
|
|
||||||
pub const GET_BLOCK_BODIES: u8 = 0x04;
|
|
||||||
pub const BLOCK_BODIES: u8 = 0x05;
|
|
||||||
|
|
||||||
// request and response for transaction receipts.
|
|
||||||
pub const GET_RECEIPTS: u8 = 0x06;
|
|
||||||
pub const RECEIPTS: u8 = 0x07;
|
|
||||||
|
|
||||||
// request and response for merkle proofs.
|
|
||||||
pub const GET_PROOFS: u8 = 0x08;
|
|
||||||
pub const PROOFS: u8 = 0x09;
|
|
||||||
|
|
||||||
// request and response for contract code.
|
|
||||||
pub const GET_CONTRACT_CODES: u8 = 0x0a;
|
|
||||||
pub const CONTRACT_CODES: u8 = 0x0b;
|
|
||||||
|
|
||||||
// relay transactions to peers.
|
// relay transactions to peers.
|
||||||
pub const SEND_TRANSACTIONS: u8 = 0x0c;
|
pub const SEND_TRANSACTIONS: u8 = 0x04;
|
||||||
|
|
||||||
// request and response for header proofs in a CHT.
|
|
||||||
pub const GET_HEADER_PROOFS: u8 = 0x0d;
|
|
||||||
pub const HEADER_PROOFS: u8 = 0x0e;
|
|
||||||
|
|
||||||
// request and response for transaction proof.
|
// request and response for transaction proof.
|
||||||
pub const GET_TRANSACTION_PROOF: u8 = 0x0f;
|
// TODO: merge with request/response.
|
||||||
pub const TRANSACTION_PROOF: u8 = 0x10;
|
pub const GET_TRANSACTION_PROOF: u8 = 0x05;
|
||||||
|
pub const TRANSACTION_PROOF: u8 = 0x06;
|
||||||
}
|
}
|
||||||
|
|
||||||
// timeouts for different kinds of requests. all values are in milliseconds.
|
// timeouts for different kinds of requests. all values are in milliseconds.
|
||||||
// TODO: variable timeouts based on request count.
|
// TODO: variable timeouts based on request count.
|
||||||
mod timeout {
|
mod timeout {
|
||||||
pub const HANDSHAKE: i64 = 2500;
|
pub const HANDSHAKE: i64 = 2500;
|
||||||
pub const HEADERS: i64 = 5000;
|
pub const HEADERS: i64 = 2500;
|
||||||
pub const BODIES: i64 = 5000;
|
pub const BODIES: i64 = 5000;
|
||||||
pub const RECEIPTS: i64 = 3500;
|
pub const RECEIPTS: i64 = 3500;
|
||||||
pub const PROOFS: i64 = 4000;
|
pub const PROOFS: i64 = 4000;
|
||||||
@ -159,17 +139,6 @@ pub struct Peer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Peer {
|
impl Peer {
|
||||||
// check the maximum cost of a request, returning an error if there's
|
|
||||||
// not enough credits left.
|
|
||||||
// returns the calculated maximum cost.
|
|
||||||
fn deduct_max(&mut self, flow_params: &FlowParams, kind: request::Kind, max: usize) -> Result<U256, Error> {
|
|
||||||
flow_params.recharge(&mut self.local_credits);
|
|
||||||
|
|
||||||
let max_cost = flow_params.compute_cost(kind, max);
|
|
||||||
self.local_credits.deduct_cost(max_cost)?;
|
|
||||||
Ok(max_cost)
|
|
||||||
}
|
|
||||||
|
|
||||||
// refund credits for a request. returns new amount of credits.
|
// refund credits for a request. returns new amount of credits.
|
||||||
fn refund(&mut self, flow_params: &FlowParams, amount: U256) -> U256 {
|
fn refund(&mut self, flow_params: &FlowParams, amount: U256) -> U256 {
|
||||||
flow_params.refund(&mut self.local_credits, amount);
|
flow_params.refund(&mut self.local_credits, amount);
|
||||||
@ -197,20 +166,8 @@ pub trait Handler: Send + Sync {
|
|||||||
fn on_announcement(&self, _ctx: &EventContext, _announcement: &Announcement) { }
|
fn on_announcement(&self, _ctx: &EventContext, _announcement: &Announcement) { }
|
||||||
/// Called when a peer requests relay of some transactions.
|
/// Called when a peer requests relay of some transactions.
|
||||||
fn on_transactions(&self, _ctx: &EventContext, _relay: &[UnverifiedTransaction]) { }
|
fn on_transactions(&self, _ctx: &EventContext, _relay: &[UnverifiedTransaction]) { }
|
||||||
/// Called when a peer responds with block bodies.
|
/// Called when a peer responds to requests.
|
||||||
fn on_block_bodies(&self, _ctx: &EventContext, _req_id: ReqId, _bodies: &[Bytes]) { }
|
fn on_responses(&self, _ctx: &EventContext, _req_id: ReqId, _relay: &[Response]) { }
|
||||||
/// Called when a peer responds with block headers.
|
|
||||||
fn on_block_headers(&self, _ctx: &EventContext, _req_id: ReqId, _headers: &[Bytes]) { }
|
|
||||||
/// Called when a peer responds with block receipts.
|
|
||||||
fn on_receipts(&self, _ctx: &EventContext, _req_id: ReqId, _receipts: &[Vec<Receipt>]) { }
|
|
||||||
/// Called when a peer responds with state proofs. Each proof should be a series of trie
|
|
||||||
/// nodes in ascending order by distance from the root.
|
|
||||||
fn on_state_proofs(&self, _ctx: &EventContext, _req_id: ReqId, _proofs: &[Vec<Bytes>]) { }
|
|
||||||
/// Called when a peer responds with contract code.
|
|
||||||
fn on_code(&self, _ctx: &EventContext, _req_id: ReqId, _codes: &[Bytes]) { }
|
|
||||||
/// Called when a peer responds with header proofs. Each proof should be a block header coupled
|
|
||||||
/// with a series of trie nodes is ascending order by distance from the root.
|
|
||||||
fn on_header_proofs(&self, _ctx: &EventContext, _req_id: ReqId, _proofs: &[(Bytes, Vec<Bytes>)]) { }
|
|
||||||
/// Called when a peer responds with a transaction proof. Each proof is a vector of state items.
|
/// Called when a peer responds with a transaction proof. Each proof is a vector of state items.
|
||||||
fn on_transaction_proof(&self, _ctx: &EventContext, _req_id: ReqId, _state_items: &[DBValue]) { }
|
fn on_transaction_proof(&self, _ctx: &EventContext, _req_id: ReqId, _state_items: &[DBValue]) { }
|
||||||
/// Called to "tick" the handler periodically.
|
/// Called to "tick" the handler periodically.
|
||||||
@ -307,7 +264,7 @@ pub struct LightProtocol {
|
|||||||
impl LightProtocol {
|
impl LightProtocol {
|
||||||
/// Create a new instance of the protocol manager.
|
/// Create a new instance of the protocol manager.
|
||||||
pub fn new(provider: Arc<Provider>, params: Params) -> Self {
|
pub fn new(provider: Arc<Provider>, params: Params) -> Self {
|
||||||
debug!(target: "les", "Initializing LES handler");
|
debug!(target: "pip", "Initializing light protocol handler");
|
||||||
|
|
||||||
let genesis_hash = provider.chain_info().genesis_hash;
|
let genesis_hash = provider.chain_info().genesis_hash;
|
||||||
LightProtocol {
|
LightProtocol {
|
||||||
@ -339,62 +296,15 @@ impl LightProtocol {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check the maximum amount of requests of a specific type
|
|
||||||
/// which a peer would be able to serve. Returns zero if the
|
|
||||||
/// peer is unknown or has no credit parameters.
|
|
||||||
fn max_requests(&self, peer: PeerId, kind: request::Kind) -> usize {
|
|
||||||
self.peers.read().get(&peer).and_then(|peer| {
|
|
||||||
let mut peer = peer.lock();
|
|
||||||
match peer.remote_flow {
|
|
||||||
Some((ref mut c, ref flow)) => {
|
|
||||||
flow.recharge(c);
|
|
||||||
Some(flow.max_amount(&*c, kind))
|
|
||||||
}
|
|
||||||
None => None,
|
|
||||||
}
|
|
||||||
}).unwrap_or(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Make a request to a peer.
|
/// Make a request to a peer.
|
||||||
///
|
///
|
||||||
/// Fails on: nonexistent peer, network error, peer not server,
|
/// Fails on: nonexistent peer, network error, peer not server,
|
||||||
/// insufficient credits. Does not check capabilities before sending.
|
/// insufficient credits. Does not check capabilities before sending.
|
||||||
/// On success, returns a request id which can later be coordinated
|
/// On success, returns a request id which can later be coordinated
|
||||||
/// with an event.
|
/// with an event.
|
||||||
|
// TODO: pass `Requests`.
|
||||||
pub fn request_from(&self, io: &IoContext, peer_id: &PeerId, request: Request) -> Result<ReqId, Error> {
|
pub fn request_from(&self, io: &IoContext, peer_id: &PeerId, request: Request) -> Result<ReqId, Error> {
|
||||||
let peers = self.peers.read();
|
unimplemented!()
|
||||||
let peer = peers.get(peer_id).ok_or_else(|| Error::UnknownPeer)?;
|
|
||||||
let mut peer = peer.lock();
|
|
||||||
|
|
||||||
match peer.remote_flow {
|
|
||||||
Some((ref mut c, ref flow)) => {
|
|
||||||
flow.recharge(c);
|
|
||||||
let max = flow.compute_cost(request.kind(), request.amount());
|
|
||||||
c.deduct_cost(max)?;
|
|
||||||
}
|
|
||||||
None => return Err(Error::NotServer),
|
|
||||||
}
|
|
||||||
|
|
||||||
let req_id = self.req_id.fetch_add(1, Ordering::SeqCst);
|
|
||||||
let packet_data = encode_request(&request, req_id);
|
|
||||||
|
|
||||||
trace!(target: "les", "Dispatching request {} to peer {}", req_id, peer_id);
|
|
||||||
|
|
||||||
let packet_id = match request.kind() {
|
|
||||||
request::Kind::Headers => packet::GET_BLOCK_HEADERS,
|
|
||||||
request::Kind::Bodies => packet::GET_BLOCK_BODIES,
|
|
||||||
request::Kind::Receipts => packet::GET_RECEIPTS,
|
|
||||||
request::Kind::StateProofs => packet::GET_PROOFS,
|
|
||||||
request::Kind::Codes => packet::GET_CONTRACT_CODES,
|
|
||||||
request::Kind::HeaderProofs => packet::GET_HEADER_PROOFS,
|
|
||||||
request::Kind::TransactionProof => packet::GET_TRANSACTION_PROOF,
|
|
||||||
};
|
|
||||||
|
|
||||||
io.send(*peer_id, packet_id, packet_data);
|
|
||||||
|
|
||||||
peer.pending_requests.insert(ReqId(req_id), request, SteadyTime::now());
|
|
||||||
|
|
||||||
Ok(ReqId(req_id))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Make an announcement of new chain head and capabilities to all peers.
|
/// Make an announcement of new chain head and capabilities to all peers.
|
||||||
@ -427,7 +337,7 @@ impl LightProtocol {
|
|||||||
None => {
|
None => {
|
||||||
// both values will always originate locally -- this means something
|
// both values will always originate locally -- this means something
|
||||||
// has gone really wrong
|
// has gone really wrong
|
||||||
debug!(target: "les", "couldn't compute reorganization depth between {:?} and {:?}",
|
debug!(target: "pip", "couldn't compute reorganization depth between {:?} and {:?}",
|
||||||
&announcement.head_hash, &peer_info.sent_head);
|
&announcement.head_hash, &peer_info.sent_head);
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
@ -474,11 +384,10 @@ impl LightProtocol {
|
|||||||
let req_id = ReqId(raw.val_at(0)?);
|
let req_id = ReqId(raw.val_at(0)?);
|
||||||
let cur_credits: U256 = raw.val_at(1)?;
|
let cur_credits: U256 = raw.val_at(1)?;
|
||||||
|
|
||||||
trace!(target: "les", "pre-verifying response from peer {}, kind={:?}", peer, kind);
|
trace!(target: "pip", "pre-verifying response from peer {}, kind={:?}", peer, kind);
|
||||||
|
|
||||||
let mut had_req = false;
|
|
||||||
let peers = self.peers.read();
|
let peers = self.peers.read();
|
||||||
let maybe_err = match peers.get(peer) {
|
let res = match peers.get(peer) {
|
||||||
Some(peer_info) => {
|
Some(peer_info) => {
|
||||||
let mut peer_info = peer_info.lock();
|
let mut peer_info = peer_info.lock();
|
||||||
let req_info = peer_info.pending_requests.remove(&req_id, SteadyTime::now());
|
let req_info = peer_info.pending_requests.remove(&req_id, SteadyTime::now());
|
||||||
@ -486,69 +395,37 @@ impl LightProtocol {
|
|||||||
|
|
||||||
match (req_info, flow_info) {
|
match (req_info, flow_info) {
|
||||||
(Some(request), Some(flow_info)) => {
|
(Some(request), Some(flow_info)) => {
|
||||||
had_req = true;
|
|
||||||
|
|
||||||
let &mut (ref mut c, ref mut flow) = flow_info;
|
let &mut (ref mut c, ref mut flow) = flow_info;
|
||||||
let actual_credits = ::std::cmp::min(cur_credits, *flow.limit());
|
let actual_credits = ::std::cmp::min(cur_credits, *flow.limit());
|
||||||
c.update_to(actual_credits);
|
c.update_to(actual_credits);
|
||||||
|
|
||||||
if request.kind() != kind {
|
Ok(())
|
||||||
Some(Error::UnsolicitedResponse)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
(None, _) => Some(Error::UnsolicitedResponse),
|
(None, _) => Err(Error::UnsolicitedResponse),
|
||||||
(_, None) => Some(Error::NotServer), // really should be impossible.
|
(_, None) => Err(Error::NotServer), // really should be impossible.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => Some(Error::UnknownPeer), // probably only occurs in a race of some kind.
|
None => Err(Error::UnknownPeer), // probably only occurs in a race of some kind.
|
||||||
};
|
};
|
||||||
|
|
||||||
if had_req {
|
res.map(|_| IdGuard::new(peers, *peer, req_id))
|
||||||
let id_guard = IdGuard::new(peers, *peer, req_id);
|
|
||||||
match maybe_err {
|
|
||||||
Some(err) => Err(err),
|
|
||||||
None => Ok(id_guard)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Err(maybe_err.expect("every branch without a request leads to error; qed"))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle an LES packet using the given io context.
|
/// Handle a packet using the given io context.
|
||||||
/// Packet data is _untrusted_, which means that invalid data won't lead to
|
/// Packet data is _untrusted_, which means that invalid data won't lead to
|
||||||
/// issues.
|
/// issues.
|
||||||
pub fn handle_packet(&self, io: &IoContext, peer: &PeerId, packet_id: u8, data: &[u8]) {
|
pub fn handle_packet(&self, io: &IoContext, peer: &PeerId, packet_id: u8, data: &[u8]) {
|
||||||
let rlp = UntrustedRlp::new(data);
|
let rlp = UntrustedRlp::new(data);
|
||||||
|
|
||||||
trace!(target: "les", "Incoming packet {} from peer {}", packet_id, peer);
|
trace!(target: "pip", "Incoming packet {} from peer {}", packet_id, peer);
|
||||||
|
|
||||||
// handle the packet
|
// handle the packet
|
||||||
let res = match packet_id {
|
let res = match packet_id {
|
||||||
packet::STATUS => self.status(peer, io, rlp),
|
packet::STATUS => self.status(peer, io, rlp),
|
||||||
packet::ANNOUNCE => self.announcement(peer, io, rlp),
|
packet::ANNOUNCE => self.announcement(peer, io, rlp),
|
||||||
|
|
||||||
packet::GET_BLOCK_HEADERS => self.get_block_headers(peer, io, rlp),
|
packet::REQUEST => self.request(peer, io, rlp),
|
||||||
packet::BLOCK_HEADERS => self.block_headers(peer, io, rlp),
|
packet::RESPONSE => self.response(peer, io, rlp),
|
||||||
|
|
||||||
packet::GET_BLOCK_BODIES => self.get_block_bodies(peer, io, rlp),
|
|
||||||
packet::BLOCK_BODIES => self.block_bodies(peer, io, rlp),
|
|
||||||
|
|
||||||
packet::GET_RECEIPTS => self.get_receipts(peer, io, rlp),
|
|
||||||
packet::RECEIPTS => self.receipts(peer, io, rlp),
|
|
||||||
|
|
||||||
packet::GET_PROOFS => self.get_proofs(peer, io, rlp),
|
|
||||||
packet::PROOFS => self.proofs(peer, io, rlp),
|
|
||||||
|
|
||||||
packet::GET_CONTRACT_CODES => self.get_contract_code(peer, io, rlp),
|
|
||||||
packet::CONTRACT_CODES => self.contract_code(peer, io, rlp),
|
|
||||||
|
|
||||||
packet::GET_HEADER_PROOFS => self.get_header_proofs(peer, io, rlp),
|
|
||||||
packet::HEADER_PROOFS => self.header_proofs(peer, io, rlp),
|
|
||||||
|
|
||||||
packet::GET_TRANSACTION_PROOF => self.get_transaction_proof(peer, io, rlp),
|
|
||||||
packet::TRANSACTION_PROOF => self.transaction_proof(peer, io, rlp),
|
|
||||||
|
|
||||||
packet::SEND_TRANSACTIONS => self.relay_transactions(peer, io, rlp),
|
packet::SEND_TRANSACTIONS => self.relay_transactions(peer, io, rlp),
|
||||||
|
|
||||||
@ -577,7 +454,7 @@ impl LightProtocol {
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
for slowpoke in slowpokes {
|
for slowpoke in slowpokes {
|
||||||
debug!(target: "les", "Peer {} handshake timed out", slowpoke);
|
debug!(target: "pip", "Peer {} handshake timed out", slowpoke);
|
||||||
pending.remove(&slowpoke);
|
pending.remove(&slowpoke);
|
||||||
io.disconnect_peer(slowpoke);
|
io.disconnect_peer(slowpoke);
|
||||||
}
|
}
|
||||||
@ -587,7 +464,7 @@ impl LightProtocol {
|
|||||||
{
|
{
|
||||||
for (peer_id, peer) in self.peers.read().iter() {
|
for (peer_id, peer) in self.peers.read().iter() {
|
||||||
if peer.lock().pending_requests.check_timeout(now) {
|
if peer.lock().pending_requests.check_timeout(now) {
|
||||||
debug!(target: "les", "Peer {} request timeout", peer_id);
|
debug!(target: "pip", "Peer {} request timeout", peer_id);
|
||||||
io.disconnect_peer(*peer_id);
|
io.disconnect_peer(*peer_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -631,7 +508,7 @@ impl LightProtocol {
|
|||||||
|
|
||||||
/// called when a peer disconnects.
|
/// called when a peer disconnects.
|
||||||
pub fn on_disconnect(&self, peer: PeerId, io: &IoContext) {
|
pub fn on_disconnect(&self, peer: PeerId, io: &IoContext) {
|
||||||
trace!(target: "les", "Peer {} disconnecting", peer);
|
trace!(target: "pip", "Peer {} disconnecting", peer);
|
||||||
|
|
||||||
self.pending_peers.write().remove(&peer);
|
self.pending_peers.write().remove(&peer);
|
||||||
let unfulfilled = match self.peers.write().remove(&peer) {
|
let unfulfilled = match self.peers.write().remove(&peer) {
|
||||||
@ -686,7 +563,7 @@ impl LightProtocol {
|
|||||||
|
|
||||||
let (status, capabilities, flow_params) = status::parse_handshake(data)?;
|
let (status, capabilities, flow_params) = status::parse_handshake(data)?;
|
||||||
|
|
||||||
trace!(target: "les", "Connected peer with chain head {:?}", (status.head_hash, status.head_num));
|
trace!(target: "pip", "Connected peer with chain head {:?}", (status.head_hash, status.head_num));
|
||||||
|
|
||||||
if (status.network_id, status.genesis_hash) != (self.network_id, self.genesis_hash) {
|
if (status.network_id, status.genesis_hash) != (self.network_id, self.genesis_hash) {
|
||||||
return Err(Error::WrongNetwork);
|
return Err(Error::WrongNetwork);
|
||||||
@ -723,7 +600,7 @@ impl LightProtocol {
|
|||||||
// Handle an announcement.
|
// Handle an announcement.
|
||||||
fn announcement(&self, peer: &PeerId, io: &IoContext, data: UntrustedRlp) -> Result<(), Error> {
|
fn announcement(&self, peer: &PeerId, io: &IoContext, data: UntrustedRlp) -> Result<(), Error> {
|
||||||
if !self.peers.read().contains_key(peer) {
|
if !self.peers.read().contains_key(peer) {
|
||||||
debug!(target: "les", "Ignoring announcement from unknown peer");
|
debug!(target: "pip", "Ignoring announcement from unknown peer");
|
||||||
return Ok(())
|
return Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -765,447 +642,19 @@ impl LightProtocol {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle a request for block headers.
|
fn request(&self, peer: &PeerId, io: &IoContext, raw: UntrustedRlp) -> Result<(), Error> {
|
||||||
fn get_block_headers(&self, peer: &PeerId, io: &IoContext, data: UntrustedRlp) -> Result<(), Error> {
|
// the maximum amount of requests we'll fill in a single packet.
|
||||||
const MAX_HEADERS: usize = 512;
|
const MAX_REQUESTS: usize = 512;
|
||||||
|
// the maximum amount of gas we'll prove execution of in a single packet.
|
||||||
let peers = self.peers.read();
|
|
||||||
let peer = match peers.get(peer) {
|
|
||||||
Some(peer) => peer,
|
|
||||||
None => {
|
|
||||||
debug!(target: "les", "Ignoring request from unknown peer");
|
|
||||||
return Ok(())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut peer = peer.lock();
|
|
||||||
|
|
||||||
let req_id: u64 = data.val_at(0)?;
|
|
||||||
let data = data.at(1)?;
|
|
||||||
|
|
||||||
let start_block = {
|
|
||||||
if data.at(0)?.size() == 32 {
|
|
||||||
HashOrNumber::Hash(data.val_at(0)?)
|
|
||||||
} else {
|
|
||||||
HashOrNumber::Number(data.val_at(0)?)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let req = request::Headers {
|
|
||||||
start: start_block,
|
|
||||||
max: ::std::cmp::min(MAX_HEADERS, data.val_at(1)?),
|
|
||||||
skip: data.val_at(2)?,
|
|
||||||
reverse: data.val_at(3)?,
|
|
||||||
};
|
|
||||||
|
|
||||||
let max_cost = peer.deduct_max(&self.flow_params, request::Kind::Headers, req.max)?;
|
|
||||||
|
|
||||||
let response = self.provider.block_headers(req);
|
|
||||||
let actual_cost = self.flow_params.compute_cost(request::Kind::Headers, response.len());
|
|
||||||
assert!(max_cost >= actual_cost, "Actual cost exceeded maximum computed cost.");
|
|
||||||
|
|
||||||
let cur_credits = peer.refund(&self.flow_params, max_cost - actual_cost);
|
|
||||||
io.respond(packet::BLOCK_HEADERS, {
|
|
||||||
let mut stream = RlpStream::new_list(3);
|
|
||||||
stream.append(&req_id).append(&cur_credits).begin_list(response.len());
|
|
||||||
|
|
||||||
for header in response {
|
|
||||||
stream.append_raw(&header.into_inner(), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
stream.out()
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Receive a response for block headers.
|
|
||||||
fn block_headers(&self, peer: &PeerId, io: &IoContext, raw: UntrustedRlp) -> Result<(), Error> {
|
|
||||||
let id_guard = self.pre_verify_response(peer, request::Kind::Headers, &raw)?;
|
|
||||||
let raw_headers: Vec<_> = raw.at(2)?.iter().map(|x| x.as_raw().to_owned()).collect();
|
|
||||||
|
|
||||||
let req_id = id_guard.defuse();
|
|
||||||
for handler in &self.handlers {
|
|
||||||
handler.on_block_headers(&Ctx {
|
|
||||||
peer: *peer,
|
|
||||||
io: io,
|
|
||||||
proto: self,
|
|
||||||
}, req_id, &raw_headers);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle a request for block bodies.
|
|
||||||
fn get_block_bodies(&self, peer: &PeerId, io: &IoContext, data: UntrustedRlp) -> Result<(), Error> {
|
|
||||||
const MAX_BODIES: usize = 256;
|
|
||||||
|
|
||||||
let peers = self.peers.read();
|
|
||||||
let peer = match peers.get(peer) {
|
|
||||||
Some(peer) => peer,
|
|
||||||
None => {
|
|
||||||
debug!(target: "les", "Ignoring request from unknown peer");
|
|
||||||
return Ok(())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let mut peer = peer.lock();
|
|
||||||
|
|
||||||
let req_id: u64 = data.val_at(0)?;
|
|
||||||
|
|
||||||
let req = request::Bodies {
|
|
||||||
block_hashes: data.at(1)?.iter()
|
|
||||||
.take(MAX_BODIES)
|
|
||||||
.map(|x| x.as_val())
|
|
||||||
.collect::<Result<_, _>>()?
|
|
||||||
};
|
|
||||||
|
|
||||||
let max_cost = peer.deduct_max(&self.flow_params, request::Kind::Bodies, req.block_hashes.len())?;
|
|
||||||
|
|
||||||
let response = self.provider.block_bodies(req);
|
|
||||||
let response_len = response.iter().filter(|x| x.is_some()).count();
|
|
||||||
let actual_cost = self.flow_params.compute_cost(request::Kind::Bodies, response_len);
|
|
||||||
assert!(max_cost >= actual_cost, "Actual cost exceeded maximum computed cost.");
|
|
||||||
|
|
||||||
let cur_credits = peer.refund(&self.flow_params, max_cost - actual_cost);
|
|
||||||
|
|
||||||
io.respond(packet::BLOCK_BODIES, {
|
|
||||||
let mut stream = RlpStream::new_list(3);
|
|
||||||
stream.append(&req_id).append(&cur_credits).begin_list(response.len());
|
|
||||||
|
|
||||||
for body in response {
|
|
||||||
match body {
|
|
||||||
Some(body) => stream.append_raw(&body.into_inner(), 1),
|
|
||||||
None => stream.append_empty_data(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
stream.out()
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Receive a response for block bodies.
|
|
||||||
fn block_bodies(&self, peer: &PeerId, io: &IoContext, raw: UntrustedRlp) -> Result<(), Error> {
|
|
||||||
let id_guard = self.pre_verify_response(peer, request::Kind::Bodies, &raw)?;
|
|
||||||
let raw_bodies: Vec<Bytes> = raw.at(2)?.iter().map(|x| x.as_raw().to_owned()).collect();
|
|
||||||
|
|
||||||
let req_id = id_guard.defuse();
|
|
||||||
for handler in &self.handlers {
|
|
||||||
handler.on_block_bodies(&Ctx {
|
|
||||||
peer: *peer,
|
|
||||||
io: io,
|
|
||||||
proto: self,
|
|
||||||
}, req_id, &raw_bodies);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle a request for receipts.
|
|
||||||
fn get_receipts(&self, peer: &PeerId, io: &IoContext, data: UntrustedRlp) -> Result<(), Error> {
|
|
||||||
const MAX_RECEIPTS: usize = 256;
|
|
||||||
|
|
||||||
let peers = self.peers.read();
|
|
||||||
let peer = match peers.get(peer) {
|
|
||||||
Some(peer) => peer,
|
|
||||||
None => {
|
|
||||||
debug!(target: "les", "Ignoring request from unknown peer");
|
|
||||||
return Ok(())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let mut peer = peer.lock();
|
|
||||||
|
|
||||||
let req_id: u64 = data.val_at(0)?;
|
|
||||||
|
|
||||||
let req = request::Receipts {
|
|
||||||
block_hashes: data.at(1)?.iter()
|
|
||||||
.take(MAX_RECEIPTS)
|
|
||||||
.map(|x| x.as_val())
|
|
||||||
.collect::<Result<_,_>>()?
|
|
||||||
};
|
|
||||||
|
|
||||||
let max_cost = peer.deduct_max(&self.flow_params, request::Kind::Receipts, req.block_hashes.len())?;
|
|
||||||
|
|
||||||
let response = self.provider.receipts(req);
|
|
||||||
let response_len = response.iter().filter(|x| &x[..] != &::rlp::EMPTY_LIST_RLP).count();
|
|
||||||
let actual_cost = self.flow_params.compute_cost(request::Kind::Receipts, response_len);
|
|
||||||
assert!(max_cost >= actual_cost, "Actual cost exceeded maximum computed cost.");
|
|
||||||
|
|
||||||
let cur_credits = peer.refund(&self.flow_params, max_cost - actual_cost);
|
|
||||||
|
|
||||||
io.respond(packet::RECEIPTS, {
|
|
||||||
let mut stream = RlpStream::new_list(3);
|
|
||||||
stream.append(&req_id).append(&cur_credits).begin_list(response.len());
|
|
||||||
|
|
||||||
for receipts in response {
|
|
||||||
stream.append_raw(&receipts, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
stream.out()
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Receive a response for receipts.
|
|
||||||
fn receipts(&self, peer: &PeerId, io: &IoContext, raw: UntrustedRlp) -> Result<(), Error> {
|
|
||||||
let id_guard = self.pre_verify_response(peer, request::Kind::Receipts, &raw)?;
|
|
||||||
let raw_receipts: Vec<Vec<Receipt>> = raw.at(2)?
|
|
||||||
.iter()
|
|
||||||
.map(|x| x.as_val())
|
|
||||||
.collect::<Result<_,_>>()?;
|
|
||||||
|
|
||||||
let req_id = id_guard.defuse();
|
|
||||||
for handler in &self.handlers {
|
|
||||||
handler.on_receipts(&Ctx {
|
|
||||||
peer: *peer,
|
|
||||||
io: io,
|
|
||||||
proto: self,
|
|
||||||
}, req_id, &raw_receipts);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle a request for proofs.
|
|
||||||
fn get_proofs(&self, peer: &PeerId, io: &IoContext, data: UntrustedRlp) -> Result<(), Error> {
|
|
||||||
const MAX_PROOFS: usize = 128;
|
|
||||||
|
|
||||||
let peers = self.peers.read();
|
|
||||||
let peer = match peers.get(peer) {
|
|
||||||
Some(peer) => peer,
|
|
||||||
None => {
|
|
||||||
debug!(target: "les", "Ignoring request from unknown peer");
|
|
||||||
return Ok(())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let mut peer = peer.lock();
|
|
||||||
|
|
||||||
let req_id: u64 = data.val_at(0)?;
|
|
||||||
|
|
||||||
let req = {
|
|
||||||
let requests: Result<Vec<_>, Error> = data.at(1)?.iter().take(MAX_PROOFS).map(|x| {
|
|
||||||
Ok(request::StateProof {
|
|
||||||
block: x.val_at(0)?,
|
|
||||||
key1: x.val_at(1)?,
|
|
||||||
key2: if x.at(2)?.is_empty() { None } else { Some(x.val_at(2)?) },
|
|
||||||
from_level: x.val_at(3)?,
|
|
||||||
})
|
|
||||||
}).collect();
|
|
||||||
|
|
||||||
request::StateProofs {
|
|
||||||
requests: requests?,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let max_cost = peer.deduct_max(&self.flow_params, request::Kind::StateProofs, req.requests.len())?;
|
|
||||||
|
|
||||||
let response = self.provider.proofs(req);
|
|
||||||
let response_len = response.iter().filter(|x| &x[..] != &::rlp::EMPTY_LIST_RLP).count();
|
|
||||||
let actual_cost = self.flow_params.compute_cost(request::Kind::StateProofs, response_len);
|
|
||||||
assert!(max_cost >= actual_cost, "Actual cost exceeded maximum computed cost.");
|
|
||||||
|
|
||||||
let cur_credits = peer.refund(&self.flow_params, max_cost - actual_cost);
|
|
||||||
|
|
||||||
io.respond(packet::PROOFS, {
|
|
||||||
let mut stream = RlpStream::new_list(3);
|
|
||||||
stream.append(&req_id).append(&cur_credits).begin_list(response.len());
|
|
||||||
|
|
||||||
for proof in response {
|
|
||||||
stream.append_raw(&proof, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
stream.out()
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Receive a response for proofs.
|
|
||||||
fn proofs(&self, peer: &PeerId, io: &IoContext, raw: UntrustedRlp) -> Result<(), Error> {
|
|
||||||
let id_guard = self.pre_verify_response(peer, request::Kind::StateProofs, &raw)?;
|
|
||||||
|
|
||||||
let raw_proofs: Vec<Vec<Bytes>> = raw.at(2)?.iter()
|
|
||||||
.map(|x| x.iter().map(|node| node.as_raw().to_owned()).collect())
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let req_id = id_guard.defuse();
|
|
||||||
for handler in &self.handlers {
|
|
||||||
handler.on_state_proofs(&Ctx {
|
|
||||||
peer: *peer,
|
|
||||||
io: io,
|
|
||||||
proto: self,
|
|
||||||
}, req_id, &raw_proofs);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle a request for contract code.
|
|
||||||
fn get_contract_code(&self, peer: &PeerId, io: &IoContext, data: UntrustedRlp) -> Result<(), Error> {
|
|
||||||
const MAX_CODES: usize = 256;
|
|
||||||
|
|
||||||
let peers = self.peers.read();
|
|
||||||
let peer = match peers.get(peer) {
|
|
||||||
Some(peer) => peer,
|
|
||||||
None => {
|
|
||||||
debug!(target: "les", "Ignoring request from unknown peer");
|
|
||||||
return Ok(())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let mut peer = peer.lock();
|
|
||||||
|
|
||||||
let req_id: u64 = data.val_at(0)?;
|
|
||||||
|
|
||||||
let req = {
|
|
||||||
let requests: Result<Vec<_>, Error> = data.at(1)?.iter().take(MAX_CODES).map(|x| {
|
|
||||||
Ok(request::ContractCode {
|
|
||||||
block_hash: x.val_at(0)?,
|
|
||||||
account_key: x.val_at(1)?,
|
|
||||||
})
|
|
||||||
}).collect();
|
|
||||||
|
|
||||||
request::ContractCodes {
|
|
||||||
code_requests: requests?,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let max_cost = peer.deduct_max(&self.flow_params, request::Kind::Codes, req.code_requests.len())?;
|
|
||||||
|
|
||||||
let response = self.provider.contract_codes(req);
|
|
||||||
let response_len = response.iter().filter(|x| !x.is_empty()).count();
|
|
||||||
let actual_cost = self.flow_params.compute_cost(request::Kind::Codes, response_len);
|
|
||||||
assert!(max_cost >= actual_cost, "Actual cost exceeded maximum computed cost.");
|
|
||||||
|
|
||||||
let cur_credits = peer.refund(&self.flow_params, max_cost - actual_cost);
|
|
||||||
|
|
||||||
io.respond(packet::CONTRACT_CODES, {
|
|
||||||
let mut stream = RlpStream::new_list(3);
|
|
||||||
stream.append(&req_id).append(&cur_credits).begin_list(response.len());
|
|
||||||
|
|
||||||
for code in response {
|
|
||||||
stream.append(&code);
|
|
||||||
}
|
|
||||||
|
|
||||||
stream.out()
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Receive a response for contract code.
|
|
||||||
fn contract_code(&self, peer: &PeerId, io: &IoContext, raw: UntrustedRlp) -> Result<(), Error> {
|
|
||||||
let id_guard = self.pre_verify_response(peer, request::Kind::Codes, &raw)?;
|
|
||||||
|
|
||||||
let raw_code: Vec<Bytes> = raw.at(2)?.iter()
|
|
||||||
.map(|x| x.as_val())
|
|
||||||
.collect::<Result<_,_>>()?;
|
|
||||||
|
|
||||||
let req_id = id_guard.defuse();
|
|
||||||
for handler in &self.handlers {
|
|
||||||
handler.on_code(&Ctx {
|
|
||||||
peer: *peer,
|
|
||||||
io: io,
|
|
||||||
proto: self,
|
|
||||||
}, req_id, &raw_code);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle a request for header proofs
|
|
||||||
fn get_header_proofs(&self, peer: &PeerId, io: &IoContext, data: UntrustedRlp) -> Result<(), Error> {
|
|
||||||
const MAX_PROOFS: usize = 256;
|
|
||||||
|
|
||||||
let peers = self.peers.read();
|
|
||||||
let peer = match peers.get(peer) {
|
|
||||||
Some(peer) => peer,
|
|
||||||
None => {
|
|
||||||
debug!(target: "les", "Ignoring request from unknown peer");
|
|
||||||
return Ok(())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let mut peer = peer.lock();
|
|
||||||
|
|
||||||
let req_id: u64 = data.val_at(0)?;
|
|
||||||
|
|
||||||
let req = {
|
|
||||||
let requests: Result<Vec<_>, Error> = data.at(1)?.iter().take(MAX_PROOFS).map(|x| {
|
|
||||||
Ok(request::HeaderProof {
|
|
||||||
cht_number: x.val_at(0)?,
|
|
||||||
block_number: x.val_at(1)?,
|
|
||||||
from_level: x.val_at(2)?,
|
|
||||||
})
|
|
||||||
}).collect();
|
|
||||||
|
|
||||||
request::HeaderProofs {
|
|
||||||
requests: requests?,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let max_cost = peer.deduct_max(&self.flow_params, request::Kind::HeaderProofs, req.requests.len())?;
|
|
||||||
|
|
||||||
let response = self.provider.header_proofs(req);
|
|
||||||
let response_len = response.iter().filter(|x| &x[..] != ::rlp::EMPTY_LIST_RLP).count();
|
|
||||||
let actual_cost = self.flow_params.compute_cost(request::Kind::HeaderProofs, response_len);
|
|
||||||
assert!(max_cost >= actual_cost, "Actual cost exceeded maximum computed cost.");
|
|
||||||
|
|
||||||
let cur_credits = peer.refund(&self.flow_params, max_cost - actual_cost);
|
|
||||||
|
|
||||||
io.respond(packet::HEADER_PROOFS, {
|
|
||||||
let mut stream = RlpStream::new_list(3);
|
|
||||||
stream.append(&req_id).append(&cur_credits).begin_list(response.len());
|
|
||||||
|
|
||||||
for proof in response {
|
|
||||||
stream.append_raw(&proof, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
stream.out()
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Receive a response for header proofs
|
|
||||||
fn header_proofs(&self, peer: &PeerId, io: &IoContext, raw: UntrustedRlp) -> Result<(), Error> {
|
|
||||||
fn decode_res(raw: UntrustedRlp) -> Result<(Bytes, Vec<Bytes>), ::rlp::DecoderError> {
|
|
||||||
Ok((
|
|
||||||
raw.val_at(0)?,
|
|
||||||
raw.at(1)?.iter().map(|x| x.as_raw().to_owned()).collect(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
let id_guard = self.pre_verify_response(peer, request::Kind::HeaderProofs, &raw)?;
|
|
||||||
let raw_proofs: Vec<_> = raw.at(2)?.iter()
|
|
||||||
.map(decode_res)
|
|
||||||
.collect::<Result<_,_>>()?;
|
|
||||||
|
|
||||||
let req_id = id_guard.defuse();
|
|
||||||
for handler in &self.handlers {
|
|
||||||
handler.on_header_proofs(&Ctx {
|
|
||||||
peer: *peer,
|
|
||||||
io: io,
|
|
||||||
proto: self,
|
|
||||||
}, req_id, &raw_proofs);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Receive a request for proof-of-execution.
|
|
||||||
fn get_transaction_proof(&self, peer: &PeerId, io: &IoContext, raw: UntrustedRlp) -> Result<(), Error> {
|
|
||||||
// refuse to execute more than this amount of gas at once.
|
|
||||||
// this is appx. the point at which the proof of execution would no longer fit in
|
|
||||||
// a single Devp2p packet.
|
|
||||||
const MAX_GAS: usize = 50_000_000;
|
const MAX_GAS: usize = 50_000_000;
|
||||||
use util::Uint;
|
|
||||||
|
use ::request_builder::RequestBuilder;
|
||||||
|
|
||||||
let peers = self.peers.read();
|
let peers = self.peers.read();
|
||||||
let peer = match peers.get(peer) {
|
let peer = match peers.get(peer) {
|
||||||
Some(peer) => peer,
|
Some(peer) => peer,
|
||||||
None => {
|
None => {
|
||||||
debug!(target: "les", "Ignoring request from unknown peer");
|
debug!(target: "pip", "Ignoring request from unknown peer");
|
||||||
return Ok(())
|
return Ok(())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1213,68 +662,11 @@ impl LightProtocol {
|
|||||||
|
|
||||||
let req_id: u64 = raw.val_at(0)?;
|
let req_id: u64 = raw.val_at(0)?;
|
||||||
|
|
||||||
let req = {
|
unimplemented!()
|
||||||
let req_rlp = raw.at(1)?;
|
|
||||||
request::TransactionProof {
|
|
||||||
at: req_rlp.val_at(0)?,
|
|
||||||
from: req_rlp.val_at(1)?,
|
|
||||||
action: if req_rlp.at(2)?.is_empty() {
|
|
||||||
Action::Create
|
|
||||||
} else {
|
|
||||||
Action::Call(req_rlp.val_at(2)?)
|
|
||||||
},
|
|
||||||
gas: ::std::cmp::min(req_rlp.val_at(3)?, MAX_GAS.into()),
|
|
||||||
gas_price: req_rlp.val_at(4)?,
|
|
||||||
value: req_rlp.val_at(5)?,
|
|
||||||
data: req_rlp.val_at(6)?,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// always charge the peer for all the gas.
|
|
||||||
peer.deduct_max(&self.flow_params, request::Kind::TransactionProof, req.gas.low_u64() as usize)?;
|
|
||||||
|
|
||||||
let response = match self.provider.transaction_proof(req) {
|
|
||||||
Some(res) => res,
|
|
||||||
None => vec![],
|
|
||||||
};
|
|
||||||
|
|
||||||
let cur_credits = peer.local_credits.current();
|
|
||||||
|
|
||||||
io.respond(packet::TRANSACTION_PROOF, {
|
|
||||||
let mut stream = RlpStream::new_list(3);
|
|
||||||
stream.append(&req_id).append(&cur_credits).begin_list(response.len());
|
|
||||||
|
|
||||||
for state_item in response {
|
|
||||||
stream.append(&&state_item[..]);
|
|
||||||
}
|
|
||||||
|
|
||||||
stream.out()
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Receive a response for proof-of-execution.
|
fn response(&self, peer: &PeerId, io: &IoContext, raw: UntrustedRlp) -> Result<(), Error> {
|
||||||
fn transaction_proof(&self, peer: &PeerId, io: &IoContext, raw: UntrustedRlp) -> Result<(), Error> {
|
unimplemented!()
|
||||||
let id_guard = self.pre_verify_response(peer, request::Kind::HeaderProofs, &raw)?;
|
|
||||||
let raw_proof: Vec<DBValue> = raw.at(2)?.iter()
|
|
||||||
.map(|rlp| {
|
|
||||||
let mut db_val = DBValue::new();
|
|
||||||
db_val.append_slice(rlp.data()?);
|
|
||||||
Ok(db_val)
|
|
||||||
})
|
|
||||||
.collect::<Result<Vec<_>, ::rlp::DecoderError>>()?;
|
|
||||||
|
|
||||||
let req_id = id_guard.defuse();
|
|
||||||
for handler in &self.handlers {
|
|
||||||
handler.on_transaction_proof(&Ctx {
|
|
||||||
peer: *peer,
|
|
||||||
io: io,
|
|
||||||
proto: self,
|
|
||||||
}, req_id, &raw_proof);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Receive a set of transactions to relay.
|
// Receive a set of transactions to relay.
|
||||||
@ -1286,7 +678,7 @@ impl LightProtocol {
|
|||||||
.map(|x| x.as_val::<UnverifiedTransaction>())
|
.map(|x| x.as_val::<UnverifiedTransaction>())
|
||||||
.collect::<Result<_,_>>()?;
|
.collect::<Result<_,_>>()?;
|
||||||
|
|
||||||
debug!(target: "les", "Received {} transactions to relay from peer {}", txs.len(), peer);
|
debug!(target: "pip", "Received {} transactions to relay from peer {}", txs.len(), peer);
|
||||||
|
|
||||||
for handler in &self.handlers {
|
for handler in &self.handlers {
|
||||||
handler.on_transactions(&Ctx {
|
handler.on_transactions(&Ctx {
|
||||||
@ -1305,11 +697,11 @@ fn punish(peer: PeerId, io: &IoContext, e: Error) {
|
|||||||
match e.punishment() {
|
match e.punishment() {
|
||||||
Punishment::None => {}
|
Punishment::None => {}
|
||||||
Punishment::Disconnect => {
|
Punishment::Disconnect => {
|
||||||
debug!(target: "les", "Disconnecting peer {}: {}", peer, e);
|
debug!(target: "pip", "Disconnecting peer {}: {}", peer, e);
|
||||||
io.disconnect_peer(peer)
|
io.disconnect_peer(peer)
|
||||||
}
|
}
|
||||||
Punishment::Disable => {
|
Punishment::Disable => {
|
||||||
debug!(target: "les", "Disabling peer {}: {}", peer, e);
|
debug!(target: "pip", "Disabling peer {}: {}", peer, e);
|
||||||
io.disable_peer(peer)
|
io.disable_peer(peer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1339,112 +731,7 @@ impl NetworkProtocolHandler for LightProtocol {
|
|||||||
match timer {
|
match timer {
|
||||||
TIMEOUT => self.timeout_check(io),
|
TIMEOUT => self.timeout_check(io),
|
||||||
TICK_TIMEOUT => self.tick_handlers(io),
|
TICK_TIMEOUT => self.tick_handlers(io),
|
||||||
_ => warn!(target: "les", "received timeout on unknown token {}", timer),
|
_ => warn!(target: "pip", "received timeout on unknown token {}", timer),
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper for encoding the request to RLP with the given ID.
|
|
||||||
fn encode_request(req: &Request, req_id: usize) -> Vec<u8> {
|
|
||||||
match *req {
|
|
||||||
Request::Headers(ref headers) => {
|
|
||||||
let mut stream = RlpStream::new_list(2);
|
|
||||||
stream.append(&req_id).begin_list(4);
|
|
||||||
|
|
||||||
match headers.start {
|
|
||||||
HashOrNumber::Hash(ref hash) => stream.append(hash),
|
|
||||||
HashOrNumber::Number(ref num) => stream.append(num),
|
|
||||||
};
|
|
||||||
|
|
||||||
stream
|
|
||||||
.append(&headers.max)
|
|
||||||
.append(&headers.skip)
|
|
||||||
.append(&headers.reverse);
|
|
||||||
|
|
||||||
stream.out()
|
|
||||||
}
|
|
||||||
Request::Bodies(ref request) => {
|
|
||||||
let mut stream = RlpStream::new_list(2);
|
|
||||||
stream.append(&req_id).begin_list(request.block_hashes.len());
|
|
||||||
|
|
||||||
for hash in &request.block_hashes {
|
|
||||||
stream.append(hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
stream.out()
|
|
||||||
}
|
|
||||||
Request::Receipts(ref request) => {
|
|
||||||
let mut stream = RlpStream::new_list(2);
|
|
||||||
stream.append(&req_id).begin_list(request.block_hashes.len());
|
|
||||||
|
|
||||||
for hash in &request.block_hashes {
|
|
||||||
stream.append(hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
stream.out()
|
|
||||||
}
|
|
||||||
Request::StateProofs(ref request) => {
|
|
||||||
let mut stream = RlpStream::new_list(2);
|
|
||||||
stream.append(&req_id).begin_list(request.requests.len());
|
|
||||||
|
|
||||||
for proof_req in &request.requests {
|
|
||||||
stream.begin_list(4)
|
|
||||||
.append(&proof_req.block)
|
|
||||||
.append(&proof_req.key1);
|
|
||||||
|
|
||||||
match proof_req.key2 {
|
|
||||||
Some(ref key2) => stream.append(key2),
|
|
||||||
None => stream.append_empty_data(),
|
|
||||||
};
|
|
||||||
|
|
||||||
stream.append(&proof_req.from_level);
|
|
||||||
}
|
|
||||||
|
|
||||||
stream.out()
|
|
||||||
}
|
|
||||||
Request::Codes(ref request) => {
|
|
||||||
let mut stream = RlpStream::new_list(2);
|
|
||||||
stream.append(&req_id).begin_list(request.code_requests.len());
|
|
||||||
|
|
||||||
for code_req in &request.code_requests {
|
|
||||||
stream.begin_list(2)
|
|
||||||
.append(&code_req.block_hash)
|
|
||||||
.append(&code_req.account_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
stream.out()
|
|
||||||
}
|
|
||||||
Request::HeaderProofs(ref request) => {
|
|
||||||
let mut stream = RlpStream::new_list(2);
|
|
||||||
stream.append(&req_id).begin_list(request.requests.len());
|
|
||||||
|
|
||||||
for proof_req in &request.requests {
|
|
||||||
stream.begin_list(3)
|
|
||||||
.append(&proof_req.cht_number)
|
|
||||||
.append(&proof_req.block_number)
|
|
||||||
.append(&proof_req.from_level);
|
|
||||||
}
|
|
||||||
|
|
||||||
stream.out()
|
|
||||||
}
|
|
||||||
Request::TransactionProof(ref request) => {
|
|
||||||
let mut stream = RlpStream::new_list(2);
|
|
||||||
stream.append(&req_id).begin_list(7)
|
|
||||||
.append(&request.at)
|
|
||||||
.append(&request.from);
|
|
||||||
|
|
||||||
match request.action {
|
|
||||||
Action::Create => stream.append_empty_data(),
|
|
||||||
Action::Call(ref to) => stream.append(to),
|
|
||||||
};
|
|
||||||
|
|
||||||
stream
|
|
||||||
.append(&request.gas)
|
|
||||||
.append(&request.gas_price)
|
|
||||||
.append(&request.value)
|
|
||||||
.append(&request.data);
|
|
||||||
|
|
||||||
stream.out()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
//! Current default costs are picked completely arbitrarily, not based
|
//! Current default costs are picked completely arbitrarily, not based
|
||||||
//! on any empirical timings or mathematical models.
|
//! on any empirical timings or mathematical models.
|
||||||
|
|
||||||
use request;
|
use request::{self, Request};
|
||||||
use super::packet;
|
use super::packet;
|
||||||
use super::error::Error;
|
use super::error::Error;
|
||||||
|
|
||||||
@ -34,10 +34,6 @@ use rlp::*;
|
|||||||
use util::U256;
|
use util::U256;
|
||||||
use time::{Duration, SteadyTime};
|
use time::{Duration, SteadyTime};
|
||||||
|
|
||||||
/// A request cost specification.
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
||||||
pub struct Cost(pub U256, pub U256);
|
|
||||||
|
|
||||||
/// Credits value.
|
/// Credits value.
|
||||||
///
|
///
|
||||||
/// Produced and recharged using `FlowParams`.
|
/// Produced and recharged using `FlowParams`.
|
||||||
@ -81,93 +77,43 @@ impl Credits {
|
|||||||
/// A cost table, mapping requests to base and per-request costs.
|
/// A cost table, mapping requests to base and per-request costs.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct CostTable {
|
pub struct CostTable {
|
||||||
headers: Cost, // cost per header
|
base: U256, // cost per packet.
|
||||||
bodies: Cost,
|
headers: U256, // cost per header
|
||||||
receipts: Cost,
|
body: U256,
|
||||||
state_proofs: Cost,
|
receipts: U256,
|
||||||
contract_codes: Cost,
|
account: U256,
|
||||||
header_proofs: Cost,
|
storage: U256,
|
||||||
transaction_proof: Cost, // cost per gas.
|
code: U256,
|
||||||
|
header_proof: U256,
|
||||||
|
transaction_proof: U256, // cost per gas.
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for CostTable {
|
impl Default for CostTable {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
// arbitrarily chosen constants.
|
// arbitrarily chosen constants.
|
||||||
CostTable {
|
CostTable {
|
||||||
headers: Cost(100000.into(), 10000.into()),
|
base: 100000.into(),
|
||||||
bodies: Cost(150000.into(), 15000.into()),
|
headers: 10000.into(),
|
||||||
receipts: Cost(50000.into(), 5000.into()),
|
body: 15000.into(),
|
||||||
state_proofs: Cost(250000.into(), 25000.into()),
|
receipts: 5000.into(),
|
||||||
contract_codes: Cost(200000.into(), 20000.into()),
|
account: 25000.into(),
|
||||||
header_proofs: Cost(150000.into(), 15000.into()),
|
storage: 25000.into(),
|
||||||
transaction_proof: Cost(100000.into(), 2.into()),
|
code: 20000.into(),
|
||||||
|
header_proof: 15000.into(),
|
||||||
|
transaction_proof: 2.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RlpEncodable for CostTable {
|
impl RlpEncodable for CostTable {
|
||||||
fn rlp_append(&self, s: &mut RlpStream) {
|
fn rlp_append(&self, s: &mut RlpStream) {
|
||||||
fn append_cost(s: &mut RlpStream, msg_id: u8, cost: &Cost) {
|
unimplemented!()
|
||||||
s.begin_list(3)
|
|
||||||
.append(&msg_id)
|
|
||||||
.append(&cost.0)
|
|
||||||
.append(&cost.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
s.begin_list(7);
|
|
||||||
|
|
||||||
append_cost(s, packet::GET_BLOCK_HEADERS, &self.headers);
|
|
||||||
append_cost(s, packet::GET_BLOCK_BODIES, &self.bodies);
|
|
||||||
append_cost(s, packet::GET_RECEIPTS, &self.receipts);
|
|
||||||
append_cost(s, packet::GET_PROOFS, &self.state_proofs);
|
|
||||||
append_cost(s, packet::GET_CONTRACT_CODES, &self.contract_codes);
|
|
||||||
append_cost(s, packet::GET_HEADER_PROOFS, &self.header_proofs);
|
|
||||||
append_cost(s, packet::GET_TRANSACTION_PROOF, &self.transaction_proof);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RlpDecodable for CostTable {
|
impl RlpDecodable for CostTable {
|
||||||
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
||||||
let rlp = decoder.as_rlp();
|
unimplemented!()
|
||||||
|
|
||||||
let mut headers = None;
|
|
||||||
let mut bodies = None;
|
|
||||||
let mut receipts = None;
|
|
||||||
let mut state_proofs = None;
|
|
||||||
let mut contract_codes = None;
|
|
||||||
let mut header_proofs = None;
|
|
||||||
let mut transaction_proof = None;
|
|
||||||
|
|
||||||
for row in rlp.iter() {
|
|
||||||
let msg_id: u8 = row.val_at(0)?;
|
|
||||||
let cost = {
|
|
||||||
let base = row.val_at(1)?;
|
|
||||||
let per = row.val_at(2)?;
|
|
||||||
|
|
||||||
Cost(base, per)
|
|
||||||
};
|
|
||||||
|
|
||||||
match msg_id {
|
|
||||||
packet::GET_BLOCK_HEADERS => headers = Some(cost),
|
|
||||||
packet::GET_BLOCK_BODIES => bodies = Some(cost),
|
|
||||||
packet::GET_RECEIPTS => receipts = Some(cost),
|
|
||||||
packet::GET_PROOFS => state_proofs = Some(cost),
|
|
||||||
packet::GET_CONTRACT_CODES => contract_codes = Some(cost),
|
|
||||||
packet::GET_HEADER_PROOFS => header_proofs = Some(cost),
|
|
||||||
packet::GET_TRANSACTION_PROOF => transaction_proof = Some(cost),
|
|
||||||
_ => return Err(DecoderError::Custom("Unrecognized message in cost table")),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(CostTable {
|
|
||||||
headers: headers.ok_or(DecoderError::Custom("No headers cost specified"))?,
|
|
||||||
bodies: bodies.ok_or(DecoderError::Custom("No bodies cost specified"))?,
|
|
||||||
receipts: receipts.ok_or(DecoderError::Custom("No receipts cost specified"))?,
|
|
||||||
state_proofs: state_proofs.ok_or(DecoderError::Custom("No proofs cost specified"))?,
|
|
||||||
contract_codes: contract_codes.ok_or(DecoderError::Custom("No contract codes specified"))?,
|
|
||||||
header_proofs: header_proofs.ok_or(DecoderError::Custom("No header proofs cost specified"))?,
|
|
||||||
transaction_proof: transaction_proof.ok_or(DecoderError::Custom("No transaction proof gas cost specified"))?,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,17 +138,19 @@ impl FlowParams {
|
|||||||
|
|
||||||
/// Create effectively infinite flow params.
|
/// Create effectively infinite flow params.
|
||||||
pub fn free() -> Self {
|
pub fn free() -> Self {
|
||||||
let free_cost = Cost(0.into(), 0.into());
|
let free_cost: U256 = 0.into();
|
||||||
FlowParams {
|
FlowParams {
|
||||||
limit: (!0u64).into(),
|
limit: (!0u64).into(),
|
||||||
recharge: 1.into(),
|
recharge: 1.into(),
|
||||||
costs: CostTable {
|
costs: CostTable {
|
||||||
|
base: free_cost.clone(),
|
||||||
headers: free_cost.clone(),
|
headers: free_cost.clone(),
|
||||||
bodies: free_cost.clone(),
|
body: free_cost.clone(),
|
||||||
receipts: free_cost.clone(),
|
receipts: free_cost.clone(),
|
||||||
state_proofs: free_cost.clone(),
|
account: free_cost.clone(),
|
||||||
contract_codes: free_cost.clone(),
|
storage: free_cost.clone(),
|
||||||
header_proofs: free_cost.clone(),
|
code: free_cost.clone(),
|
||||||
|
header_proof: free_cost.clone(),
|
||||||
transaction_proof: free_cost,
|
transaction_proof: free_cost,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -219,56 +167,20 @@ impl FlowParams {
|
|||||||
|
|
||||||
/// Compute the actual cost of a request, given the kind of request
|
/// Compute the actual cost of a request, given the kind of request
|
||||||
/// and number of requests made.
|
/// and number of requests made.
|
||||||
pub fn compute_cost(&self, kind: request::Kind, amount: usize) -> U256 {
|
pub fn compute_cost(&self, request: &Request) -> U256 {
|
||||||
let cost = match kind {
|
match *request {
|
||||||
request::Kind::Headers => &self.costs.headers,
|
Request::Headers(ref req) => self.costs.headers * req.max.into(),
|
||||||
request::Kind::Bodies => &self.costs.bodies,
|
Request::HeaderProof(_) => self.costs.header_proof,
|
||||||
request::Kind::Receipts => &self.costs.receipts,
|
Request::Body(_) => self.costs.body,
|
||||||
request::Kind::StateProofs => &self.costs.state_proofs,
|
Request::Receipts(_) => self.costs.receipts,
|
||||||
request::Kind::Codes => &self.costs.contract_codes,
|
Request::Account(_) => self.costs.account,
|
||||||
request::Kind::HeaderProofs => &self.costs.header_proofs,
|
Request::Storage(_) => self.costs.storage,
|
||||||
request::Kind::TransactionProof => &self.costs.transaction_proof,
|
Request::Code(_) => self.costs.code,
|
||||||
};
|
Request::Execution(ref req) => self.costs.transaction_proof * req.gas,
|
||||||
|
|
||||||
let amount: U256 = amount.into();
|
|
||||||
cost.0 + (amount * cost.1)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Compute the maximum number of costs of a specific kind which can be made
|
|
||||||
/// with the given amount of credits
|
|
||||||
/// Saturates at `usize::max()`. This is not a problem in practice because
|
|
||||||
/// this amount of requests is already prohibitively large.
|
|
||||||
pub fn max_amount(&self, credits: &Credits, kind: request::Kind) -> usize {
|
|
||||||
use util::Uint;
|
|
||||||
use std::usize;
|
|
||||||
|
|
||||||
let cost = match kind {
|
|
||||||
request::Kind::Headers => &self.costs.headers,
|
|
||||||
request::Kind::Bodies => &self.costs.bodies,
|
|
||||||
request::Kind::Receipts => &self.costs.receipts,
|
|
||||||
request::Kind::StateProofs => &self.costs.state_proofs,
|
|
||||||
request::Kind::Codes => &self.costs.contract_codes,
|
|
||||||
request::Kind::HeaderProofs => &self.costs.header_proofs,
|
|
||||||
request::Kind::TransactionProof => &self.costs.transaction_proof,
|
|
||||||
};
|
|
||||||
|
|
||||||
let start = credits.current();
|
|
||||||
|
|
||||||
if start <= cost.0 {
|
|
||||||
return 0;
|
|
||||||
} else if cost.1 == U256::zero() {
|
|
||||||
return usize::MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
let max = (start - cost.0) / cost.1;
|
|
||||||
if max >= usize::MAX.into() {
|
|
||||||
usize::MAX
|
|
||||||
} else {
|
|
||||||
max.as_u64() as usize
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create initial credits..
|
/// Create initial credits.
|
||||||
pub fn create_credits(&self) -> Credits {
|
pub fn create_credits(&self) -> Credits {
|
||||||
Credits {
|
Credits {
|
||||||
estimate: self.limit,
|
estimate: self.limit,
|
||||||
|
@ -89,22 +89,7 @@ impl RequestSet {
|
|||||||
None => return false,
|
None => return false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let kind = self.reqs.values()
|
unimplemented!()
|
||||||
.next()
|
|
||||||
.map(|r| r.kind())
|
|
||||||
.expect("base time implies `reqs` non-empty; qed");
|
|
||||||
|
|
||||||
let kind_timeout = match kind {
|
|
||||||
request::Kind::Headers => timeout::HEADERS,
|
|
||||||
request::Kind::Bodies => timeout::BODIES,
|
|
||||||
request::Kind::Receipts => timeout::RECEIPTS,
|
|
||||||
request::Kind::StateProofs => timeout::PROOFS,
|
|
||||||
request::Kind::Codes => timeout::CONTRACT_CODES,
|
|
||||||
request::Kind::HeaderProofs => timeout::HEADER_PROOFS,
|
|
||||||
request::Kind::TransactionProof => timeout::TRANSACTION_PROOF,
|
|
||||||
};
|
|
||||||
|
|
||||||
base + Duration::milliseconds(kind_timeout) <= now
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Collect all pending request ids.
|
/// Collect all pending request ids.
|
||||||
|
@ -121,7 +121,7 @@ pub trait Provider: Send + Sync {
|
|||||||
|
|
||||||
/// Provide a proof-of-execution for the given transaction proof request.
|
/// Provide a proof-of-execution for the given transaction proof request.
|
||||||
/// Returns a vector of all state items necessary to execute the transaction.
|
/// Returns a vector of all state items necessary to execute the transaction.
|
||||||
fn transaction_proof(&self, req: request::TransactionProof) -> Option<Vec<DBValue>>;
|
fn transaction_proof(&self, req: request::CompleteExecutionRequest) -> Option<request::ExecutionResponse>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implementation of a light client data provider for a client.
|
// Implementation of a light client data provider for a client.
|
||||||
@ -143,12 +143,12 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
BlockChainClient::block_body(self, BlockId::Hash(req.hash))
|
||||||
.map(|body| ::request::BodyResponse { body: body })
|
.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)
|
BlockChainClient::block_receipts(self, &req.hash)
|
||||||
.map(|x| ::request::ReceiptsResponse { receipts: ::rlp::decode(&x) })
|
.map(|x| ::request::ReceiptsResponse { receipts: ::rlp::decode(&x) })
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,7 +165,7 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn storage_proof(&self, req: request::CompleteStorageRequest) -> Option<request::StorageResponse> {
|
fn storage_proof(&self, req: request::CompleteStorageRequest) -> Option<request::StorageResponse> {
|
||||||
self.prove_account(req.address_hash, req.key_hash, BlockId::Hash(req.block_hash)).map(|(proof, item) | {
|
self.prove_storage(req.address_hash, req.key_hash, BlockId::Hash(req.block_hash)).map(|(proof, item) | {
|
||||||
::request::StorageResponse {
|
::request::StorageResponse {
|
||||||
proof: proof,
|
proof: proof,
|
||||||
value: item,
|
value: item,
|
||||||
@ -173,7 +173,7 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn contract_code(&self, req: request::ContractCode) -> Option<request::CodeResponse> {
|
fn contract_code(&self, req: request::CompleteCodeRequest) -> Option<request::CodeResponse> {
|
||||||
self.state_data(&req.code_hash)
|
self.state_data(&req.code_hash)
|
||||||
.map(|code| ::request::CodeResponse { code: code })
|
.map(|code| ::request::CodeResponse { code: code })
|
||||||
}
|
}
|
||||||
@ -239,7 +239,7 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
|
|||||||
fn transaction_proof(&self, req: request::CompleteExecutionRequest) -> Option<request::ExecutionResponse> {
|
fn transaction_proof(&self, req: request::CompleteExecutionRequest) -> Option<request::ExecutionResponse> {
|
||||||
use ethcore::transaction::Transaction;
|
use ethcore::transaction::Transaction;
|
||||||
|
|
||||||
let id = BlockId::Hash(req.at);
|
let id = BlockId::Hash(req.block_hash);
|
||||||
let nonce = match self.nonce(&req.from, id.clone()) {
|
let nonce = match self.nonce(&req.from, id.clone()) {
|
||||||
Some(nonce) => nonce,
|
Some(nonce) => nonce,
|
||||||
None => return None,
|
None => return None,
|
||||||
@ -321,7 +321,7 @@ impl<L: AsLightClient + Send + Sync> Provider for LightProvider<L> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transaction_proof(&self, _req: request::TransactionProof) -> Option<Vec<DBValue>> {
|
fn transaction_proof(&self, _req: request::CompleteExecutionRequest) -> Option<request::ExecutionResponse> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
116
ethcore/light/src/request_builder.rs
Normal file
116
ethcore/light/src/request_builder.rs
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
// 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Request chain builder utility.
|
||||||
|
//! Push requests with `push`. Back-references and data required to verify responses must be
|
||||||
|
//! supplied as well.
|
||||||
|
|
||||||
|
use std::collections::{HashMap, VecDeque};
|
||||||
|
use request::{
|
||||||
|
IncompleteRequest, CompleteRequest, Request,
|
||||||
|
Field, OutputKind, Output, NoSuchOutput, Response,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Build chained requests. Push them onto the series with `push`,
|
||||||
|
/// and produce a `Requests` object with `build`. Outputs are checked for consistency.
|
||||||
|
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
||||||
|
pub struct RequestBuilder {
|
||||||
|
output_kinds: HashMap<(usize, usize), OutputKind>,
|
||||||
|
requests: Vec<Request>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RequestBuilder {
|
||||||
|
/// Attempt to push a request onto the request chain. Fails if the request
|
||||||
|
/// references a non-existant output of a prior request.
|
||||||
|
pub fn push(&mut self, request: Request) -> Result<(), NoSuchOutput> {
|
||||||
|
request.check_outputs(|req, idx, kind| {
|
||||||
|
match self.output_kinds.get(&(req, idx)) {
|
||||||
|
Some(k) if k == &kind => Ok(()),
|
||||||
|
_ => Err(NoSuchOutput),
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
let req_idx = self.requests.len();
|
||||||
|
request.note_outputs(|idx, kind| { self.output_kinds.insert((req_idx, idx), kind); });
|
||||||
|
self.requests.push(request);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert this into a "requests" object.
|
||||||
|
pub fn build(self) -> Requests {
|
||||||
|
Requests {
|
||||||
|
output_kinds: self.output_kinds,
|
||||||
|
outputs: HashMap::new(),
|
||||||
|
requests: self.requests,
|
||||||
|
offset: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Requests pending responses.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct Requests {
|
||||||
|
output_kinds: HashMap<(usize, usize), OutputKind>,
|
||||||
|
outputs: HashMap<(usize, usize), Output>,
|
||||||
|
requests: Vec<Request>,
|
||||||
|
offset: usize, // offset for splitting.
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Requests {
|
||||||
|
/// For each request, produce responses for each.
|
||||||
|
/// The responses vector produced goes up to the point where the responder
|
||||||
|
/// first returns `None`, an invalid response, or until all requests have been responded to.
|
||||||
|
pub fn respond_to_all<F>(mut self, responder: F) -> Vec<Response>
|
||||||
|
where F: Fn(CompleteRequest) -> Option<Response>
|
||||||
|
{
|
||||||
|
let mut responses = Vec::new();
|
||||||
|
let mut found_bad = false;
|
||||||
|
let offset = self.offset;
|
||||||
|
let output_kinds = self.output_kinds;
|
||||||
|
let mut outputs = self.outputs;
|
||||||
|
for (idx, req) in self.requests.into_iter().enumerate().map(|(idx, req)| (idx + offset, req)) {
|
||||||
|
let complete = req.fill(|req_idx, out_idx| outputs.get(&(req_idx, out_idx)).cloned().ok_or(NoSuchOutput))
|
||||||
|
.expect("All outputs checked as invariant of `Requests` object; qed");
|
||||||
|
|
||||||
|
match responder(complete) {
|
||||||
|
Some(response) => {
|
||||||
|
response.fill_outputs(|out_idx, output| {
|
||||||
|
match output_kinds.get(&(idx, out_idx)) {
|
||||||
|
None => {},
|
||||||
|
Some(out) => if out == &output.kind() {
|
||||||
|
outputs.insert((idx, out_idx), output);
|
||||||
|
} else {
|
||||||
|
// output kind doesn't match expected.
|
||||||
|
found_bad = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if found_bad {
|
||||||
|
return responses;
|
||||||
|
}
|
||||||
|
|
||||||
|
responses.push(response);
|
||||||
|
}
|
||||||
|
None => return responses,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
responses
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get access to the underlying slice of requests.
|
||||||
|
pub fn requests(&self) -> &[Request] { &self.requests }
|
||||||
|
}
|
@ -19,7 +19,7 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use ethcore::transaction::Action;
|
use ethcore::transaction::Action;
|
||||||
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream};
|
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream, View};
|
||||||
use util::{Address, H256, U256, Uint};
|
use util::{Address, H256, U256, Uint};
|
||||||
|
|
||||||
// re-exports of request types.
|
// re-exports of request types.
|
||||||
@ -65,6 +65,7 @@ pub use self::execution::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Error indicating a reference to a non-existent or wrongly-typed output.
|
/// Error indicating a reference to a non-existent or wrongly-typed output.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct NoSuchOutput;
|
pub struct NoSuchOutput;
|
||||||
|
|
||||||
/// An input to a request.
|
/// An input to a request.
|
||||||
@ -77,7 +78,7 @@ pub enum Field<T> {
|
|||||||
BackReference(usize, usize),
|
BackReference(usize, usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<T> for Field<T> {
|
impl<T> From<T> for Field<T> {
|
||||||
fn from(val: T) -> Self {
|
fn from(val: T) -> Self {
|
||||||
Field::Scalar(val)
|
Field::Scalar(val)
|
||||||
}
|
}
|
||||||
@ -119,7 +120,8 @@ pub enum Output {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Output {
|
impl Output {
|
||||||
fn kind(&self) -> OutputKind {
|
/// Get the output kind.
|
||||||
|
pub fn kind(&self) -> OutputKind {
|
||||||
match *self {
|
match *self {
|
||||||
Output::Hash(_) => OutputKind::Hash,
|
Output::Hash(_) => OutputKind::Hash,
|
||||||
Output::Number(_) => OutputKind::Number,
|
Output::Number(_) => OutputKind::Number,
|
||||||
@ -158,6 +160,24 @@ impl From<u64> for HashOrNumber {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Decodable for HashOrNumber {
|
||||||
|
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
||||||
|
let rlp = decoder.as_rlp();
|
||||||
|
|
||||||
|
rlp.val_at::<H256>(0).map(HashOrNumber::Hash)
|
||||||
|
.or_else(|_| rlp.val_at(0).map(HashOrNumber::Number))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Encodable for HashOrNumber {
|
||||||
|
fn rlp_append(&self, s: &mut RlpStream) {
|
||||||
|
match *self {
|
||||||
|
HashOrNumber::Hash(ref hash) => s.append(hash),
|
||||||
|
HashOrNumber::Number(ref num) => s.append(num),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// All request types, as they're sent over the network.
|
/// All request types, as they're sent over the network.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum Request {
|
pub enum Request {
|
||||||
@ -305,13 +325,20 @@ impl IncompleteRequest for Request {
|
|||||||
pub enum Kind {
|
pub enum Kind {
|
||||||
/// A request for headers.
|
/// A request for headers.
|
||||||
Headers = 0,
|
Headers = 0,
|
||||||
|
/// A request for a header proof.
|
||||||
HeaderProof = 1,
|
HeaderProof = 1,
|
||||||
// TransactionIndex = 2,
|
// TransactionIndex = 2,
|
||||||
|
/// A request for block receipts.
|
||||||
Receipts = 3,
|
Receipts = 3,
|
||||||
|
/// A request for a block body.
|
||||||
Body = 4,
|
Body = 4,
|
||||||
|
/// A request for an account + merkle proof.
|
||||||
Account = 5,
|
Account = 5,
|
||||||
|
/// A request for contract storage + merkle proof
|
||||||
Storage = 6,
|
Storage = 6,
|
||||||
|
/// A request for contract.
|
||||||
Code = 7,
|
Code = 7,
|
||||||
|
/// A request for transaction execution + state proof.
|
||||||
Execution = 8,
|
Execution = 8,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,7 +363,7 @@ impl Decodable for Kind {
|
|||||||
|
|
||||||
impl Encodable for Kind {
|
impl Encodable for Kind {
|
||||||
fn rlp_append(&self, s: &mut RlpStream) {
|
fn rlp_append(&self, s: &mut RlpStream) {
|
||||||
s.append(self as &u8);
|
s.append(&(*self as u8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -366,14 +393,14 @@ impl Response {
|
|||||||
/// Fill reusable outputs by writing them into the function.
|
/// Fill reusable outputs by writing them into the function.
|
||||||
pub fn fill_outputs<F>(&self, mut f: F) where F: FnMut(usize, Output) {
|
pub fn fill_outputs<F>(&self, mut f: F) where F: FnMut(usize, Output) {
|
||||||
match *self {
|
match *self {
|
||||||
Response::Headers(res) => res.fill_outputs(f),
|
Response::Headers(ref res) => res.fill_outputs(f),
|
||||||
Response::HeaderProof(res) => res.fill_outputs(f),
|
Response::HeaderProof(ref res) => res.fill_outputs(f),
|
||||||
Response::Receipts(res) => res.fill_outputs(f),
|
Response::Receipts(ref res) => res.fill_outputs(f),
|
||||||
Response::Body(res) => res.fill_outputs(f),
|
Response::Body(ref res) => res.fill_outputs(f),
|
||||||
Response::Account(res) => res.fill_outputs(f),
|
Response::Account(ref res) => res.fill_outputs(f),
|
||||||
Response::Storage(res) => res.fill_outputs(f),
|
Response::Storage(ref res) => res.fill_outputs(f),
|
||||||
Response::Code(res) => res.fill_outputs(f),
|
Response::Code(ref res) => res.fill_outputs(f),
|
||||||
Response::Execution(res) => res.fill_outputs(f),
|
Response::Execution(ref res) => res.fill_outputs(f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,7 +413,7 @@ impl Response {
|
|||||||
Response::Account(_) => Kind::Account,
|
Response::Account(_) => Kind::Account,
|
||||||
Response::Storage(_) => Kind::Storage,
|
Response::Storage(_) => Kind::Storage,
|
||||||
Response::Code(_) => Kind::Code,
|
Response::Code(_) => Kind::Code,
|
||||||
Respnse::Execution(_) => Kind::Execution,
|
Response::Execution(_) => Kind::Execution,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -403,7 +430,7 @@ impl Decodable for Response {
|
|||||||
Kind::Account => Ok(Response::Account(rlp.val_at(1)?)),
|
Kind::Account => Ok(Response::Account(rlp.val_at(1)?)),
|
||||||
Kind::Storage => Ok(Response::Storage(rlp.val_at(1)?)),
|
Kind::Storage => Ok(Response::Storage(rlp.val_at(1)?)),
|
||||||
Kind::Code => Ok(Response::Code(rlp.val_at(1)?)),
|
Kind::Code => Ok(Response::Code(rlp.val_at(1)?)),
|
||||||
Kind::Execution=> Ok(Response::Execution(rlp.val_at(1)?)),
|
Kind::Execution => Ok(Response::Execution(rlp.val_at(1)?)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -427,6 +454,7 @@ impl Encodable for Response {
|
|||||||
|
|
||||||
/// A potentially incomplete request.
|
/// A potentially incomplete request.
|
||||||
pub trait IncompleteRequest: Sized {
|
pub trait IncompleteRequest: Sized {
|
||||||
|
/// The complete variant of this request.
|
||||||
type Complete;
|
type Complete;
|
||||||
|
|
||||||
/// Check prior outputs against the needed inputs.
|
/// Check prior outputs against the needed inputs.
|
||||||
@ -453,7 +481,6 @@ pub mod header {
|
|||||||
use super::{Field, HashOrNumber, NoSuchOutput, OutputKind, Output};
|
use super::{Field, HashOrNumber, NoSuchOutput, OutputKind, Output};
|
||||||
use ethcore::encoded;
|
use ethcore::encoded;
|
||||||
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream, View};
|
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream, View};
|
||||||
use util::U256;
|
|
||||||
|
|
||||||
/// Potentially incomplete headers request.
|
/// Potentially incomplete headers request.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
@ -461,9 +488,9 @@ pub mod header {
|
|||||||
/// Start block.
|
/// Start block.
|
||||||
pub start: Field<HashOrNumber>,
|
pub start: Field<HashOrNumber>,
|
||||||
/// Skip between.
|
/// Skip between.
|
||||||
pub skip: U256,
|
pub skip: u64,
|
||||||
/// Maximum to return.
|
/// Maximum to return.
|
||||||
pub max: U256,
|
pub max: u64,
|
||||||
/// Whether to reverse from start.
|
/// Whether to reverse from start.
|
||||||
pub reverse: bool,
|
pub reverse: bool,
|
||||||
}
|
}
|
||||||
@ -499,7 +526,7 @@ pub mod header {
|
|||||||
match self.start {
|
match self.start {
|
||||||
Field::Scalar(_) => Ok(()),
|
Field::Scalar(_) => Ok(()),
|
||||||
Field::BackReference(req, idx) =>
|
Field::BackReference(req, idx) =>
|
||||||
f(req, idx, OutputKind::Hash).or_else(|| f(req, idx, OutputKind::Number))
|
f(req, idx, OutputKind::Hash).or_else(|_| f(req, idx, OutputKind::Number))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -532,9 +559,9 @@ pub mod header {
|
|||||||
/// Start block.
|
/// Start block.
|
||||||
pub start: HashOrNumber,
|
pub start: HashOrNumber,
|
||||||
/// Skip between.
|
/// Skip between.
|
||||||
pub skip: U256,
|
pub skip: u64,
|
||||||
/// Maximum to return.
|
/// Maximum to return.
|
||||||
pub max: U256,
|
pub max: u64,
|
||||||
/// Whether to reverse from start.
|
/// Whether to reverse from start.
|
||||||
pub reverse: bool,
|
pub reverse: bool,
|
||||||
}
|
}
|
||||||
@ -695,7 +722,7 @@ pub mod block_receipts {
|
|||||||
use super::{Field, NoSuchOutput, OutputKind, Output};
|
use super::{Field, NoSuchOutput, OutputKind, Output};
|
||||||
use ethcore::receipt::Receipt;
|
use ethcore::receipt::Receipt;
|
||||||
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream, View};
|
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream, View};
|
||||||
use util::{Bytes, U256, H256};
|
use util::H256;
|
||||||
|
|
||||||
/// Potentially incomplete block receipts request.
|
/// Potentially incomplete block receipts request.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
@ -725,7 +752,7 @@ pub mod block_receipts {
|
|||||||
fn check_outputs<F>(&self, mut f: F) -> Result<(), NoSuchOutput>
|
fn check_outputs<F>(&self, mut f: F) -> Result<(), NoSuchOutput>
|
||||||
where F: FnMut(usize, usize, OutputKind) -> Result<(), NoSuchOutput>
|
where F: FnMut(usize, usize, OutputKind) -> Result<(), NoSuchOutput>
|
||||||
{
|
{
|
||||||
match self.num {
|
match self.hash {
|
||||||
Field::Scalar(_) => Ok(()),
|
Field::Scalar(_) => Ok(()),
|
||||||
Field::BackReference(req, idx) => f(req, idx, OutputKind::Hash),
|
Field::BackReference(req, idx) => f(req, idx, OutputKind::Hash),
|
||||||
}
|
}
|
||||||
@ -791,7 +818,7 @@ pub mod block_body {
|
|||||||
use super::{Field, NoSuchOutput, OutputKind, Output};
|
use super::{Field, NoSuchOutput, OutputKind, Output};
|
||||||
use ethcore::encoded;
|
use ethcore::encoded;
|
||||||
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream, View};
|
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream, View};
|
||||||
use util::{Bytes, U256, H256};
|
use util::H256;
|
||||||
|
|
||||||
/// Potentially incomplete block body request.
|
/// Potentially incomplete block body request.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
@ -821,7 +848,7 @@ pub mod block_body {
|
|||||||
fn check_outputs<F>(&self, mut f: F) -> Result<(), NoSuchOutput>
|
fn check_outputs<F>(&self, mut f: F) -> Result<(), NoSuchOutput>
|
||||||
where F: FnMut(usize, usize, OutputKind) -> Result<(), NoSuchOutput>
|
where F: FnMut(usize, usize, OutputKind) -> Result<(), NoSuchOutput>
|
||||||
{
|
{
|
||||||
match self.num {
|
match self.hash {
|
||||||
Field::Scalar(_) => Ok(()),
|
Field::Scalar(_) => Ok(()),
|
||||||
Field::BackReference(req, idx) => f(req, idx, OutputKind::Hash),
|
Field::BackReference(req, idx) => f(req, idx, OutputKind::Hash),
|
||||||
}
|
}
|
||||||
@ -869,14 +896,14 @@ pub mod block_body {
|
|||||||
impl Decodable for Response {
|
impl Decodable for Response {
|
||||||
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
||||||
use ethcore::header::Header as FullHeader;
|
use ethcore::header::Header as FullHeader;
|
||||||
use ethcore::transaction::SignedTransaction;
|
use ethcore::transaction::UnverifiedTransaction;
|
||||||
|
|
||||||
let rlp = decoder.as_rlp();
|
let rlp = decoder.as_rlp();
|
||||||
let body_rlp = rlp.at(0)?;
|
let body_rlp = rlp.at(0)?;
|
||||||
|
|
||||||
// check body validity.
|
// check body validity.
|
||||||
let _: Vec<FullHeader> = rlp.val_at(0)?;
|
let _: Vec<FullHeader> = rlp.val_at(0)?;
|
||||||
let _: Vec<SignedTransaction> = rlp.val_at(1)?;
|
let _: Vec<UnverifiedTransaction> = rlp.val_at(1)?;
|
||||||
|
|
||||||
Ok(Response {
|
Ok(Response {
|
||||||
body: encoded::Body::new(body_rlp.as_raw().to_owned()),
|
body: encoded::Body::new(body_rlp.as_raw().to_owned()),
|
||||||
@ -895,7 +922,6 @@ pub mod block_body {
|
|||||||
/// A request for an account proof.
|
/// A request for an account proof.
|
||||||
pub mod account {
|
pub mod account {
|
||||||
use super::{Field, NoSuchOutput, OutputKind, Output};
|
use super::{Field, NoSuchOutput, OutputKind, Output};
|
||||||
use ethcore::encoded;
|
|
||||||
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream, View};
|
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream, View};
|
||||||
use util::{Bytes, U256, H256};
|
use util::{Bytes, U256, H256};
|
||||||
|
|
||||||
@ -1028,7 +1054,7 @@ pub mod account {
|
|||||||
.append(&self.nonce)
|
.append(&self.nonce)
|
||||||
.append(&self.balance)
|
.append(&self.balance)
|
||||||
.append(&self.code_hash)
|
.append(&self.code_hash)
|
||||||
.append(&self.storage_root)
|
.append(&self.storage_root);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1036,9 +1062,8 @@ pub mod account {
|
|||||||
/// A request for a storage proof.
|
/// A request for a storage proof.
|
||||||
pub mod storage {
|
pub mod storage {
|
||||||
use super::{Field, NoSuchOutput, OutputKind, Output};
|
use super::{Field, NoSuchOutput, OutputKind, Output};
|
||||||
use ethcore::encoded;
|
|
||||||
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream, View};
|
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream, View};
|
||||||
use util::{Bytes, U256, H256};
|
use util::{Bytes, H256};
|
||||||
|
|
||||||
/// Potentially incomplete request for an storage proof.
|
/// Potentially incomplete request for an storage proof.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
@ -1182,9 +1207,8 @@ pub mod storage {
|
|||||||
/// A request for contract code.
|
/// A request for contract code.
|
||||||
pub mod contract_code {
|
pub mod contract_code {
|
||||||
use super::{Field, NoSuchOutput, OutputKind, Output};
|
use super::{Field, NoSuchOutput, OutputKind, Output};
|
||||||
use ethcore::encoded;
|
|
||||||
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream, View};
|
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream, View};
|
||||||
use util::{Bytes, U256, H256};
|
use util::{Bytes, H256};
|
||||||
|
|
||||||
/// Potentially incomplete contract code request.
|
/// Potentially incomplete contract code request.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
@ -1299,7 +1323,6 @@ pub mod contract_code {
|
|||||||
/// A request for proof of execution.
|
/// A request for proof of execution.
|
||||||
pub mod execution {
|
pub mod execution {
|
||||||
use super::{Field, NoSuchOutput, OutputKind, Output};
|
use super::{Field, NoSuchOutput, OutputKind, Output};
|
||||||
use ethcore::encoded;
|
|
||||||
use ethcore::transaction::Action;
|
use ethcore::transaction::Action;
|
||||||
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream, View};
|
use rlp::{Encodable, Decodable, Decoder, DecoderError, RlpStream, Stream, View};
|
||||||
use util::{Bytes, Address, U256, H256, DBValue};
|
use util::{Bytes, Address, U256, H256, DBValue};
|
||||||
@ -1328,7 +1351,7 @@ pub mod execution {
|
|||||||
let rlp = decoder.as_rlp();
|
let rlp = decoder.as_rlp();
|
||||||
Ok(Incomplete {
|
Ok(Incomplete {
|
||||||
block_hash: rlp.val_at(0)?,
|
block_hash: rlp.val_at(0)?,
|
||||||
address: rlp.val_at(1)?,
|
from: rlp.val_at(1)?,
|
||||||
action: rlp.val_at(2)?,
|
action: rlp.val_at(2)?,
|
||||||
gas: rlp.val_at(3)?,
|
gas: rlp.val_at(3)?,
|
||||||
gas_price: rlp.val_at(4)?,
|
gas_price: rlp.val_at(4)?,
|
||||||
@ -1344,7 +1367,7 @@ pub mod execution {
|
|||||||
.append(&self.block_hash)
|
.append(&self.block_hash)
|
||||||
.append(&self.from);
|
.append(&self.from);
|
||||||
|
|
||||||
match *self.action {
|
match self.action {
|
||||||
Action::Create => s.append_empty_data(),
|
Action::Create => s.append_empty_data(),
|
||||||
Action::Call(ref addr) => s.append(addr),
|
Action::Call(ref addr) => s.append(addr),
|
||||||
};
|
};
|
||||||
@ -1432,7 +1455,7 @@ pub mod execution {
|
|||||||
let mut items = Vec::new();
|
let mut items = Vec::new();
|
||||||
for raw_item in rlp.at(0)?.iter() {
|
for raw_item in rlp.at(0)?.iter() {
|
||||||
let mut item = DBValue::new();
|
let mut item = DBValue::new();
|
||||||
item.append_slice(raw_item.data());
|
item.append_slice(raw_item.data()?);
|
||||||
items.push(item);
|
items.push(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1444,7 +1467,7 @@ pub mod execution {
|
|||||||
|
|
||||||
impl Encodable for Response {
|
impl Encodable for Response {
|
||||||
fn rlp_append(&self, s: &mut RlpStream) {
|
fn rlp_append(&self, s: &mut RlpStream) {
|
||||||
s.begin_list(&self.items.len());
|
s.begin_list(self.items.len());
|
||||||
|
|
||||||
for item in &self.items {
|
for item in &self.items {
|
||||||
s.append(&&**item);
|
s.append(&&**item);
|
||||||
|
Loading…
Reference in New Issue
Block a user