Merge branch 'master' into ui-2
This commit is contained in:
		
						commit
						c33ff96bb6
					
				| @ -66,6 +66,8 @@ pub enum Error { | ||||
| 	BadProtocolVersion, | ||||
| 	/// Peer is overburdened.
 | ||||
| 	Overburdened, | ||||
| 	/// No handler kept the peer.
 | ||||
| 	RejectedByHandlers, | ||||
| } | ||||
| 
 | ||||
| impl Error { | ||||
| @ -85,6 +87,7 @@ impl Error { | ||||
| 			Error::UnsupportedProtocolVersion(_) => Punishment::Disable, | ||||
| 			Error::BadProtocolVersion => Punishment::Disable, | ||||
| 			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::BadProtocolVersion => write!(f, "Bad protocol version in handshake"), | ||||
| 			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 { | ||||
| 		Kind::Headers => 500_000, | ||||
| 		Kind::HeaderProof => 500_000, | ||||
| 		Kind::TransactionIndex => 500_000, | ||||
| 		Kind::Receipts => 1_000_000, | ||||
| 		Kind::Body => 1_000_000, | ||||
| 		Kind::Account => 1_500_000, | ||||
|  | ||||
| @ -31,6 +31,7 @@ use std::collections::{HashMap, HashSet}; | ||||
| use std::fmt; | ||||
| use std::sync::Arc; | ||||
| use std::sync::atomic::{AtomicUsize, Ordering}; | ||||
| use std::ops::{BitOr, BitAnd, Not}; | ||||
| 
 | ||||
| use provider::Provider; | ||||
| 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; | ||||
| 
 | ||||
| /// Packet count for PIP.
 | ||||
| pub const PACKET_COUNT: u8 = 5; | ||||
| pub const PACKET_COUNT: u8 = 9; | ||||
| 
 | ||||
| // packet ID definitions.
 | ||||
| mod packet { | ||||
| @ -100,6 +101,10 @@ mod packet { | ||||
| 
 | ||||
| 	// relay transactions to peers.
 | ||||
| 	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.
 | ||||
| @ -110,6 +115,7 @@ mod timeout { | ||||
| 
 | ||||
| 	// timeouts per request within packet.
 | ||||
| 	pub const HEADERS: i64 = 250; // per header?
 | ||||
| 	pub const TRANSACTION_INDEX: i64 = 100; | ||||
| 	pub const BODY: i64 = 50; | ||||
| 	pub const RECEIPT: i64 = 50; | ||||
| 	pub const PROOF: i64 = 100; // state proof
 | ||||
| @ -157,6 +163,54 @@ pub struct Peer { | ||||
| 	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.
 | ||||
| ///
 | ||||
| /// 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.
 | ||||
| pub trait Handler: Send + Sync { | ||||
| 	/// 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
 | ||||
| 	/// of yet.
 | ||||
| 	fn on_disconnect(&self, _ctx: &EventContext, _unfulfilled: &[ReqId]) { } | ||||
| @ -523,6 +582,12 @@ impl LightProtocol { | ||||
| 
 | ||||
| 			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 => { | ||||
| 				Err(Error::UnrecognizedPacket(other)) | ||||
| 			} | ||||
| @ -766,15 +831,23 @@ impl LightProtocol { | ||||
| 			awaiting_acknowledge: None, | ||||
| 		})); | ||||
| 
 | ||||
| 		for handler in &self.handlers { | ||||
| 			handler.on_connect(&Ctx { | ||||
| 				peer: *peer, | ||||
| 				io: io, | ||||
| 				proto: self, | ||||
| 			}, &status, &capabilities) | ||||
| 		} | ||||
| 		let any_kept = self.handlers.iter().map( | ||||
| 			|handler| handler.on_connect( | ||||
| 				&Ctx { | ||||
| 					peer: *peer, | ||||
| 					io: io, | ||||
| 					proto: self, | ||||
| 				}, | ||||
| 				&status, | ||||
| 				&capabilities | ||||
| 			) | ||||
| 		).fold(PeerStatus::Kept, PeerStatus::bitor); | ||||
| 
 | ||||
| 		Ok(()) | ||||
| 		if any_kept == PeerStatus::Unkept { | ||||
| 			Err(Error::RejectedByHandlers) | ||||
| 		} else { | ||||
| 			Ok(()) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Handle an announcement.
 | ||||
| @ -867,6 +940,7 @@ impl LightProtocol { | ||||
| 			match complete_req { | ||||
| 				CompleteRequest::Headers(req) => self.provider.block_headers(req).map(Response::Headers), | ||||
| 				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::Receipts(req) => self.provider.block_receipts(req).map(Response::Receipts), | ||||
| 				CompleteRequest::Account(req) => self.provider.account_proof(req).map(Response::Account), | ||||
|  | ||||
| @ -83,6 +83,7 @@ impl Credits { | ||||
| pub struct CostTable { | ||||
| 	base: U256, // cost per packet.
 | ||||
| 	headers: U256, // cost per header
 | ||||
| 	transaction_index: U256, | ||||
| 	body: U256, | ||||
| 	receipts: U256, | ||||
| 	account: U256, | ||||
| @ -98,6 +99,7 @@ impl Default for CostTable { | ||||
| 		CostTable { | ||||
| 			base: 100000.into(), | ||||
| 			headers: 10000.into(), | ||||
| 			transaction_index: 10000.into(), | ||||
| 			body: 15000.into(), | ||||
| 			receipts: 5000.into(), | ||||
| 			account: 25000.into(), | ||||
| @ -119,8 +121,9 @@ impl Encodable for CostTable { | ||||
| 			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.transaction_index, request::Kind::TransactionIndex); | ||||
| 		append_cost(s, &self.body, request::Kind::Body); | ||||
| 		append_cost(s, &self.receipts, request::Kind::Receipts); | ||||
| 		append_cost(s, &self.account, request::Kind::Account); | ||||
| @ -136,6 +139,7 @@ impl Decodable for CostTable { | ||||
| 		let base = rlp.val_at(0)?; | ||||
| 
 | ||||
| 		let mut headers = None; | ||||
| 		let mut transaction_index = None; | ||||
| 		let mut body = None; | ||||
| 		let mut receipts = None; | ||||
| 		let mut account = None; | ||||
| @ -148,6 +152,7 @@ impl Decodable for CostTable { | ||||
| 			let cost = cost_list.val_at(1)?; | ||||
| 			match cost_list.val_at(0)? { | ||||
| 				request::Kind::Headers => headers = Some(cost), | ||||
| 				request::Kind::TransactionIndex => transaction_index = Some(cost), | ||||
| 				request::Kind::Body => body = Some(cost), | ||||
| 				request::Kind::Receipts => receipts = Some(cost), | ||||
| 				request::Kind::Account => account = Some(cost), | ||||
| @ -163,6 +168,7 @@ impl Decodable for CostTable { | ||||
| 		Ok(CostTable { | ||||
| 			base: base, | ||||
| 			headers: unwrap_cost(headers)?, | ||||
| 			transaction_index: unwrap_cost(transaction_index)?, | ||||
| 			body: unwrap_cost(body)?, | ||||
| 			receipts: unwrap_cost(receipts)?, | ||||
| 			account: unwrap_cost(account)?, | ||||
| @ -224,6 +230,7 @@ impl FlowParams { | ||||
| 		let costs = CostTable { | ||||
| 			base: 0.into(), | ||||
| 			headers: cost_for_kind(Kind::Headers), | ||||
| 			transaction_index: cost_for_kind(Kind::TransactionIndex), | ||||
| 			body: cost_for_kind(Kind::Body), | ||||
| 			receipts: cost_for_kind(Kind::Receipts), | ||||
| 			account: cost_for_kind(Kind::Account), | ||||
| @ -249,6 +256,7 @@ impl FlowParams { | ||||
| 			costs: CostTable { | ||||
| 				base: free_cost.clone(), | ||||
| 				headers: free_cost.clone(), | ||||
| 				transaction_index: free_cost.clone(), | ||||
| 				body: free_cost.clone(), | ||||
| 				receipts: free_cost.clone(), | ||||
| 				account: free_cost.clone(), | ||||
| @ -278,6 +286,7 @@ impl FlowParams { | ||||
| 		match *request { | ||||
| 			Request::Headers(ref req) => self.costs.headers * req.max.into(), | ||||
| 			Request::HeaderProof(_) => self.costs.header_proof, | ||||
| 			Request::TransactionIndex(_) => self.costs.transaction_index, | ||||
| 			Request::Body(_) => self.costs.body, | ||||
| 			Request::Receipts(_) => self.costs.receipts, | ||||
| 			Request::Account(_) => self.costs.account, | ||||
|  | ||||
| @ -132,6 +132,7 @@ fn compute_timeout(reqs: &Requests) -> Duration { | ||||
| 		tm + match *req { | ||||
| 			Request::Headers(_) => timeout::HEADERS, | ||||
| 			Request::HeaderProof(_) => timeout::HEADER_PROOF, | ||||
| 			Request::TransactionIndex(_) => timeout::TRANSACTION_INDEX, | ||||
| 			Request::Receipts(_) => timeout::RECEIPT, | ||||
| 			Request::Body(_) => timeout::BODY, | ||||
| 			Request::Account(_) => timeout::PROOF, | ||||
|  | ||||
| @ -29,7 +29,10 @@ use futures::sync::oneshot::{self, Sender, Receiver, Canceled}; | ||||
| use network::PeerId; | ||||
| 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 request::{self as basic_request, Request as NetworkRequest}; | ||||
| use self::request::CheckedRequest; | ||||
| @ -402,9 +405,18 @@ impl OnDemand { | ||||
| } | ||||
| 
 | ||||
| impl Handler for OnDemand { | ||||
| 	fn on_connect(&self, ctx: &EventContext, status: &Status, capabilities: &Capabilities) { | ||||
| 		self.peers.write().insert(ctx.peer(), Peer { status: status.clone(), capabilities: capabilities.clone() }); | ||||
| 	fn on_connect( | ||||
| 		&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()); | ||||
| 		PeerStatus::Kept | ||||
| 	} | ||||
| 
 | ||||
| 	fn on_disconnect(&self, ctx: &EventContext, unfulfilled: &[ReqId]) { | ||||
|  | ||||
| @ -32,6 +32,11 @@ pub use self::header_proof::{ | ||||
| 	Incomplete as IncompleteHeaderProofRequest, | ||||
| 	Response as HeaderProofResponse | ||||
| }; | ||||
| pub use self::transaction_index::{ | ||||
| 	Complete as CompleteTransactionIndexRequest, | ||||
| 	Incomplete as IncompleteTransactionIndexRequest, | ||||
| 	Response as TransactionIndexResponse | ||||
| }; | ||||
| pub use self::block_body::{ | ||||
| 	Complete as CompleteBodyRequest, | ||||
| 	Incomplete as IncompleteBodyRequest, | ||||
| @ -242,7 +247,8 @@ pub enum Request { | ||||
| 	Headers(IncompleteHeadersRequest), | ||||
| 	/// A request for a header proof (from a CHT)
 | ||||
| 	HeaderProof(IncompleteHeaderProofRequest), | ||||
| 	// TransactionIndex,
 | ||||
| 	/// A request for a transaction index by hash.
 | ||||
| 	TransactionIndex(IncompleteTransactionIndexRequest), | ||||
| 	/// A request for a block's receipts.
 | ||||
| 	Receipts(IncompleteReceiptsRequest), | ||||
| 	/// A request for a block body.
 | ||||
| @ -264,7 +270,8 @@ pub enum CompleteRequest { | ||||
| 	Headers(CompleteHeadersRequest), | ||||
| 	/// A request for a header proof (from a CHT)
 | ||||
| 	HeaderProof(CompleteHeaderProofRequest), | ||||
| 	// TransactionIndex,
 | ||||
| 	/// A request for a transaction index by hash.
 | ||||
| 	TransactionIndex(CompleteTransactionIndexRequest), | ||||
| 	/// A request for a block's receipts.
 | ||||
| 	Receipts(CompleteReceiptsRequest), | ||||
| 	/// A request for a block body.
 | ||||
| @ -285,6 +292,7 @@ impl CompleteRequest { | ||||
| 		match *self { | ||||
| 			CompleteRequest::Headers(_) => Kind::Headers, | ||||
| 			CompleteRequest::HeaderProof(_) => Kind::HeaderProof, | ||||
| 			CompleteRequest::TransactionIndex(_) => Kind::TransactionIndex, | ||||
| 			CompleteRequest::Receipts(_) => Kind::Receipts, | ||||
| 			CompleteRequest::Body(_) => Kind::Body, | ||||
| 			CompleteRequest::Account(_) => Kind::Account, | ||||
| @ -301,6 +309,7 @@ impl Request { | ||||
| 		match *self { | ||||
| 			Request::Headers(_) => Kind::Headers, | ||||
| 			Request::HeaderProof(_) => Kind::HeaderProof, | ||||
| 			Request::TransactionIndex(_) => Kind::TransactionIndex, | ||||
| 			Request::Receipts(_) => Kind::Receipts, | ||||
| 			Request::Body(_) => Kind::Body, | ||||
| 			Request::Account(_) => Kind::Account, | ||||
| @ -316,6 +325,7 @@ impl Decodable for Request { | ||||
| 		match rlp.val_at::<Kind>(0)? { | ||||
| 			Kind::Headers => Ok(Request::Headers(rlp.val_at(1)?)), | ||||
| 			Kind::HeaderProof => Ok(Request::HeaderProof(rlp.val_at(1)?)), | ||||
| 			Kind::TransactionIndex => Ok(Request::TransactionIndex(rlp.val_at(1)?)), | ||||
| 			Kind::Receipts => Ok(Request::Receipts(rlp.val_at(1)?)), | ||||
| 			Kind::Body => Ok(Request::Body(rlp.val_at(1)?)), | ||||
| 			Kind::Account => Ok(Request::Account(rlp.val_at(1)?)), | ||||
| @ -336,6 +346,7 @@ impl Encodable for Request { | ||||
| 		match *self { | ||||
| 			Request::Headers(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::Body(ref req) => s.append(req), | ||||
| 			Request::Account(ref req) => s.append(req), | ||||
| @ -356,6 +367,7 @@ impl IncompleteRequest for Request { | ||||
| 		match *self { | ||||
| 			Request::Headers(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::Body(ref req) => req.check_outputs(f), | ||||
| 			Request::Account(ref req) => req.check_outputs(f), | ||||
| @ -369,6 +381,7 @@ impl IncompleteRequest for Request { | ||||
| 		match *self { | ||||
| 			Request::Headers(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::Body(ref req) => req.note_outputs(f), | ||||
| 			Request::Account(ref req) => req.note_outputs(f), | ||||
| @ -382,6 +395,7 @@ impl IncompleteRequest for Request { | ||||
| 		match *self { | ||||
| 			Request::Headers(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::Body(ref mut req) => req.fill(oracle), | ||||
| 			Request::Account(ref mut req) => req.fill(oracle), | ||||
| @ -395,6 +409,7 @@ impl IncompleteRequest for Request { | ||||
| 		match self { | ||||
| 			Request::Headers(req) => req.complete().map(CompleteRequest::Headers), | ||||
| 			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::Body(req) => req.complete().map(CompleteRequest::Body), | ||||
| 			Request::Account(req) => req.complete().map(CompleteRequest::Account), | ||||
| @ -408,6 +423,7 @@ impl IncompleteRequest for Request { | ||||
| 		match *self { | ||||
| 			Request::Headers(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::Body(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, | ||||
| 	/// A request for a header proof.
 | ||||
| 	HeaderProof = 1, | ||||
| 	// TransactionIndex = 2,
 | ||||
| 	/// A request for a transaction index.
 | ||||
| 	TransactionIndex = 2, | ||||
| 	/// A request for block receipts.
 | ||||
| 	Receipts = 3, | ||||
| 	/// A request for a block body.
 | ||||
| @ -461,7 +478,7 @@ impl Decodable for Kind { | ||||
| 		match rlp.as_val::<u8>()? { | ||||
| 			0 => Ok(Kind::Headers), | ||||
| 			1 => Ok(Kind::HeaderProof), | ||||
| 			// 2 => Ok(Kind::TransactionIndex),
 | ||||
| 			2 => Ok(Kind::TransactionIndex), | ||||
| 			3 => Ok(Kind::Receipts), | ||||
| 			4 => Ok(Kind::Body), | ||||
| 			5 => Ok(Kind::Account), | ||||
| @ -486,7 +503,8 @@ pub enum Response { | ||||
| 	Headers(HeadersResponse), | ||||
| 	/// A response for a header proof (from a CHT)
 | ||||
| 	HeaderProof(HeaderProofResponse), | ||||
| 	// TransactionIndex,
 | ||||
| 	/// A response for a transaction index.
 | ||||
| 	TransactionIndex(TransactionIndexResponse), | ||||
| 	/// A response for a block's receipts.
 | ||||
| 	Receipts(ReceiptsResponse), | ||||
| 	/// A response for a block body.
 | ||||
| @ -507,6 +525,7 @@ impl ResponseLike for Response { | ||||
| 		match *self { | ||||
| 			Response::Headers(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::Body(ref res) => res.fill_outputs(f), | ||||
| 			Response::Account(ref res) => res.fill_outputs(f), | ||||
| @ -523,6 +542,7 @@ impl Response { | ||||
| 		match *self { | ||||
| 			Response::Headers(_) => Kind::Headers, | ||||
| 			Response::HeaderProof(_) => Kind::HeaderProof, | ||||
| 			Response::TransactionIndex(_) => Kind::TransactionIndex, | ||||
| 			Response::Receipts(_) => Kind::Receipts, | ||||
| 			Response::Body(_) => Kind::Body, | ||||
| 			Response::Account(_) => Kind::Account, | ||||
| @ -538,6 +558,7 @@ impl Decodable for Response { | ||||
| 		match rlp.val_at::<Kind>(0)? { | ||||
| 			Kind::Headers => Ok(Response::Headers(rlp.val_at(1)?)), | ||||
| 			Kind::HeaderProof => Ok(Response::HeaderProof(rlp.val_at(1)?)), | ||||
| 			Kind::TransactionIndex => Ok(Response::TransactionIndex(rlp.val_at(1)?)), | ||||
| 			Kind::Receipts => Ok(Response::Receipts(rlp.val_at(1)?)), | ||||
| 			Kind::Body => Ok(Response::Body(rlp.val_at(1)?)), | ||||
| 			Kind::Account => Ok(Response::Account(rlp.val_at(1)?)), | ||||
| @ -558,6 +579,7 @@ impl Encodable for Response { | ||||
| 		match *self { | ||||
| 			Response::Headers(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::Body(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
 | ||||
| pub mod block_receipts { | ||||
| 	use super::{Field, NoSuchOutput, OutputKind, Output}; | ||||
| @ -1704,6 +1837,26 @@ mod tests { | ||||
| 		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] | ||||
| 	fn receipts_roundtrip() { | ||||
| 		let req = IncompleteReceiptsRequest { | ||||
|  | ||||
| @ -39,8 +39,9 @@ use std::sync::Arc; | ||||
| use ethcore::encoded; | ||||
| use light::client::{AsLightClient, LightChainClient}; | ||||
| use light::net::{ | ||||
| 	Announcement, Handler, BasicContext, EventContext, | ||||
| 	Capabilities, ReqId, Status, Error as NetError, | ||||
| 	PeerStatus, Announcement, Handler, BasicContext, | ||||
| 	EventContext, Capabilities, ReqId, Status, | ||||
| 	Error as NetError, | ||||
| }; | ||||
| use light::request::{self, CompleteHeadersRequest as HeadersRequest}; | ||||
| use network::PeerId; | ||||
| @ -229,26 +230,33 @@ pub struct LightSync<L: AsLightClient> { | ||||
| } | ||||
| 
 | ||||
| impl<L: AsLightClient + Send + Sync> Handler for LightSync<L> { | ||||
| 	fn on_connect(&self, ctx: &EventContext, status: &Status, capabilities: &Capabilities) { | ||||
| 		if !capabilities.serve_headers { | ||||
| 			trace!(target: "sync", "Disconnecting irrelevant peer: {}", ctx.peer()); | ||||
| 			ctx.disconnect_peer(ctx.peer()); | ||||
| 			return; | ||||
| 	fn on_connect( | ||||
| 		&self, | ||||
| 		ctx: &EventContext, | ||||
| 		status: &Status, | ||||
| 		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]) { | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user