Merge branch 'master' into ui-2
This commit is contained in:
commit
c33ff96bb6
@ -66,6 +66,8 @@ pub enum Error {
|
|||||||
BadProtocolVersion,
|
BadProtocolVersion,
|
||||||
/// Peer is overburdened.
|
/// Peer is overburdened.
|
||||||
Overburdened,
|
Overburdened,
|
||||||
|
/// No handler kept the peer.
|
||||||
|
RejectedByHandlers,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error {
|
impl Error {
|
||||||
@ -85,6 +87,7 @@ impl Error {
|
|||||||
Error::UnsupportedProtocolVersion(_) => Punishment::Disable,
|
Error::UnsupportedProtocolVersion(_) => Punishment::Disable,
|
||||||
Error::BadProtocolVersion => Punishment::Disable,
|
Error::BadProtocolVersion => Punishment::Disable,
|
||||||
Error::Overburdened => Punishment::None,
|
Error::Overburdened => Punishment::None,
|
||||||
|
Error::RejectedByHandlers => Punishment::Disconnect,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -117,6 +120,7 @@ impl fmt::Display for Error {
|
|||||||
Error::UnsupportedProtocolVersion(pv) => write!(f, "Unsupported protocol version: {}", pv),
|
Error::UnsupportedProtocolVersion(pv) => write!(f, "Unsupported protocol version: {}", pv),
|
||||||
Error::BadProtocolVersion => write!(f, "Bad protocol version in handshake"),
|
Error::BadProtocolVersion => write!(f, "Bad protocol version in handshake"),
|
||||||
Error::Overburdened => write!(f, "Peer overburdened"),
|
Error::Overburdened => write!(f, "Peer overburdened"),
|
||||||
|
Error::RejectedByHandlers => write!(f, "No handler kept this peer"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,7 @@ fn hardcoded_serve_time(kind: Kind) -> u64 {
|
|||||||
match kind {
|
match kind {
|
||||||
Kind::Headers => 500_000,
|
Kind::Headers => 500_000,
|
||||||
Kind::HeaderProof => 500_000,
|
Kind::HeaderProof => 500_000,
|
||||||
|
Kind::TransactionIndex => 500_000,
|
||||||
Kind::Receipts => 1_000_000,
|
Kind::Receipts => 1_000_000,
|
||||||
Kind::Body => 1_000_000,
|
Kind::Body => 1_000_000,
|
||||||
Kind::Account => 1_500_000,
|
Kind::Account => 1_500_000,
|
||||||
|
@ -31,6 +31,7 @@ use std::collections::{HashMap, HashSet};
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
use std::ops::{BitOr, BitAnd, Not};
|
||||||
|
|
||||||
use provider::Provider;
|
use provider::Provider;
|
||||||
use request::{Request, NetworkRequests as Requests, Response};
|
use request::{Request, NetworkRequests as Requests, Response};
|
||||||
@ -80,7 +81,7 @@ pub const PROTOCOL_VERSIONS: &'static [u8] = &[1];
|
|||||||
pub const MAX_PROTOCOL_VERSION: u8 = 1;
|
pub const MAX_PROTOCOL_VERSION: u8 = 1;
|
||||||
|
|
||||||
/// Packet count for PIP.
|
/// Packet count for PIP.
|
||||||
pub const PACKET_COUNT: u8 = 5;
|
pub const PACKET_COUNT: u8 = 9;
|
||||||
|
|
||||||
// packet ID definitions.
|
// packet ID definitions.
|
||||||
mod packet {
|
mod packet {
|
||||||
@ -100,6 +101,10 @@ mod packet {
|
|||||||
|
|
||||||
// relay transactions to peers.
|
// relay transactions to peers.
|
||||||
pub const SEND_TRANSACTIONS: u8 = 0x06;
|
pub const SEND_TRANSACTIONS: u8 = 0x06;
|
||||||
|
|
||||||
|
// request and respond with epoch transition proof
|
||||||
|
pub const REQUEST_EPOCH_PROOF: u8 = 0x07;
|
||||||
|
pub const EPOCH_PROOF: u8 = 0x08;
|
||||||
}
|
}
|
||||||
|
|
||||||
// timeouts for different kinds of requests. all values are in milliseconds.
|
// timeouts for different kinds of requests. all values are in milliseconds.
|
||||||
@ -110,6 +115,7 @@ mod timeout {
|
|||||||
|
|
||||||
// timeouts per request within packet.
|
// timeouts per request within packet.
|
||||||
pub const HEADERS: i64 = 250; // per header?
|
pub const HEADERS: i64 = 250; // per header?
|
||||||
|
pub const TRANSACTION_INDEX: i64 = 100;
|
||||||
pub const BODY: i64 = 50;
|
pub const BODY: i64 = 50;
|
||||||
pub const RECEIPT: i64 = 50;
|
pub const RECEIPT: i64 = 50;
|
||||||
pub const PROOF: i64 = 100; // state proof
|
pub const PROOF: i64 = 100; // state proof
|
||||||
@ -157,6 +163,54 @@ pub struct Peer {
|
|||||||
awaiting_acknowledge: Option<(SteadyTime, Arc<FlowParams>)>,
|
awaiting_acknowledge: Option<(SteadyTime, Arc<FlowParams>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether or not a peer was kept by a handler
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum PeerStatus {
|
||||||
|
/// The peer was kept
|
||||||
|
Kept,
|
||||||
|
/// The peer was not kept
|
||||||
|
Unkept,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Not for PeerStatus {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn not(self) -> Self {
|
||||||
|
use self::PeerStatus::*;
|
||||||
|
|
||||||
|
match self {
|
||||||
|
Kept => Unkept,
|
||||||
|
Unkept => Kept,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitAnd for PeerStatus {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn bitand(self, other: Self) -> Self {
|
||||||
|
use self::PeerStatus::*;
|
||||||
|
|
||||||
|
match (self, other) {
|
||||||
|
(Kept, Kept) => Kept,
|
||||||
|
_ => Unkept,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitOr for PeerStatus {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn bitor(self, other: Self) -> Self {
|
||||||
|
use self::PeerStatus::*;
|
||||||
|
|
||||||
|
match (self, other) {
|
||||||
|
(_, Kept) | (Kept, _) => Kept,
|
||||||
|
_ => Unkept,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A light protocol event handler.
|
/// A light protocol event handler.
|
||||||
///
|
///
|
||||||
/// Each handler function takes a context which describes the relevant peer
|
/// Each handler function takes a context which describes the relevant peer
|
||||||
@ -168,7 +222,12 @@ pub struct Peer {
|
|||||||
/// that relevant data will be stored by interested handlers.
|
/// that relevant data will be stored by interested handlers.
|
||||||
pub trait Handler: Send + Sync {
|
pub trait Handler: Send + Sync {
|
||||||
/// Called when a peer connects.
|
/// Called when a peer connects.
|
||||||
fn on_connect(&self, _ctx: &EventContext, _status: &Status, _capabilities: &Capabilities) { }
|
fn on_connect(
|
||||||
|
&self,
|
||||||
|
_ctx: &EventContext,
|
||||||
|
_status: &Status,
|
||||||
|
_capabilities: &Capabilities
|
||||||
|
) -> PeerStatus { PeerStatus::Kept }
|
||||||
/// Called when a peer disconnects, with a list of unfulfilled request IDs as
|
/// Called when a peer disconnects, with a list of unfulfilled request IDs as
|
||||||
/// of yet.
|
/// of yet.
|
||||||
fn on_disconnect(&self, _ctx: &EventContext, _unfulfilled: &[ReqId]) { }
|
fn on_disconnect(&self, _ctx: &EventContext, _unfulfilled: &[ReqId]) { }
|
||||||
@ -523,6 +582,12 @@ impl LightProtocol {
|
|||||||
|
|
||||||
packet::SEND_TRANSACTIONS => self.relay_transactions(peer, io, rlp),
|
packet::SEND_TRANSACTIONS => self.relay_transactions(peer, io, rlp),
|
||||||
|
|
||||||
|
packet::REQUEST_EPOCH_PROOF | packet::EPOCH_PROOF => {
|
||||||
|
// ignore these for now, but leave them specified.
|
||||||
|
debug!(target: "pip", "Ignoring request/response for epoch proof");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
other => {
|
other => {
|
||||||
Err(Error::UnrecognizedPacket(other))
|
Err(Error::UnrecognizedPacket(other))
|
||||||
}
|
}
|
||||||
@ -766,15 +831,23 @@ impl LightProtocol {
|
|||||||
awaiting_acknowledge: None,
|
awaiting_acknowledge: None,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
for handler in &self.handlers {
|
let any_kept = self.handlers.iter().map(
|
||||||
handler.on_connect(&Ctx {
|
|handler| handler.on_connect(
|
||||||
peer: *peer,
|
&Ctx {
|
||||||
io: io,
|
peer: *peer,
|
||||||
proto: self,
|
io: io,
|
||||||
}, &status, &capabilities)
|
proto: self,
|
||||||
}
|
},
|
||||||
|
&status,
|
||||||
|
&capabilities
|
||||||
|
)
|
||||||
|
).fold(PeerStatus::Kept, PeerStatus::bitor);
|
||||||
|
|
||||||
Ok(())
|
if any_kept == PeerStatus::Unkept {
|
||||||
|
Err(Error::RejectedByHandlers)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle an announcement.
|
// Handle an announcement.
|
||||||
@ -867,6 +940,7 @@ impl LightProtocol {
|
|||||||
match complete_req {
|
match complete_req {
|
||||||
CompleteRequest::Headers(req) => self.provider.block_headers(req).map(Response::Headers),
|
CompleteRequest::Headers(req) => self.provider.block_headers(req).map(Response::Headers),
|
||||||
CompleteRequest::HeaderProof(req) => self.provider.header_proof(req).map(Response::HeaderProof),
|
CompleteRequest::HeaderProof(req) => self.provider.header_proof(req).map(Response::HeaderProof),
|
||||||
|
CompleteRequest::TransactionIndex(_) => None, // don't answer these yet, but leave them in protocol.
|
||||||
CompleteRequest::Body(req) => self.provider.block_body(req).map(Response::Body),
|
CompleteRequest::Body(req) => self.provider.block_body(req).map(Response::Body),
|
||||||
CompleteRequest::Receipts(req) => self.provider.block_receipts(req).map(Response::Receipts),
|
CompleteRequest::Receipts(req) => self.provider.block_receipts(req).map(Response::Receipts),
|
||||||
CompleteRequest::Account(req) => self.provider.account_proof(req).map(Response::Account),
|
CompleteRequest::Account(req) => self.provider.account_proof(req).map(Response::Account),
|
||||||
|
@ -83,6 +83,7 @@ impl Credits {
|
|||||||
pub struct CostTable {
|
pub struct CostTable {
|
||||||
base: U256, // cost per packet.
|
base: U256, // cost per packet.
|
||||||
headers: U256, // cost per header
|
headers: U256, // cost per header
|
||||||
|
transaction_index: U256,
|
||||||
body: U256,
|
body: U256,
|
||||||
receipts: U256,
|
receipts: U256,
|
||||||
account: U256,
|
account: U256,
|
||||||
@ -98,6 +99,7 @@ impl Default for CostTable {
|
|||||||
CostTable {
|
CostTable {
|
||||||
base: 100000.into(),
|
base: 100000.into(),
|
||||||
headers: 10000.into(),
|
headers: 10000.into(),
|
||||||
|
transaction_index: 10000.into(),
|
||||||
body: 15000.into(),
|
body: 15000.into(),
|
||||||
receipts: 5000.into(),
|
receipts: 5000.into(),
|
||||||
account: 25000.into(),
|
account: 25000.into(),
|
||||||
@ -119,8 +121,9 @@ impl Encodable for CostTable {
|
|||||||
s.append(cost);
|
s.append(cost);
|
||||||
}
|
}
|
||||||
|
|
||||||
s.begin_list(9).append(&self.base);
|
s.begin_list(10).append(&self.base);
|
||||||
append_cost(s, &self.headers, request::Kind::Headers);
|
append_cost(s, &self.headers, request::Kind::Headers);
|
||||||
|
append_cost(s, &self.transaction_index, request::Kind::TransactionIndex);
|
||||||
append_cost(s, &self.body, request::Kind::Body);
|
append_cost(s, &self.body, request::Kind::Body);
|
||||||
append_cost(s, &self.receipts, request::Kind::Receipts);
|
append_cost(s, &self.receipts, request::Kind::Receipts);
|
||||||
append_cost(s, &self.account, request::Kind::Account);
|
append_cost(s, &self.account, request::Kind::Account);
|
||||||
@ -136,6 +139,7 @@ impl Decodable for CostTable {
|
|||||||
let base = rlp.val_at(0)?;
|
let base = rlp.val_at(0)?;
|
||||||
|
|
||||||
let mut headers = None;
|
let mut headers = None;
|
||||||
|
let mut transaction_index = None;
|
||||||
let mut body = None;
|
let mut body = None;
|
||||||
let mut receipts = None;
|
let mut receipts = None;
|
||||||
let mut account = None;
|
let mut account = None;
|
||||||
@ -148,6 +152,7 @@ impl Decodable for CostTable {
|
|||||||
let cost = cost_list.val_at(1)?;
|
let cost = cost_list.val_at(1)?;
|
||||||
match cost_list.val_at(0)? {
|
match cost_list.val_at(0)? {
|
||||||
request::Kind::Headers => headers = Some(cost),
|
request::Kind::Headers => headers = Some(cost),
|
||||||
|
request::Kind::TransactionIndex => transaction_index = Some(cost),
|
||||||
request::Kind::Body => body = Some(cost),
|
request::Kind::Body => body = Some(cost),
|
||||||
request::Kind::Receipts => receipts = Some(cost),
|
request::Kind::Receipts => receipts = Some(cost),
|
||||||
request::Kind::Account => account = Some(cost),
|
request::Kind::Account => account = Some(cost),
|
||||||
@ -163,6 +168,7 @@ impl Decodable for CostTable {
|
|||||||
Ok(CostTable {
|
Ok(CostTable {
|
||||||
base: base,
|
base: base,
|
||||||
headers: unwrap_cost(headers)?,
|
headers: unwrap_cost(headers)?,
|
||||||
|
transaction_index: unwrap_cost(transaction_index)?,
|
||||||
body: unwrap_cost(body)?,
|
body: unwrap_cost(body)?,
|
||||||
receipts: unwrap_cost(receipts)?,
|
receipts: unwrap_cost(receipts)?,
|
||||||
account: unwrap_cost(account)?,
|
account: unwrap_cost(account)?,
|
||||||
@ -224,6 +230,7 @@ impl FlowParams {
|
|||||||
let costs = CostTable {
|
let costs = CostTable {
|
||||||
base: 0.into(),
|
base: 0.into(),
|
||||||
headers: cost_for_kind(Kind::Headers),
|
headers: cost_for_kind(Kind::Headers),
|
||||||
|
transaction_index: cost_for_kind(Kind::TransactionIndex),
|
||||||
body: cost_for_kind(Kind::Body),
|
body: cost_for_kind(Kind::Body),
|
||||||
receipts: cost_for_kind(Kind::Receipts),
|
receipts: cost_for_kind(Kind::Receipts),
|
||||||
account: cost_for_kind(Kind::Account),
|
account: cost_for_kind(Kind::Account),
|
||||||
@ -249,6 +256,7 @@ impl FlowParams {
|
|||||||
costs: CostTable {
|
costs: CostTable {
|
||||||
base: free_cost.clone(),
|
base: free_cost.clone(),
|
||||||
headers: free_cost.clone(),
|
headers: free_cost.clone(),
|
||||||
|
transaction_index: free_cost.clone(),
|
||||||
body: free_cost.clone(),
|
body: free_cost.clone(),
|
||||||
receipts: free_cost.clone(),
|
receipts: free_cost.clone(),
|
||||||
account: free_cost.clone(),
|
account: free_cost.clone(),
|
||||||
@ -278,6 +286,7 @@ impl FlowParams {
|
|||||||
match *request {
|
match *request {
|
||||||
Request::Headers(ref req) => self.costs.headers * req.max.into(),
|
Request::Headers(ref req) => self.costs.headers * req.max.into(),
|
||||||
Request::HeaderProof(_) => self.costs.header_proof,
|
Request::HeaderProof(_) => self.costs.header_proof,
|
||||||
|
Request::TransactionIndex(_) => self.costs.transaction_index,
|
||||||
Request::Body(_) => self.costs.body,
|
Request::Body(_) => self.costs.body,
|
||||||
Request::Receipts(_) => self.costs.receipts,
|
Request::Receipts(_) => self.costs.receipts,
|
||||||
Request::Account(_) => self.costs.account,
|
Request::Account(_) => self.costs.account,
|
||||||
|
@ -132,6 +132,7 @@ fn compute_timeout(reqs: &Requests) -> Duration {
|
|||||||
tm + match *req {
|
tm + match *req {
|
||||||
Request::Headers(_) => timeout::HEADERS,
|
Request::Headers(_) => timeout::HEADERS,
|
||||||
Request::HeaderProof(_) => timeout::HEADER_PROOF,
|
Request::HeaderProof(_) => timeout::HEADER_PROOF,
|
||||||
|
Request::TransactionIndex(_) => timeout::TRANSACTION_INDEX,
|
||||||
Request::Receipts(_) => timeout::RECEIPT,
|
Request::Receipts(_) => timeout::RECEIPT,
|
||||||
Request::Body(_) => timeout::BODY,
|
Request::Body(_) => timeout::BODY,
|
||||||
Request::Account(_) => timeout::PROOF,
|
Request::Account(_) => timeout::PROOF,
|
||||||
|
@ -29,7 +29,10 @@ use futures::sync::oneshot::{self, Sender, Receiver, Canceled};
|
|||||||
use network::PeerId;
|
use network::PeerId;
|
||||||
use util::{RwLock, Mutex};
|
use util::{RwLock, Mutex};
|
||||||
|
|
||||||
use net::{self, Handler, Status, Capabilities, Announcement, EventContext, BasicContext, ReqId};
|
use net::{
|
||||||
|
self, Handler, PeerStatus, Status, Capabilities,
|
||||||
|
Announcement, EventContext, BasicContext, ReqId,
|
||||||
|
};
|
||||||
use cache::Cache;
|
use cache::Cache;
|
||||||
use request::{self as basic_request, Request as NetworkRequest};
|
use request::{self as basic_request, Request as NetworkRequest};
|
||||||
use self::request::CheckedRequest;
|
use self::request::CheckedRequest;
|
||||||
@ -402,9 +405,18 @@ impl OnDemand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Handler for OnDemand {
|
impl Handler for OnDemand {
|
||||||
fn on_connect(&self, ctx: &EventContext, status: &Status, capabilities: &Capabilities) {
|
fn on_connect(
|
||||||
self.peers.write().insert(ctx.peer(), Peer { status: status.clone(), capabilities: capabilities.clone() });
|
&self,
|
||||||
|
ctx: &EventContext,
|
||||||
|
status: &Status,
|
||||||
|
capabilities: &Capabilities
|
||||||
|
) -> PeerStatus {
|
||||||
|
self.peers.write().insert(
|
||||||
|
ctx.peer(),
|
||||||
|
Peer { status: status.clone(), capabilities: capabilities.clone() }
|
||||||
|
);
|
||||||
self.attempt_dispatch(ctx.as_basic());
|
self.attempt_dispatch(ctx.as_basic());
|
||||||
|
PeerStatus::Kept
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_disconnect(&self, ctx: &EventContext, unfulfilled: &[ReqId]) {
|
fn on_disconnect(&self, ctx: &EventContext, unfulfilled: &[ReqId]) {
|
||||||
|
@ -32,6 +32,11 @@ pub use self::header_proof::{
|
|||||||
Incomplete as IncompleteHeaderProofRequest,
|
Incomplete as IncompleteHeaderProofRequest,
|
||||||
Response as HeaderProofResponse
|
Response as HeaderProofResponse
|
||||||
};
|
};
|
||||||
|
pub use self::transaction_index::{
|
||||||
|
Complete as CompleteTransactionIndexRequest,
|
||||||
|
Incomplete as IncompleteTransactionIndexRequest,
|
||||||
|
Response as TransactionIndexResponse
|
||||||
|
};
|
||||||
pub use self::block_body::{
|
pub use self::block_body::{
|
||||||
Complete as CompleteBodyRequest,
|
Complete as CompleteBodyRequest,
|
||||||
Incomplete as IncompleteBodyRequest,
|
Incomplete as IncompleteBodyRequest,
|
||||||
@ -242,7 +247,8 @@ pub enum Request {
|
|||||||
Headers(IncompleteHeadersRequest),
|
Headers(IncompleteHeadersRequest),
|
||||||
/// A request for a header proof (from a CHT)
|
/// A request for a header proof (from a CHT)
|
||||||
HeaderProof(IncompleteHeaderProofRequest),
|
HeaderProof(IncompleteHeaderProofRequest),
|
||||||
// TransactionIndex,
|
/// A request for a transaction index by hash.
|
||||||
|
TransactionIndex(IncompleteTransactionIndexRequest),
|
||||||
/// A request for a block's receipts.
|
/// A request for a block's receipts.
|
||||||
Receipts(IncompleteReceiptsRequest),
|
Receipts(IncompleteReceiptsRequest),
|
||||||
/// A request for a block body.
|
/// A request for a block body.
|
||||||
@ -264,7 +270,8 @@ pub enum CompleteRequest {
|
|||||||
Headers(CompleteHeadersRequest),
|
Headers(CompleteHeadersRequest),
|
||||||
/// A request for a header proof (from a CHT)
|
/// A request for a header proof (from a CHT)
|
||||||
HeaderProof(CompleteHeaderProofRequest),
|
HeaderProof(CompleteHeaderProofRequest),
|
||||||
// TransactionIndex,
|
/// A request for a transaction index by hash.
|
||||||
|
TransactionIndex(CompleteTransactionIndexRequest),
|
||||||
/// A request for a block's receipts.
|
/// A request for a block's receipts.
|
||||||
Receipts(CompleteReceiptsRequest),
|
Receipts(CompleteReceiptsRequest),
|
||||||
/// A request for a block body.
|
/// A request for a block body.
|
||||||
@ -285,6 +292,7 @@ impl CompleteRequest {
|
|||||||
match *self {
|
match *self {
|
||||||
CompleteRequest::Headers(_) => Kind::Headers,
|
CompleteRequest::Headers(_) => Kind::Headers,
|
||||||
CompleteRequest::HeaderProof(_) => Kind::HeaderProof,
|
CompleteRequest::HeaderProof(_) => Kind::HeaderProof,
|
||||||
|
CompleteRequest::TransactionIndex(_) => Kind::TransactionIndex,
|
||||||
CompleteRequest::Receipts(_) => Kind::Receipts,
|
CompleteRequest::Receipts(_) => Kind::Receipts,
|
||||||
CompleteRequest::Body(_) => Kind::Body,
|
CompleteRequest::Body(_) => Kind::Body,
|
||||||
CompleteRequest::Account(_) => Kind::Account,
|
CompleteRequest::Account(_) => Kind::Account,
|
||||||
@ -301,6 +309,7 @@ impl Request {
|
|||||||
match *self {
|
match *self {
|
||||||
Request::Headers(_) => Kind::Headers,
|
Request::Headers(_) => Kind::Headers,
|
||||||
Request::HeaderProof(_) => Kind::HeaderProof,
|
Request::HeaderProof(_) => Kind::HeaderProof,
|
||||||
|
Request::TransactionIndex(_) => Kind::TransactionIndex,
|
||||||
Request::Receipts(_) => Kind::Receipts,
|
Request::Receipts(_) => Kind::Receipts,
|
||||||
Request::Body(_) => Kind::Body,
|
Request::Body(_) => Kind::Body,
|
||||||
Request::Account(_) => Kind::Account,
|
Request::Account(_) => Kind::Account,
|
||||||
@ -316,6 +325,7 @@ impl Decodable for Request {
|
|||||||
match rlp.val_at::<Kind>(0)? {
|
match rlp.val_at::<Kind>(0)? {
|
||||||
Kind::Headers => Ok(Request::Headers(rlp.val_at(1)?)),
|
Kind::Headers => Ok(Request::Headers(rlp.val_at(1)?)),
|
||||||
Kind::HeaderProof => Ok(Request::HeaderProof(rlp.val_at(1)?)),
|
Kind::HeaderProof => Ok(Request::HeaderProof(rlp.val_at(1)?)),
|
||||||
|
Kind::TransactionIndex => Ok(Request::TransactionIndex(rlp.val_at(1)?)),
|
||||||
Kind::Receipts => Ok(Request::Receipts(rlp.val_at(1)?)),
|
Kind::Receipts => Ok(Request::Receipts(rlp.val_at(1)?)),
|
||||||
Kind::Body => Ok(Request::Body(rlp.val_at(1)?)),
|
Kind::Body => Ok(Request::Body(rlp.val_at(1)?)),
|
||||||
Kind::Account => Ok(Request::Account(rlp.val_at(1)?)),
|
Kind::Account => Ok(Request::Account(rlp.val_at(1)?)),
|
||||||
@ -336,6 +346,7 @@ impl Encodable for Request {
|
|||||||
match *self {
|
match *self {
|
||||||
Request::Headers(ref req) => s.append(req),
|
Request::Headers(ref req) => s.append(req),
|
||||||
Request::HeaderProof(ref req) => s.append(req),
|
Request::HeaderProof(ref req) => s.append(req),
|
||||||
|
Request::TransactionIndex(ref req) => s.append(req),
|
||||||
Request::Receipts(ref req) => s.append(req),
|
Request::Receipts(ref req) => s.append(req),
|
||||||
Request::Body(ref req) => s.append(req),
|
Request::Body(ref req) => s.append(req),
|
||||||
Request::Account(ref req) => s.append(req),
|
Request::Account(ref req) => s.append(req),
|
||||||
@ -356,6 +367,7 @@ impl IncompleteRequest for Request {
|
|||||||
match *self {
|
match *self {
|
||||||
Request::Headers(ref req) => req.check_outputs(f),
|
Request::Headers(ref req) => req.check_outputs(f),
|
||||||
Request::HeaderProof(ref req) => req.check_outputs(f),
|
Request::HeaderProof(ref req) => req.check_outputs(f),
|
||||||
|
Request::TransactionIndex(ref req) => req.check_outputs(f),
|
||||||
Request::Receipts(ref req) => req.check_outputs(f),
|
Request::Receipts(ref req) => req.check_outputs(f),
|
||||||
Request::Body(ref req) => req.check_outputs(f),
|
Request::Body(ref req) => req.check_outputs(f),
|
||||||
Request::Account(ref req) => req.check_outputs(f),
|
Request::Account(ref req) => req.check_outputs(f),
|
||||||
@ -369,6 +381,7 @@ impl IncompleteRequest for Request {
|
|||||||
match *self {
|
match *self {
|
||||||
Request::Headers(ref req) => req.note_outputs(f),
|
Request::Headers(ref req) => req.note_outputs(f),
|
||||||
Request::HeaderProof(ref req) => req.note_outputs(f),
|
Request::HeaderProof(ref req) => req.note_outputs(f),
|
||||||
|
Request::TransactionIndex(ref req) => req.note_outputs(f),
|
||||||
Request::Receipts(ref req) => req.note_outputs(f),
|
Request::Receipts(ref req) => req.note_outputs(f),
|
||||||
Request::Body(ref req) => req.note_outputs(f),
|
Request::Body(ref req) => req.note_outputs(f),
|
||||||
Request::Account(ref req) => req.note_outputs(f),
|
Request::Account(ref req) => req.note_outputs(f),
|
||||||
@ -382,6 +395,7 @@ impl IncompleteRequest for Request {
|
|||||||
match *self {
|
match *self {
|
||||||
Request::Headers(ref mut req) => req.fill(oracle),
|
Request::Headers(ref mut req) => req.fill(oracle),
|
||||||
Request::HeaderProof(ref mut req) => req.fill(oracle),
|
Request::HeaderProof(ref mut req) => req.fill(oracle),
|
||||||
|
Request::TransactionIndex(ref mut req) => req.fill(oracle),
|
||||||
Request::Receipts(ref mut req) => req.fill(oracle),
|
Request::Receipts(ref mut req) => req.fill(oracle),
|
||||||
Request::Body(ref mut req) => req.fill(oracle),
|
Request::Body(ref mut req) => req.fill(oracle),
|
||||||
Request::Account(ref mut req) => req.fill(oracle),
|
Request::Account(ref mut req) => req.fill(oracle),
|
||||||
@ -395,6 +409,7 @@ impl IncompleteRequest for Request {
|
|||||||
match self {
|
match self {
|
||||||
Request::Headers(req) => req.complete().map(CompleteRequest::Headers),
|
Request::Headers(req) => req.complete().map(CompleteRequest::Headers),
|
||||||
Request::HeaderProof(req) => req.complete().map(CompleteRequest::HeaderProof),
|
Request::HeaderProof(req) => req.complete().map(CompleteRequest::HeaderProof),
|
||||||
|
Request::TransactionIndex(req) => req.complete().map(CompleteRequest::TransactionIndex),
|
||||||
Request::Receipts(req) => req.complete().map(CompleteRequest::Receipts),
|
Request::Receipts(req) => req.complete().map(CompleteRequest::Receipts),
|
||||||
Request::Body(req) => req.complete().map(CompleteRequest::Body),
|
Request::Body(req) => req.complete().map(CompleteRequest::Body),
|
||||||
Request::Account(req) => req.complete().map(CompleteRequest::Account),
|
Request::Account(req) => req.complete().map(CompleteRequest::Account),
|
||||||
@ -408,6 +423,7 @@ impl IncompleteRequest for Request {
|
|||||||
match *self {
|
match *self {
|
||||||
Request::Headers(ref mut req) => req.adjust_refs(mapping),
|
Request::Headers(ref mut req) => req.adjust_refs(mapping),
|
||||||
Request::HeaderProof(ref mut req) => req.adjust_refs(mapping),
|
Request::HeaderProof(ref mut req) => req.adjust_refs(mapping),
|
||||||
|
Request::TransactionIndex(ref mut req) => req.adjust_refs(mapping),
|
||||||
Request::Receipts(ref mut req) => req.adjust_refs(mapping),
|
Request::Receipts(ref mut req) => req.adjust_refs(mapping),
|
||||||
Request::Body(ref mut req) => req.adjust_refs(mapping),
|
Request::Body(ref mut req) => req.adjust_refs(mapping),
|
||||||
Request::Account(ref mut req) => req.adjust_refs(mapping),
|
Request::Account(ref mut req) => req.adjust_refs(mapping),
|
||||||
@ -441,7 +457,8 @@ pub enum Kind {
|
|||||||
Headers = 0,
|
Headers = 0,
|
||||||
/// A request for a header proof.
|
/// A request for a header proof.
|
||||||
HeaderProof = 1,
|
HeaderProof = 1,
|
||||||
// TransactionIndex = 2,
|
/// A request for a transaction index.
|
||||||
|
TransactionIndex = 2,
|
||||||
/// A request for block receipts.
|
/// A request for block receipts.
|
||||||
Receipts = 3,
|
Receipts = 3,
|
||||||
/// A request for a block body.
|
/// A request for a block body.
|
||||||
@ -461,7 +478,7 @@ impl Decodable for Kind {
|
|||||||
match rlp.as_val::<u8>()? {
|
match rlp.as_val::<u8>()? {
|
||||||
0 => Ok(Kind::Headers),
|
0 => Ok(Kind::Headers),
|
||||||
1 => Ok(Kind::HeaderProof),
|
1 => Ok(Kind::HeaderProof),
|
||||||
// 2 => Ok(Kind::TransactionIndex),
|
2 => Ok(Kind::TransactionIndex),
|
||||||
3 => Ok(Kind::Receipts),
|
3 => Ok(Kind::Receipts),
|
||||||
4 => Ok(Kind::Body),
|
4 => Ok(Kind::Body),
|
||||||
5 => Ok(Kind::Account),
|
5 => Ok(Kind::Account),
|
||||||
@ -486,7 +503,8 @@ pub enum Response {
|
|||||||
Headers(HeadersResponse),
|
Headers(HeadersResponse),
|
||||||
/// A response for a header proof (from a CHT)
|
/// A response for a header proof (from a CHT)
|
||||||
HeaderProof(HeaderProofResponse),
|
HeaderProof(HeaderProofResponse),
|
||||||
// TransactionIndex,
|
/// A response for a transaction index.
|
||||||
|
TransactionIndex(TransactionIndexResponse),
|
||||||
/// A response for a block's receipts.
|
/// A response for a block's receipts.
|
||||||
Receipts(ReceiptsResponse),
|
Receipts(ReceiptsResponse),
|
||||||
/// A response for a block body.
|
/// A response for a block body.
|
||||||
@ -507,6 +525,7 @@ impl ResponseLike for Response {
|
|||||||
match *self {
|
match *self {
|
||||||
Response::Headers(ref res) => res.fill_outputs(f),
|
Response::Headers(ref res) => res.fill_outputs(f),
|
||||||
Response::HeaderProof(ref res) => res.fill_outputs(f),
|
Response::HeaderProof(ref res) => res.fill_outputs(f),
|
||||||
|
Response::TransactionIndex(ref res) => res.fill_outputs(f),
|
||||||
Response::Receipts(ref res) => res.fill_outputs(f),
|
Response::Receipts(ref res) => res.fill_outputs(f),
|
||||||
Response::Body(ref res) => res.fill_outputs(f),
|
Response::Body(ref res) => res.fill_outputs(f),
|
||||||
Response::Account(ref res) => res.fill_outputs(f),
|
Response::Account(ref res) => res.fill_outputs(f),
|
||||||
@ -523,6 +542,7 @@ impl Response {
|
|||||||
match *self {
|
match *self {
|
||||||
Response::Headers(_) => Kind::Headers,
|
Response::Headers(_) => Kind::Headers,
|
||||||
Response::HeaderProof(_) => Kind::HeaderProof,
|
Response::HeaderProof(_) => Kind::HeaderProof,
|
||||||
|
Response::TransactionIndex(_) => Kind::TransactionIndex,
|
||||||
Response::Receipts(_) => Kind::Receipts,
|
Response::Receipts(_) => Kind::Receipts,
|
||||||
Response::Body(_) => Kind::Body,
|
Response::Body(_) => Kind::Body,
|
||||||
Response::Account(_) => Kind::Account,
|
Response::Account(_) => Kind::Account,
|
||||||
@ -538,6 +558,7 @@ impl Decodable for Response {
|
|||||||
match rlp.val_at::<Kind>(0)? {
|
match rlp.val_at::<Kind>(0)? {
|
||||||
Kind::Headers => Ok(Response::Headers(rlp.val_at(1)?)),
|
Kind::Headers => Ok(Response::Headers(rlp.val_at(1)?)),
|
||||||
Kind::HeaderProof => Ok(Response::HeaderProof(rlp.val_at(1)?)),
|
Kind::HeaderProof => Ok(Response::HeaderProof(rlp.val_at(1)?)),
|
||||||
|
Kind::TransactionIndex => Ok(Response::TransactionIndex(rlp.val_at(1)?)),
|
||||||
Kind::Receipts => Ok(Response::Receipts(rlp.val_at(1)?)),
|
Kind::Receipts => Ok(Response::Receipts(rlp.val_at(1)?)),
|
||||||
Kind::Body => Ok(Response::Body(rlp.val_at(1)?)),
|
Kind::Body => Ok(Response::Body(rlp.val_at(1)?)),
|
||||||
Kind::Account => Ok(Response::Account(rlp.val_at(1)?)),
|
Kind::Account => Ok(Response::Account(rlp.val_at(1)?)),
|
||||||
@ -558,6 +579,7 @@ impl Encodable for Response {
|
|||||||
match *self {
|
match *self {
|
||||||
Response::Headers(ref res) => s.append(res),
|
Response::Headers(ref res) => s.append(res),
|
||||||
Response::HeaderProof(ref res) => s.append(res),
|
Response::HeaderProof(ref res) => s.append(res),
|
||||||
|
Response::TransactionIndex(ref res) => s.append(res),
|
||||||
Response::Receipts(ref res) => s.append(res),
|
Response::Receipts(ref res) => s.append(res),
|
||||||
Response::Body(ref res) => s.append(res),
|
Response::Body(ref res) => s.append(res),
|
||||||
Response::Account(ref res) => s.append(res),
|
Response::Account(ref res) => s.append(res),
|
||||||
@ -864,6 +886,117 @@ pub mod header_proof {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request and response for transaction index.
|
||||||
|
pub mod transaction_index {
|
||||||
|
use super::{Field, NoSuchOutput, OutputKind, Output};
|
||||||
|
use rlp::{Encodable, Decodable, DecoderError, RlpStream, UntrustedRlp};
|
||||||
|
use util::H256;
|
||||||
|
|
||||||
|
/// Potentially incomplete transaction index request.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct Incomplete {
|
||||||
|
/// Transaction hash to get index for.
|
||||||
|
pub hash: Field<H256>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Decodable for Incomplete {
|
||||||
|
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
|
||||||
|
Ok(Incomplete {
|
||||||
|
hash: rlp.val_at(0)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Encodable for Incomplete {
|
||||||
|
fn rlp_append(&self, s: &mut RlpStream) {
|
||||||
|
s.begin_list(1).append(&self.hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl super::IncompleteRequest for Incomplete {
|
||||||
|
type Complete = Complete;
|
||||||
|
type Response = Response;
|
||||||
|
|
||||||
|
fn check_outputs<F>(&self, mut f: F) -> Result<(), NoSuchOutput>
|
||||||
|
where F: FnMut(usize, usize, OutputKind) -> Result<(), NoSuchOutput>
|
||||||
|
{
|
||||||
|
match self.hash {
|
||||||
|
Field::Scalar(_) => Ok(()),
|
||||||
|
Field::BackReference(req, idx) => f(req, idx, OutputKind::Hash),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn note_outputs<F>(&self, mut f: F) where F: FnMut(usize, OutputKind) {
|
||||||
|
f(0, OutputKind::Number);
|
||||||
|
f(1, OutputKind::Hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fill<F>(&mut self, oracle: F) where F: Fn(usize, usize) -> Result<Output, NoSuchOutput> {
|
||||||
|
if let Field::BackReference(req, idx) = self.hash {
|
||||||
|
self.hash = match oracle(req, idx) {
|
||||||
|
Ok(Output::Number(hash)) => Field::Scalar(hash.into()),
|
||||||
|
_ => Field::BackReference(req, idx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn complete(self) -> Result<Self::Complete, NoSuchOutput> {
|
||||||
|
Ok(Complete {
|
||||||
|
hash: self.hash.into_scalar()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn adjust_refs<F>(&mut self, mapping: F) where F: FnMut(usize) -> usize {
|
||||||
|
self.hash.adjust_req(mapping)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A complete transaction index request.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct Complete {
|
||||||
|
/// The transaction hash to get index for.
|
||||||
|
pub hash: H256,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The output of a request for transaction index.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct Response {
|
||||||
|
/// Block number.
|
||||||
|
pub num: u64,
|
||||||
|
/// Block hash
|
||||||
|
pub hash: H256,
|
||||||
|
/// Index in block.
|
||||||
|
pub index: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl super::ResponseLike for Response {
|
||||||
|
/// Fill reusable outputs by providing them to the function.
|
||||||
|
fn fill_outputs<F>(&self, mut f: F) where F: FnMut(usize, Output) {
|
||||||
|
f(0, Output::Number(self.num));
|
||||||
|
f(1, Output::Hash(self.hash));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Decodable for Response {
|
||||||
|
fn decode(rlp: &UntrustedRlp) -> Result<Self, DecoderError> {
|
||||||
|
Ok(Response {
|
||||||
|
num: rlp.val_at(0)?,
|
||||||
|
hash: rlp.val_at(1)?,
|
||||||
|
index: rlp.val_at(2)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Encodable for Response {
|
||||||
|
fn rlp_append(&self, s: &mut RlpStream) {
|
||||||
|
s.begin_list(3)
|
||||||
|
.append(&self.num)
|
||||||
|
.append(&self.hash)
|
||||||
|
.append(&self.index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Request and response for block receipts
|
/// Request and response for block receipts
|
||||||
pub mod block_receipts {
|
pub mod block_receipts {
|
||||||
use super::{Field, NoSuchOutput, OutputKind, Output};
|
use super::{Field, NoSuchOutput, OutputKind, Output};
|
||||||
@ -1704,6 +1837,26 @@ mod tests {
|
|||||||
check_roundtrip(full_res);
|
check_roundtrip(full_res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn transaction_index_roundtrip() {
|
||||||
|
let req = IncompleteTransactionIndexRequest {
|
||||||
|
hash: Field::Scalar(Default::default()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let full_req = Request::TransactionIndex(req.clone());
|
||||||
|
let res = TransactionIndexResponse {
|
||||||
|
num: 1000,
|
||||||
|
hash: ::util::H256::random(),
|
||||||
|
index: 4,
|
||||||
|
};
|
||||||
|
let full_res = Response::TransactionIndex(res.clone());
|
||||||
|
|
||||||
|
check_roundtrip(req);
|
||||||
|
check_roundtrip(full_req);
|
||||||
|
check_roundtrip(res);
|
||||||
|
check_roundtrip(full_res);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn receipts_roundtrip() {
|
fn receipts_roundtrip() {
|
||||||
let req = IncompleteReceiptsRequest {
|
let req = IncompleteReceiptsRequest {
|
||||||
|
@ -39,8 +39,9 @@ use std::sync::Arc;
|
|||||||
use ethcore::encoded;
|
use ethcore::encoded;
|
||||||
use light::client::{AsLightClient, LightChainClient};
|
use light::client::{AsLightClient, LightChainClient};
|
||||||
use light::net::{
|
use light::net::{
|
||||||
Announcement, Handler, BasicContext, EventContext,
|
PeerStatus, Announcement, Handler, BasicContext,
|
||||||
Capabilities, ReqId, Status, Error as NetError,
|
EventContext, Capabilities, ReqId, Status,
|
||||||
|
Error as NetError,
|
||||||
};
|
};
|
||||||
use light::request::{self, CompleteHeadersRequest as HeadersRequest};
|
use light::request::{self, CompleteHeadersRequest as HeadersRequest};
|
||||||
use network::PeerId;
|
use network::PeerId;
|
||||||
@ -229,26 +230,33 @@ pub struct LightSync<L: AsLightClient> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<L: AsLightClient + Send + Sync> Handler for LightSync<L> {
|
impl<L: AsLightClient + Send + Sync> Handler for LightSync<L> {
|
||||||
fn on_connect(&self, ctx: &EventContext, status: &Status, capabilities: &Capabilities) {
|
fn on_connect(
|
||||||
if !capabilities.serve_headers {
|
&self,
|
||||||
trace!(target: "sync", "Disconnecting irrelevant peer: {}", ctx.peer());
|
ctx: &EventContext,
|
||||||
ctx.disconnect_peer(ctx.peer());
|
status: &Status,
|
||||||
return;
|
capabilities: &Capabilities
|
||||||
|
) -> PeerStatus {
|
||||||
|
use std::cmp;
|
||||||
|
|
||||||
|
if capabilities.serve_headers {
|
||||||
|
let chain_info = ChainInfo {
|
||||||
|
head_td: status.head_td,
|
||||||
|
head_hash: status.head_hash,
|
||||||
|
head_num: status.head_num,
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut best = self.best_seen.lock();
|
||||||
|
*best = cmp::max(best.clone(), Some(chain_info.clone()));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.peers.write().insert(ctx.peer(), Mutex::new(Peer::new(chain_info)));
|
||||||
|
self.maintain_sync(ctx.as_basic());
|
||||||
|
|
||||||
|
PeerStatus::Kept
|
||||||
|
} else {
|
||||||
|
PeerStatus::Unkept
|
||||||
}
|
}
|
||||||
|
|
||||||
let chain_info = ChainInfo {
|
|
||||||
head_td: status.head_td,
|
|
||||||
head_hash: status.head_hash,
|
|
||||||
head_num: status.head_num,
|
|
||||||
};
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut best = self.best_seen.lock();
|
|
||||||
*best = ::std::cmp::max(best.clone(), Some(chain_info.clone()));
|
|
||||||
}
|
|
||||||
|
|
||||||
self.peers.write().insert(ctx.peer(), Mutex::new(Peer::new(chain_info)));
|
|
||||||
self.maintain_sync(ctx.as_basic());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_disconnect(&self, ctx: &EventContext, unfulfilled: &[ReqId]) {
|
fn on_disconnect(&self, ctx: &EventContext, unfulfilled: &[ReqId]) {
|
||||||
|
Loading…
Reference in New Issue
Block a user