buffer flow -> request credits
This commit is contained in:
parent
f169c8dbb0
commit
ddbdfafc05
@ -44,8 +44,8 @@ pub enum Error {
|
|||||||
Rlp(DecoderError),
|
Rlp(DecoderError),
|
||||||
/// A network error.
|
/// A network error.
|
||||||
Network(NetworkError),
|
Network(NetworkError),
|
||||||
/// Out of buffer.
|
/// Out of credits.
|
||||||
BufferEmpty,
|
NoCredits,
|
||||||
/// Unrecognized packet code.
|
/// Unrecognized packet code.
|
||||||
UnrecognizedPacket(u8),
|
UnrecognizedPacket(u8),
|
||||||
/// Unexpected handshake.
|
/// Unexpected handshake.
|
||||||
@ -72,7 +72,7 @@ impl Error {
|
|||||||
match *self {
|
match *self {
|
||||||
Error::Rlp(_) => Punishment::Disable,
|
Error::Rlp(_) => Punishment::Disable,
|
||||||
Error::Network(_) => Punishment::None,
|
Error::Network(_) => Punishment::None,
|
||||||
Error::BufferEmpty => Punishment::Disable,
|
Error::NoCredits => Punishment::Disable,
|
||||||
Error::UnrecognizedPacket(_) => Punishment::Disconnect,
|
Error::UnrecognizedPacket(_) => Punishment::Disconnect,
|
||||||
Error::UnexpectedHandshake => Punishment::Disconnect,
|
Error::UnexpectedHandshake => Punishment::Disconnect,
|
||||||
Error::WrongNetwork => Punishment::Disable,
|
Error::WrongNetwork => Punishment::Disable,
|
||||||
@ -103,7 +103,7 @@ impl fmt::Display for Error {
|
|||||||
match *self {
|
match *self {
|
||||||
Error::Rlp(ref err) => err.fmt(f),
|
Error::Rlp(ref err) => err.fmt(f),
|
||||||
Error::Network(ref err) => err.fmt(f),
|
Error::Network(ref err) => err.fmt(f),
|
||||||
Error::BufferEmpty => write!(f, "Out of buffer"),
|
Error::NoCredits => write!(f, "Out of request credits"),
|
||||||
Error::UnrecognizedPacket(code) => write!(f, "Unrecognized packet: 0x{:x}", code),
|
Error::UnrecognizedPacket(code) => write!(f, "Unrecognized packet: 0x{:x}", code),
|
||||||
Error::UnexpectedHandshake => write!(f, "Unexpected handshake"),
|
Error::UnexpectedHandshake => write!(f, "Unexpected handshake"),
|
||||||
Error::WrongNetwork => write!(f, "Wrong network"),
|
Error::WrongNetwork => write!(f, "Wrong network"),
|
||||||
|
@ -37,7 +37,7 @@ use std::sync::atomic::{AtomicUsize, Ordering};
|
|||||||
use provider::Provider;
|
use provider::Provider;
|
||||||
use request::{self, HashOrNumber, Request};
|
use request::{self, HashOrNumber, Request};
|
||||||
|
|
||||||
use self::buffer_flow::{Buffer, FlowParams};
|
use self::request_credits::{Credits, FlowParams};
|
||||||
use self::context::{Ctx, TickCtx};
|
use self::context::{Ctx, TickCtx};
|
||||||
use self::error::Punishment;
|
use self::error::Punishment;
|
||||||
use self::request_set::RequestSet;
|
use self::request_set::RequestSet;
|
||||||
@ -51,7 +51,7 @@ mod request_set;
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
pub mod buffer_flow;
|
pub mod request_credits;
|
||||||
|
|
||||||
pub use self::error::Error;
|
pub use self::error::Error;
|
||||||
pub use self::context::{BasicContext, EventContext, IoContext};
|
pub use self::context::{BasicContext, EventContext, IoContext};
|
||||||
@ -143,10 +143,10 @@ struct PendingPeer {
|
|||||||
/// Relevant data to each peer. Not accessible publicly, only `pub` due to
|
/// Relevant data to each peer. Not accessible publicly, only `pub` due to
|
||||||
/// limitations of the privacy system.
|
/// limitations of the privacy system.
|
||||||
pub struct Peer {
|
pub struct Peer {
|
||||||
local_buffer: Buffer, // their buffer relative to us
|
local_credits: Credits, // their credits relative to us
|
||||||
status: Status,
|
status: Status,
|
||||||
capabilities: Capabilities,
|
capabilities: Capabilities,
|
||||||
remote_flow: Option<(Buffer, FlowParams)>,
|
remote_flow: Option<(Credits, FlowParams)>,
|
||||||
sent_head: H256, // last chain head we've given them.
|
sent_head: H256, // last chain head we've given them.
|
||||||
last_update: SteadyTime,
|
last_update: SteadyTime,
|
||||||
pending_requests: RequestSet,
|
pending_requests: RequestSet,
|
||||||
@ -155,21 +155,21 @@ pub struct Peer {
|
|||||||
|
|
||||||
impl Peer {
|
impl Peer {
|
||||||
// check the maximum cost of a request, returning an error if there's
|
// check the maximum cost of a request, returning an error if there's
|
||||||
// not enough buffer left.
|
// not enough credits left.
|
||||||
// returns the calculated maximum cost.
|
// returns the calculated maximum cost.
|
||||||
fn deduct_max(&mut self, flow_params: &FlowParams, kind: request::Kind, max: usize) -> Result<U256, Error> {
|
fn deduct_max(&mut self, flow_params: &FlowParams, kind: request::Kind, max: usize) -> Result<U256, Error> {
|
||||||
flow_params.recharge(&mut self.local_buffer);
|
flow_params.recharge(&mut self.local_credits);
|
||||||
|
|
||||||
let max_cost = flow_params.compute_cost(kind, max);
|
let max_cost = flow_params.compute_cost(kind, max);
|
||||||
self.local_buffer.deduct_cost(max_cost)?;
|
self.local_credits.deduct_cost(max_cost)?;
|
||||||
Ok(max_cost)
|
Ok(max_cost)
|
||||||
}
|
}
|
||||||
|
|
||||||
// refund buffer for a request. returns new buffer amount.
|
// 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_buffer, amount);
|
flow_params.refund(&mut self.local_credits, amount);
|
||||||
|
|
||||||
self.local_buffer.current()
|
self.local_credits.current()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,7 +218,7 @@ pub trait Handler: Send + Sync {
|
|||||||
pub struct Params {
|
pub struct Params {
|
||||||
/// Network id.
|
/// Network id.
|
||||||
pub network_id: u64,
|
pub network_id: u64,
|
||||||
/// Buffer flow parameters.
|
/// Request credits parameters.
|
||||||
pub flow_params: FlowParams,
|
pub flow_params: FlowParams,
|
||||||
/// Initial capabilities.
|
/// Initial capabilities.
|
||||||
pub capabilities: Capabilities,
|
pub capabilities: Capabilities,
|
||||||
@ -324,14 +324,14 @@ impl LightProtocol {
|
|||||||
|
|
||||||
/// Check the maximum amount of requests of a specific type
|
/// Check the maximum amount of requests of a specific type
|
||||||
/// which a peer would be able to serve. Returns zero if the
|
/// which a peer would be able to serve. Returns zero if the
|
||||||
/// peer is unknown or has no buffer flow parameters.
|
/// peer is unknown or has no credit parameters.
|
||||||
fn max_requests(&self, peer: PeerId, kind: request::Kind) -> usize {
|
fn max_requests(&self, peer: PeerId, kind: request::Kind) -> usize {
|
||||||
self.peers.read().get(&peer).and_then(|peer| {
|
self.peers.read().get(&peer).and_then(|peer| {
|
||||||
let mut peer = peer.lock();
|
let mut peer = peer.lock();
|
||||||
match peer.remote_flow {
|
match peer.remote_flow {
|
||||||
Some((ref mut buf, ref flow)) => {
|
Some((ref mut c, ref flow)) => {
|
||||||
flow.recharge(buf);
|
flow.recharge(c);
|
||||||
Some(flow.max_amount(&*buf, kind))
|
Some(flow.max_amount(&*c, kind))
|
||||||
}
|
}
|
||||||
None => None,
|
None => None,
|
||||||
}
|
}
|
||||||
@ -341,7 +341,7 @@ impl LightProtocol {
|
|||||||
/// 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 buffer. 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.
|
||||||
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> {
|
||||||
@ -350,10 +350,10 @@ impl LightProtocol {
|
|||||||
let mut peer = peer.lock();
|
let mut peer = peer.lock();
|
||||||
|
|
||||||
match peer.remote_flow {
|
match peer.remote_flow {
|
||||||
Some((ref mut buf, ref flow)) => {
|
Some((ref mut c, ref flow)) => {
|
||||||
flow.recharge(buf);
|
flow.recharge(c);
|
||||||
let max = flow.compute_cost(request.kind(), request.amount());
|
let max = flow.compute_cost(request.kind(), request.amount());
|
||||||
buf.deduct_cost(max)?;
|
c.deduct_cost(max)?;
|
||||||
}
|
}
|
||||||
None => return Err(Error::NotServer),
|
None => return Err(Error::NotServer),
|
||||||
}
|
}
|
||||||
@ -454,7 +454,7 @@ impl LightProtocol {
|
|||||||
// - check whether request kinds match
|
// - check whether request kinds match
|
||||||
fn pre_verify_response(&self, peer: &PeerId, kind: request::Kind, raw: &UntrustedRlp) -> Result<IdGuard, Error> {
|
fn pre_verify_response(&self, peer: &PeerId, kind: request::Kind, raw: &UntrustedRlp) -> Result<IdGuard, Error> {
|
||||||
let req_id = ReqId(raw.val_at(0)?);
|
let req_id = ReqId(raw.val_at(0)?);
|
||||||
let cur_buffer: 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: "les", "pre-verifying response from peer {}, kind={:?}", peer, kind);
|
||||||
|
|
||||||
@ -470,9 +470,9 @@ impl LightProtocol {
|
|||||||
(Some(request), Some(flow_info)) => {
|
(Some(request), Some(flow_info)) => {
|
||||||
had_req = true;
|
had_req = true;
|
||||||
|
|
||||||
let &mut (ref mut buf, ref mut flow) = flow_info;
|
let &mut (ref mut c, ref mut flow) = flow_info;
|
||||||
let actual_buffer = ::std::cmp::min(cur_buffer, *flow.limit());
|
let actual_credits = ::std::cmp::min(cur_credits, *flow.limit());
|
||||||
buf.update_to(actual_buffer);
|
c.update_to(actual_credits);
|
||||||
|
|
||||||
if request.kind() != kind {
|
if request.kind() != kind {
|
||||||
Some(Error::UnsolicitedResponse)
|
Some(Error::UnsolicitedResponse)
|
||||||
@ -675,10 +675,10 @@ impl LightProtocol {
|
|||||||
return Err(Error::BadProtocolVersion);
|
return Err(Error::BadProtocolVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
let remote_flow = flow_params.map(|params| (params.create_buffer(), params));
|
let remote_flow = flow_params.map(|params| (params.create_credits(), params));
|
||||||
|
|
||||||
self.peers.write().insert(*peer, Mutex::new(Peer {
|
self.peers.write().insert(*peer, Mutex::new(Peer {
|
||||||
local_buffer: self.flow_params.create_buffer(),
|
local_credits: self.flow_params.create_credits(),
|
||||||
status: status.clone(),
|
status: status.clone(),
|
||||||
capabilities: capabilities.clone(),
|
capabilities: capabilities.clone(),
|
||||||
remote_flow: remote_flow,
|
remote_flow: remote_flow,
|
||||||
@ -783,10 +783,10 @@ impl LightProtocol {
|
|||||||
let actual_cost = self.flow_params.compute_cost(request::Kind::Headers, response.len());
|
let actual_cost = self.flow_params.compute_cost(request::Kind::Headers, response.len());
|
||||||
assert!(max_cost >= actual_cost, "Actual cost exceeded maximum computed cost.");
|
assert!(max_cost >= actual_cost, "Actual cost exceeded maximum computed cost.");
|
||||||
|
|
||||||
let cur_buffer = peer.refund(&self.flow_params, max_cost - actual_cost);
|
let cur_credits = peer.refund(&self.flow_params, max_cost - actual_cost);
|
||||||
io.respond(packet::BLOCK_HEADERS, {
|
io.respond(packet::BLOCK_HEADERS, {
|
||||||
let mut stream = RlpStream::new_list(3);
|
let mut stream = RlpStream::new_list(3);
|
||||||
stream.append(&req_id).append(&cur_buffer).begin_list(response.len());
|
stream.append(&req_id).append(&cur_credits).begin_list(response.len());
|
||||||
|
|
||||||
for header in response {
|
for header in response {
|
||||||
stream.append_raw(&header.into_inner(), 1);
|
stream.append_raw(&header.into_inner(), 1);
|
||||||
@ -845,11 +845,11 @@ impl LightProtocol {
|
|||||||
let actual_cost = self.flow_params.compute_cost(request::Kind::Bodies, response_len);
|
let actual_cost = self.flow_params.compute_cost(request::Kind::Bodies, response_len);
|
||||||
assert!(max_cost >= actual_cost, "Actual cost exceeded maximum computed cost.");
|
assert!(max_cost >= actual_cost, "Actual cost exceeded maximum computed cost.");
|
||||||
|
|
||||||
let cur_buffer = peer.refund(&self.flow_params, max_cost - actual_cost);
|
let cur_credits = peer.refund(&self.flow_params, max_cost - actual_cost);
|
||||||
|
|
||||||
io.respond(packet::BLOCK_BODIES, {
|
io.respond(packet::BLOCK_BODIES, {
|
||||||
let mut stream = RlpStream::new_list(3);
|
let mut stream = RlpStream::new_list(3);
|
||||||
stream.append(&req_id).append(&cur_buffer).begin_list(response.len());
|
stream.append(&req_id).append(&cur_credits).begin_list(response.len());
|
||||||
|
|
||||||
for body in response {
|
for body in response {
|
||||||
match body {
|
match body {
|
||||||
@ -911,11 +911,11 @@ impl LightProtocol {
|
|||||||
let actual_cost = self.flow_params.compute_cost(request::Kind::Receipts, response_len);
|
let actual_cost = self.flow_params.compute_cost(request::Kind::Receipts, response_len);
|
||||||
assert!(max_cost >= actual_cost, "Actual cost exceeded maximum computed cost.");
|
assert!(max_cost >= actual_cost, "Actual cost exceeded maximum computed cost.");
|
||||||
|
|
||||||
let cur_buffer = peer.refund(&self.flow_params, max_cost - actual_cost);
|
let cur_credits = peer.refund(&self.flow_params, max_cost - actual_cost);
|
||||||
|
|
||||||
io.respond(packet::RECEIPTS, {
|
io.respond(packet::RECEIPTS, {
|
||||||
let mut stream = RlpStream::new_list(3);
|
let mut stream = RlpStream::new_list(3);
|
||||||
stream.append(&req_id).append(&cur_buffer).begin_list(response.len());
|
stream.append(&req_id).append(&cur_credits).begin_list(response.len());
|
||||||
|
|
||||||
for receipts in response {
|
for receipts in response {
|
||||||
stream.append_raw(&receipts, 1);
|
stream.append_raw(&receipts, 1);
|
||||||
@ -985,11 +985,11 @@ impl LightProtocol {
|
|||||||
let actual_cost = self.flow_params.compute_cost(request::Kind::StateProofs, response_len);
|
let actual_cost = self.flow_params.compute_cost(request::Kind::StateProofs, response_len);
|
||||||
assert!(max_cost >= actual_cost, "Actual cost exceeded maximum computed cost.");
|
assert!(max_cost >= actual_cost, "Actual cost exceeded maximum computed cost.");
|
||||||
|
|
||||||
let cur_buffer = peer.refund(&self.flow_params, max_cost - actual_cost);
|
let cur_credits = peer.refund(&self.flow_params, max_cost - actual_cost);
|
||||||
|
|
||||||
io.respond(packet::PROOFS, {
|
io.respond(packet::PROOFS, {
|
||||||
let mut stream = RlpStream::new_list(3);
|
let mut stream = RlpStream::new_list(3);
|
||||||
stream.append(&req_id).append(&cur_buffer).begin_list(response.len());
|
stream.append(&req_id).append(&cur_credits).begin_list(response.len());
|
||||||
|
|
||||||
for proof in response {
|
for proof in response {
|
||||||
stream.append_raw(&proof, 1);
|
stream.append_raw(&proof, 1);
|
||||||
@ -1057,11 +1057,11 @@ impl LightProtocol {
|
|||||||
let actual_cost = self.flow_params.compute_cost(request::Kind::Codes, response_len);
|
let actual_cost = self.flow_params.compute_cost(request::Kind::Codes, response_len);
|
||||||
assert!(max_cost >= actual_cost, "Actual cost exceeded maximum computed cost.");
|
assert!(max_cost >= actual_cost, "Actual cost exceeded maximum computed cost.");
|
||||||
|
|
||||||
let cur_buffer = peer.refund(&self.flow_params, max_cost - actual_cost);
|
let cur_credits = peer.refund(&self.flow_params, max_cost - actual_cost);
|
||||||
|
|
||||||
io.respond(packet::CONTRACT_CODES, {
|
io.respond(packet::CONTRACT_CODES, {
|
||||||
let mut stream = RlpStream::new_list(3);
|
let mut stream = RlpStream::new_list(3);
|
||||||
stream.append(&req_id).append(&cur_buffer).begin_list(response.len());
|
stream.append(&req_id).append(&cur_credits).begin_list(response.len());
|
||||||
|
|
||||||
for code in response {
|
for code in response {
|
||||||
stream.append(&code);
|
stream.append(&code);
|
||||||
@ -1130,11 +1130,11 @@ impl LightProtocol {
|
|||||||
let actual_cost = self.flow_params.compute_cost(request::Kind::HeaderProofs, response_len);
|
let actual_cost = self.flow_params.compute_cost(request::Kind::HeaderProofs, response_len);
|
||||||
assert!(max_cost >= actual_cost, "Actual cost exceeded maximum computed cost.");
|
assert!(max_cost >= actual_cost, "Actual cost exceeded maximum computed cost.");
|
||||||
|
|
||||||
let cur_buffer = peer.refund(&self.flow_params, max_cost - actual_cost);
|
let cur_credits = peer.refund(&self.flow_params, max_cost - actual_cost);
|
||||||
|
|
||||||
io.respond(packet::HEADER_PROOFS, {
|
io.respond(packet::HEADER_PROOFS, {
|
||||||
let mut stream = RlpStream::new_list(3);
|
let mut stream = RlpStream::new_list(3);
|
||||||
stream.append(&req_id).append(&cur_buffer).begin_list(response.len());
|
stream.append(&req_id).append(&cur_credits).begin_list(response.len());
|
||||||
|
|
||||||
for proof in response {
|
for proof in response {
|
||||||
stream.append_raw(&proof, 1);
|
stream.append_raw(&proof, 1);
|
||||||
|
@ -14,14 +14,14 @@
|
|||||||
// 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 buffer flow management.
|
//! Request credit management.
|
||||||
//!
|
//!
|
||||||
//! Every request in the LES protocol leads to a reduction
|
//! Every request in the light protocol leads to a reduction
|
||||||
//! of the requester's buffer value as a rate-limiting mechanism.
|
//! of the requester's amount of credits as a rate-limiting mechanism.
|
||||||
//! This buffer value will recharge at a set rate.
|
//! The amount of credits will recharge at a set rate.
|
||||||
//!
|
//!
|
||||||
//! This module provides an interface for configuration of buffer
|
//! This module provides an interface for configuration of
|
||||||
//! flow costs and recharge rates.
|
//! costs and recharge rates of request credits.
|
||||||
//!
|
//!
|
||||||
//! 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.
|
||||||
@ -38,19 +38,19 @@ use time::{Duration, SteadyTime};
|
|||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Cost(pub U256, pub U256);
|
pub struct Cost(pub U256, pub U256);
|
||||||
|
|
||||||
/// Buffer value.
|
/// Credits value.
|
||||||
///
|
///
|
||||||
/// Produced and recharged using `FlowParams`.
|
/// Produced and recharged using `FlowParams`.
|
||||||
/// Definitive updates can be made as well -- these will reset the recharge
|
/// Definitive updates can be made as well -- these will reset the recharge
|
||||||
/// point to the time of the update.
|
/// point to the time of the update.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Buffer {
|
pub struct Credits {
|
||||||
estimate: U256,
|
estimate: U256,
|
||||||
recharge_point: SteadyTime,
|
recharge_point: SteadyTime,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Buffer {
|
impl Credits {
|
||||||
/// Get the current buffer value.
|
/// Get the current amount of credits..
|
||||||
pub fn current(&self) -> U256 { self.estimate.clone() }
|
pub fn current(&self) -> U256 { self.estimate.clone() }
|
||||||
|
|
||||||
/// Make a definitive update.
|
/// Make a definitive update.
|
||||||
@ -61,7 +61,7 @@ impl Buffer {
|
|||||||
self.recharge_point = SteadyTime::now();
|
self.recharge_point = SteadyTime::now();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt to apply the given cost to the buffer.
|
/// Attempt to apply the given cost to the amount of credits.
|
||||||
///
|
///
|
||||||
/// If successful, the cost will be deducted successfully.
|
/// If successful, the cost will be deducted successfully.
|
||||||
///
|
///
|
||||||
@ -69,7 +69,7 @@ impl Buffer {
|
|||||||
/// error will be produced.
|
/// error will be produced.
|
||||||
pub fn deduct_cost(&mut self, cost: U256) -> Result<(), Error> {
|
pub fn deduct_cost(&mut self, cost: U256) -> Result<(), Error> {
|
||||||
match cost > self.estimate {
|
match cost > self.estimate {
|
||||||
true => Err(Error::BufferEmpty),
|
true => Err(Error::NoCredits),
|
||||||
false => {
|
false => {
|
||||||
self.estimate = self.estimate - cost;
|
self.estimate = self.estimate - cost;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -165,7 +165,7 @@ impl RlpDecodable for CostTable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A buffer-flow manager handles costs, recharge, limits
|
/// Handles costs, recharge, limits of request credits.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct FlowParams {
|
pub struct FlowParams {
|
||||||
costs: CostTable,
|
costs: CostTable,
|
||||||
@ -175,7 +175,7 @@ pub struct FlowParams {
|
|||||||
|
|
||||||
impl FlowParams {
|
impl FlowParams {
|
||||||
/// Create new flow parameters from a request cost table,
|
/// Create new flow parameters from a request cost table,
|
||||||
/// buffer limit, and (minimum) rate of recharge.
|
/// credit limit, and (minimum) rate of recharge.
|
||||||
pub fn new(limit: U256, costs: CostTable, recharge: U256) -> Self {
|
pub fn new(limit: U256, costs: CostTable, recharge: U256) -> Self {
|
||||||
FlowParams {
|
FlowParams {
|
||||||
costs: costs,
|
costs: costs,
|
||||||
@ -201,7 +201,7 @@ impl FlowParams {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a reference to the buffer limit.
|
/// Get a reference to the credit limit.
|
||||||
pub fn limit(&self) -> &U256 { &self.limit }
|
pub fn limit(&self) -> &U256 { &self.limit }
|
||||||
|
|
||||||
/// Get a reference to the cost table.
|
/// Get a reference to the cost table.
|
||||||
@ -227,10 +227,10 @@ impl FlowParams {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Compute the maximum number of costs of a specific kind which can be made
|
/// Compute the maximum number of costs of a specific kind which can be made
|
||||||
/// with the given buffer.
|
/// with the given amount of credits
|
||||||
/// Saturates at `usize::max()`. This is not a problem in practice because
|
/// Saturates at `usize::max()`. This is not a problem in practice because
|
||||||
/// this amount of requests is already prohibitively large.
|
/// this amount of requests is already prohibitively large.
|
||||||
pub fn max_amount(&self, buffer: &Buffer, kind: request::Kind) -> usize {
|
pub fn max_amount(&self, credits: &Credits, kind: request::Kind) -> usize {
|
||||||
use util::Uint;
|
use util::Uint;
|
||||||
use std::usize;
|
use std::usize;
|
||||||
|
|
||||||
@ -243,7 +243,7 @@ impl FlowParams {
|
|||||||
request::Kind::HeaderProofs => &self.costs.header_proofs,
|
request::Kind::HeaderProofs => &self.costs.header_proofs,
|
||||||
};
|
};
|
||||||
|
|
||||||
let start = buffer.current();
|
let start = credits.current();
|
||||||
|
|
||||||
if start <= cost.0 {
|
if start <= cost.0 {
|
||||||
return 0;
|
return 0;
|
||||||
@ -259,36 +259,36 @@ impl FlowParams {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create initial buffer parameter.
|
/// Create initial credits..
|
||||||
pub fn create_buffer(&self) -> Buffer {
|
pub fn create_credits(&self) -> Credits {
|
||||||
Buffer {
|
Credits {
|
||||||
estimate: self.limit,
|
estimate: self.limit,
|
||||||
recharge_point: SteadyTime::now(),
|
recharge_point: SteadyTime::now(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Recharge the buffer based on time passed since last
|
/// Recharge the given credits based on time passed since last
|
||||||
/// update.
|
/// update.
|
||||||
pub fn recharge(&self, buf: &mut Buffer) {
|
pub fn recharge(&self, credits: &mut Credits) {
|
||||||
let now = SteadyTime::now();
|
let now = SteadyTime::now();
|
||||||
|
|
||||||
// recompute and update only in terms of full seconds elapsed
|
// recompute and update only in terms of full seconds elapsed
|
||||||
// in order to keep the estimate as an underestimate.
|
// in order to keep the estimate as an underestimate.
|
||||||
let elapsed = (now - buf.recharge_point).num_seconds();
|
let elapsed = (now - credits.recharge_point).num_seconds();
|
||||||
buf.recharge_point = buf.recharge_point + Duration::seconds(elapsed);
|
credits.recharge_point = credits.recharge_point + Duration::seconds(elapsed);
|
||||||
|
|
||||||
let elapsed: U256 = elapsed.into();
|
let elapsed: U256 = elapsed.into();
|
||||||
|
|
||||||
buf.estimate = ::std::cmp::min(self.limit, buf.estimate + (elapsed * self.recharge));
|
credits.estimate = ::std::cmp::min(self.limit, credits.estimate + (elapsed * self.recharge));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Refund some buffer which was previously deducted.
|
/// Refund some credits which were previously deducted.
|
||||||
/// Does not update the recharge timestamp.
|
/// Does not update the recharge timestamp.
|
||||||
pub fn refund(&self, buf: &mut Buffer, refund_amount: U256) {
|
pub fn refund(&self, credits: &mut Credits, refund_amount: U256) {
|
||||||
buf.estimate = buf.estimate + refund_amount;
|
credits.estimate = credits.estimate + refund_amount;
|
||||||
|
|
||||||
if buf.estimate > self.limit {
|
if credits.estimate > self.limit {
|
||||||
buf.estimate = self.limit
|
credits.estimate = self.limit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -318,20 +318,20 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn buffer_mechanism() {
|
fn credits_mechanism() {
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
let flow_params = FlowParams::new(100.into(), Default::default(), 20.into());
|
let flow_params = FlowParams::new(100.into(), Default::default(), 20.into());
|
||||||
let mut buffer = flow_params.create_buffer();
|
let mut credits = flow_params.create_credits();
|
||||||
|
|
||||||
assert!(buffer.deduct_cost(101.into()).is_err());
|
assert!(credits.deduct_cost(101.into()).is_err());
|
||||||
assert!(buffer.deduct_cost(10.into()).is_ok());
|
assert!(credits.deduct_cost(10.into()).is_ok());
|
||||||
|
|
||||||
thread::sleep(Duration::from_secs(1));
|
thread::sleep(Duration::from_secs(1));
|
||||||
|
|
||||||
flow_params.recharge(&mut buffer);
|
flow_params.recharge(&mut credits);
|
||||||
|
|
||||||
assert_eq!(buffer.estimate, 100.into());
|
assert_eq!(credits.estimate, 100.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -19,7 +19,7 @@
|
|||||||
use rlp::{DecoderError, RlpDecodable, RlpEncodable, RlpStream, Stream, UntrustedRlp, View};
|
use rlp::{DecoderError, RlpDecodable, RlpEncodable, RlpStream, Stream, UntrustedRlp, View};
|
||||||
use util::{H256, U256};
|
use util::{H256, U256};
|
||||||
|
|
||||||
use super::buffer_flow::FlowParams;
|
use super::request_credits::FlowParams;
|
||||||
|
|
||||||
// recognized handshake/announcement keys.
|
// recognized handshake/announcement keys.
|
||||||
// unknown keys are to be skipped, known keys have a defined order.
|
// unknown keys are to be skipped, known keys have a defined order.
|
||||||
@ -207,7 +207,7 @@ impl Capabilities {
|
|||||||
/// Attempt to parse a handshake message into its three parts:
|
/// Attempt to parse a handshake message into its three parts:
|
||||||
/// - chain status
|
/// - chain status
|
||||||
/// - serving capabilities
|
/// - serving capabilities
|
||||||
/// - buffer flow parameters
|
/// - request credit parameters
|
||||||
pub fn parse_handshake(rlp: UntrustedRlp) -> Result<(Status, Capabilities, Option<FlowParams>), DecoderError> {
|
pub fn parse_handshake(rlp: UntrustedRlp) -> Result<(Status, Capabilities, Option<FlowParams>), DecoderError> {
|
||||||
let mut parser = Parser {
|
let mut parser = Parser {
|
||||||
pos: 0,
|
pos: 0,
|
||||||
@ -300,7 +300,7 @@ pub struct Announcement {
|
|||||||
pub serve_chain_since: Option<u64>,
|
pub serve_chain_since: Option<u64>,
|
||||||
/// optional new transaction-relay capability. false means "no change"
|
/// optional new transaction-relay capability. false means "no change"
|
||||||
pub tx_relay: bool,
|
pub tx_relay: bool,
|
||||||
// TODO: changes in buffer flow?
|
// TODO: changes in request credits.
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse an announcement.
|
/// Parse an announcement.
|
||||||
@ -372,7 +372,7 @@ pub fn write_announcement(announcement: &Announcement) -> Vec<u8> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use super::super::buffer_flow::FlowParams;
|
use super::super::request_credits::FlowParams;
|
||||||
use util::{U256, H256, FixedHash};
|
use util::{U256, H256, FixedHash};
|
||||||
use rlp::{RlpStream, Stream ,UntrustedRlp, View};
|
use rlp::{RlpStream, Stream ,UntrustedRlp, View};
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ use ethcore::transaction::PendingTransaction;
|
|||||||
use ethcore::encoded;
|
use ethcore::encoded;
|
||||||
use network::{PeerId, NodeId};
|
use network::{PeerId, NodeId};
|
||||||
|
|
||||||
use net::buffer_flow::FlowParams;
|
use net::request_credits::FlowParams;
|
||||||
use net::context::IoContext;
|
use net::context::IoContext;
|
||||||
use net::status::{Capabilities, Status, write_handshake};
|
use net::status::{Capabilities, Status, write_handshake};
|
||||||
use net::{encode_request, LightProtocol, Params, packet, Peer};
|
use net::{encode_request, LightProtocol, Params, packet, Peer};
|
||||||
@ -203,7 +203,7 @@ fn genesis_mismatch() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn buffer_overflow() {
|
fn credit_overflow() {
|
||||||
let flow_params = make_flow_params();
|
let flow_params = make_flow_params();
|
||||||
let capabilities = capabilities();
|
let capabilities = capabilities();
|
||||||
|
|
||||||
@ -268,11 +268,11 @@ fn get_block_headers() {
|
|||||||
let headers: Vec<_> = (0..10).map(|i| provider.client.block_header(BlockId::Number(i + 1)).unwrap()).collect();
|
let headers: Vec<_> = (0..10).map(|i| provider.client.block_header(BlockId::Number(i + 1)).unwrap()).collect();
|
||||||
assert_eq!(headers.len(), 10);
|
assert_eq!(headers.len(), 10);
|
||||||
|
|
||||||
let new_buf = *flow_params.limit() - flow_params.compute_cost(request::Kind::Headers, 10);
|
let new_creds = *flow_params.limit() - flow_params.compute_cost(request::Kind::Headers, 10);
|
||||||
|
|
||||||
let mut response_stream = RlpStream::new_list(3);
|
let mut response_stream = RlpStream::new_list(3);
|
||||||
|
|
||||||
response_stream.append(&req_id).append(&new_buf).begin_list(10);
|
response_stream.append(&req_id).append(&new_creds).begin_list(10);
|
||||||
for header in headers {
|
for header in headers {
|
||||||
response_stream.append_raw(&header.into_inner(), 1);
|
response_stream.append_raw(&header.into_inner(), 1);
|
||||||
}
|
}
|
||||||
@ -317,11 +317,11 @@ fn get_block_bodies() {
|
|||||||
let bodies: Vec<_> = (0..10).map(|i| provider.client.block_body(BlockId::Number(i + 1)).unwrap()).collect();
|
let bodies: Vec<_> = (0..10).map(|i| provider.client.block_body(BlockId::Number(i + 1)).unwrap()).collect();
|
||||||
assert_eq!(bodies.len(), 10);
|
assert_eq!(bodies.len(), 10);
|
||||||
|
|
||||||
let new_buf = *flow_params.limit() - flow_params.compute_cost(request::Kind::Bodies, 10);
|
let new_creds = *flow_params.limit() - flow_params.compute_cost(request::Kind::Bodies, 10);
|
||||||
|
|
||||||
let mut response_stream = RlpStream::new_list(3);
|
let mut response_stream = RlpStream::new_list(3);
|
||||||
|
|
||||||
response_stream.append(&req_id).append(&new_buf).begin_list(10);
|
response_stream.append(&req_id).append(&new_creds).begin_list(10);
|
||||||
for body in bodies {
|
for body in bodies {
|
||||||
response_stream.append_raw(&body.into_inner(), 1);
|
response_stream.append_raw(&body.into_inner(), 1);
|
||||||
}
|
}
|
||||||
@ -371,11 +371,11 @@ fn get_block_receipts() {
|
|||||||
.map(|hash| provider.client.block_receipts(hash).unwrap())
|
.map(|hash| provider.client.block_receipts(hash).unwrap())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let new_buf = *flow_params.limit() - flow_params.compute_cost(request::Kind::Receipts, receipts.len());
|
let new_creds = *flow_params.limit() - flow_params.compute_cost(request::Kind::Receipts, receipts.len());
|
||||||
|
|
||||||
let mut response_stream = RlpStream::new_list(3);
|
let mut response_stream = RlpStream::new_list(3);
|
||||||
|
|
||||||
response_stream.append(&req_id).append(&new_buf).begin_list(receipts.len());
|
response_stream.append(&req_id).append(&new_creds).begin_list(receipts.len());
|
||||||
for block_receipts in receipts {
|
for block_receipts in receipts {
|
||||||
response_stream.append_raw(&block_receipts, 1);
|
response_stream.append_raw(&block_receipts, 1);
|
||||||
}
|
}
|
||||||
@ -420,11 +420,11 @@ fn get_state_proofs() {
|
|||||||
vec![::util::sha3::SHA3_NULL_RLP.to_vec()],
|
vec![::util::sha3::SHA3_NULL_RLP.to_vec()],
|
||||||
];
|
];
|
||||||
|
|
||||||
let new_buf = *flow_params.limit() - flow_params.compute_cost(request::Kind::StateProofs, 2);
|
let new_creds = *flow_params.limit() - flow_params.compute_cost(request::Kind::StateProofs, 2);
|
||||||
|
|
||||||
let mut response_stream = RlpStream::new_list(3);
|
let mut response_stream = RlpStream::new_list(3);
|
||||||
|
|
||||||
response_stream.append(&req_id).append(&new_buf).begin_list(2);
|
response_stream.append(&req_id).append(&new_creds).begin_list(2);
|
||||||
for proof in proofs {
|
for proof in proofs {
|
||||||
response_stream.begin_list(proof.len());
|
response_stream.begin_list(proof.len());
|
||||||
for node in proof {
|
for node in proof {
|
||||||
@ -472,11 +472,11 @@ fn get_contract_code() {
|
|||||||
key2.iter().chain(key2.iter()).cloned().collect(),
|
key2.iter().chain(key2.iter()).cloned().collect(),
|
||||||
];
|
];
|
||||||
|
|
||||||
let new_buf = *flow_params.limit() - flow_params.compute_cost(request::Kind::Codes, 2);
|
let new_creds = *flow_params.limit() - flow_params.compute_cost(request::Kind::Codes, 2);
|
||||||
|
|
||||||
let mut response_stream = RlpStream::new_list(3);
|
let mut response_stream = RlpStream::new_list(3);
|
||||||
|
|
||||||
response_stream.append(&req_id).append(&new_buf).begin_list(2);
|
response_stream.append(&req_id).append(&new_creds).begin_list(2);
|
||||||
for code in codes {
|
for code in codes {
|
||||||
response_stream.append(&code);
|
response_stream.append(&code);
|
||||||
}
|
}
|
||||||
@ -515,10 +515,10 @@ fn id_guard() {
|
|||||||
pending_requests.insert(req_id_2, req, ::time::SteadyTime::now());
|
pending_requests.insert(req_id_2, req, ::time::SteadyTime::now());
|
||||||
|
|
||||||
proto.peers.write().insert(peer_id, ::util::Mutex::new(Peer {
|
proto.peers.write().insert(peer_id, ::util::Mutex::new(Peer {
|
||||||
local_buffer: flow_params.create_buffer(),
|
local_credits: flow_params.create_credits(),
|
||||||
status: status(provider.client.chain_info()),
|
status: status(provider.client.chain_info()),
|
||||||
capabilities: capabilities.clone(),
|
capabilities: capabilities.clone(),
|
||||||
remote_flow: Some((flow_params.create_buffer(), flow_params)),
|
remote_flow: Some((flow_params.create_credits(), flow_params)),
|
||||||
sent_head: provider.client.chain_info().best_block_hash,
|
sent_head: provider.client.chain_info().best_block_hash,
|
||||||
last_update: ::time::SteadyTime::now(),
|
last_update: ::time::SteadyTime::now(),
|
||||||
pending_requests: pending_requests,
|
pending_requests: pending_requests,
|
||||||
|
@ -27,7 +27,7 @@ use ethcore::spec::Spec;
|
|||||||
use io::IoChannel;
|
use io::IoChannel;
|
||||||
use light::client::Client as LightClient;
|
use light::client::Client as LightClient;
|
||||||
use light::net::{LightProtocol, IoContext, Capabilities, Params as LightParams};
|
use light::net::{LightProtocol, IoContext, Capabilities, Params as LightParams};
|
||||||
use light::net::buffer_flow::FlowParams;
|
use light::net::request_credits::FlowParams;
|
||||||
use network::{NodeId, PeerId};
|
use network::{NodeId, PeerId};
|
||||||
use util::RwLock;
|
use util::RwLock;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user