light: integrate with sync + serve_light CLI

This commit is contained in:
Robert Habermeier
2016-12-08 23:21:47 +01:00
parent efd66f566d
commit 6f5f1f5e26
20 changed files with 236 additions and 74 deletions

View File

@@ -33,8 +33,21 @@
pub mod client;
pub mod net;
#[cfg(not(feature = "ipc"))]
pub mod provider;
#[cfg(feature = "ipc")]
pub mod provider {
#![allow(dead_code, unused_assignments, unused_variables, missing_docs)] // codegen issues
include!(concat!(env!("OUT_DIR"), "/provider.rs"));
}
#[cfg(feature = "ipc")]
pub mod remote {
pub use provider::LightProviderClient;
}
mod types;
pub use self::provider::Provider;

View File

@@ -22,6 +22,9 @@
//!
//! This module provides an interface for configuration of buffer
//! flow costs and recharge rates.
//!
//! Current default costs are picked completely arbitrarily, not based
//! on any empirical timings or mathematical models.
use request;
use super::packet;
@@ -273,6 +276,16 @@ impl FlowParams {
}
}
impl Default for FlowParams {
fn default() -> Self {
FlowParams {
limit: 50_000_000.into(),
costs: CostTable::default(),
recharge: 100_000.into(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;

View File

@@ -30,13 +30,14 @@ use util::{Bytes, Mutex, RwLock, U256};
use time::SteadyTime;
use std::collections::HashMap;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use provider::Provider;
use request::{self, Request};
use self::buffer_flow::{Buffer, FlowParams};
use self::context::{IoContext, EventContext, Ctx};
use self::context::Ctx;
use self::error::{Error, Punishment};
mod buffer_flow;
@@ -47,16 +48,20 @@ mod status;
#[cfg(test)]
mod tests;
pub use self::status::{Status, Capabilities, Announcement, NetworkId};
pub use self::context::{EventContext, IoContext};
pub use self::status::{Status, Capabilities, Announcement};
const TIMEOUT: TimerToken = 0;
const TIMEOUT_INTERVAL_MS: u64 = 1000;
// LPV1
const PROTOCOL_VERSION: u32 = 1;
// Supported protocol versions.
pub const PROTOCOL_VERSIONS: &'static [u8] = &[1];
// TODO [rob] make configurable.
const PROTOCOL_ID: [u8; 3] = *b"les";
// Max protocol version.
pub const MAX_PROTOCOL_VERSION: u8 = 1;
// Packet count for LES.
pub const PACKET_COUNT: u8 = 15;
// packet ID definitions.
mod packet {
@@ -173,6 +178,8 @@ pub trait Handler: Send + Sync {
/// Called when a peer responds with header proofs. Each proof is a block header coupled
/// with a series of trie nodes is ascending order by distance from the root.
fn on_header_proofs(&self, _ctx: &EventContext, _req_id: ReqId, _proofs: &[(Bytes, Vec<Bytes>)]) { }
/// Called on abort.
fn on_abort(&self) { }
}
// a request, the peer who it was made to, and the time it was made.
@@ -185,7 +192,7 @@ struct Requested {
/// Protocol parameters.
pub struct Params {
/// Network id.
pub network_id: NetworkId,
pub network_id: u64,
/// Buffer flow parameters.
pub flow_params: FlowParams,
/// Initial capabilities.
@@ -203,9 +210,9 @@ pub struct Params {
// Locks must be acquired in the order declared, and when holding a read lock
// on the peers, only one peer may be held at a time.
pub struct LightProtocol {
provider: Box<Provider>,
provider: Arc<Provider>,
genesis_hash: H256,
network_id: NetworkId,
network_id: u64,
pending_peers: RwLock<HashMap<PeerId, PendingPeer>>,
peers: RwLock<HashMap<PeerId, Mutex<Peer>>>,
pending_requests: RwLock<HashMap<usize, Requested>>,
@@ -217,7 +224,7 @@ pub struct LightProtocol {
impl LightProtocol {
/// Create a new instance of the protocol manager.
pub fn new(provider: Box<Provider>, params: Params) -> Self {
pub fn new(provider: Arc<Provider>, params: Params) -> Self {
let genesis_hash = provider.chain_info().genesis_hash;
LightProtocol {
provider: provider,
@@ -323,6 +330,23 @@ impl LightProtocol {
self.handlers.push(handler);
}
/// Signal to handlers that network activity is being aborted
/// and clear peer data.
pub fn abort(&self) {
for handler in &self.handlers {
handler.on_abort();
}
// acquire in order and hold.
let mut pending_peers = self.pending_peers.write();
let mut peers = self.peers.write();
let mut pending_requests = self.pending_requests.write();
pending_peers.clear();
peers.clear();
pending_requests.clear();
}
// Does the common pre-verification of responses before the response itself
// is actually decoded:
// - check whether peer exists
@@ -460,7 +484,7 @@ impl LightProtocol {
head_hash: chain_info.best_block_hash,
head_num: chain_info.best_block_number,
genesis_hash: chain_info.genesis_hash,
protocol_version: PROTOCOL_VERSION,
protocol_version: MAX_PROTOCOL_VERSION as u32,
network_id: self.network_id,
last_head: None,
};

View File

@@ -82,26 +82,6 @@ impl Key {
}
}
/// Network ID structure.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
pub enum NetworkId {
/// ID for the mainnet
Mainnet = 1,
/// ID for the testnet
Testnet = 0,
}
impl NetworkId {
fn from_raw(raw: u32) -> Option<Self> {
match raw {
0 => Some(NetworkId::Testnet),
1 => Some(NetworkId::Mainnet),
_ => None,
}
}
}
// helper for decoding key-value pairs in the handshake or an announcement.
struct Parser<'a> {
pos: usize,
@@ -164,7 +144,7 @@ pub struct Status {
/// Protocol version.
pub protocol_version: u32,
/// Network id of this peer.
pub network_id: NetworkId,
pub network_id: u64,
/// Total difficulty of the head of the chain.
pub head_td: U256,
/// Hash of the best block.
@@ -225,8 +205,7 @@ pub fn parse_handshake(rlp: UntrustedRlp) -> Result<(Status, Capabilities, FlowP
let status = Status {
protocol_version: try!(parser.expect(Key::ProtocolVersion)),
network_id: try!(parser.expect(Key::NetworkId)
.and_then(|id: u32| NetworkId::from_raw(id).ok_or(DecoderError::Custom("Invalid network ID")))),
network_id: try!(parser.expect(Key::NetworkId)),
head_td: try!(parser.expect(Key::HeadTD)),
head_hash: try!(parser.expect(Key::HeadHash)),
head_num: try!(parser.expect(Key::HeadNum)),
@@ -254,7 +233,7 @@ pub fn parse_handshake(rlp: UntrustedRlp) -> Result<(Status, Capabilities, FlowP
pub fn write_handshake(status: &Status, capabilities: &Capabilities, flow_params: &FlowParams) -> Vec<u8> {
let mut pairs = Vec::new();
pairs.push(encode_pair(Key::ProtocolVersion, &status.protocol_version));
pairs.push(encode_pair(Key::NetworkId, &(status.network_id as u32)));
pairs.push(encode_pair(Key::NetworkId, &(status.network_id as u64)));
pairs.push(encode_pair(Key::HeadTD, &status.head_td));
pairs.push(encode_pair(Key::HeadHash, &status.head_hash));
pairs.push(encode_pair(Key::HeadNum, &status.head_num));
@@ -385,7 +364,7 @@ mod tests {
fn full_handshake() {
let status = Status {
protocol_version: 1,
network_id: NetworkId::Mainnet,
network_id: 1,
head_td: U256::default(),
head_hash: H256::default(),
head_num: 10,
@@ -420,7 +399,7 @@ mod tests {
fn partial_handshake() {
let status = Status {
protocol_version: 1,
network_id: NetworkId::Mainnet,
network_id: 1,
head_td: U256::default(),
head_hash: H256::default(),
head_num: 10,
@@ -455,7 +434,7 @@ mod tests {
fn skip_unknown_keys() {
let status = Status {
protocol_version: 1,
network_id: NetworkId::Mainnet,
network_id: 1,
head_td: U256::default(),
head_hash: H256::default(),
head_num: 10,

View File

@@ -25,7 +25,7 @@ use network::PeerId;
use net::buffer_flow::FlowParams;
use net::context::IoContext;
use net::status::{Capabilities, Status, NetworkId, write_handshake};
use net::status::{Capabilities, Status, write_handshake};
use net::{encode_request, LightProtocol, Params, packet};
use provider::Provider;
use request::{self, Request, Headers};
@@ -174,8 +174,8 @@ fn setup(flow_params: FlowParams, capabilities: Capabilities) -> (Arc<TestProvid
client: TestBlockChainClient::new(),
});
let proto = LightProtocol::new(Box::new(TestProvider(provider.clone())), Params {
network_id: NetworkId::Testnet,
let proto = LightProtocol::new(Arc::new(TestProvider(provider.clone())), Params {
network_id: 2,
flow_params: flow_params,
capabilities: capabilities,
});
@@ -185,8 +185,8 @@ fn setup(flow_params: FlowParams, capabilities: Capabilities) -> (Arc<TestProvid
fn status(chain_info: BlockChainInfo) -> Status {
Status {
protocol_version: ::net::PROTOCOL_VERSION,
network_id: NetworkId::Testnet,
protocol_version: 1,
network_id: 2,
head_td: chain_info.total_difficulty,
head_hash: chain_info.best_block_hash,
head_num: chain_info.best_block_number,

View File

@@ -33,6 +33,7 @@ use request;
/// or empty vector where appropriate.
///
/// [1]: https://github.com/ethcore/parity/wiki/Light-Ethereum-Subprotocol-(LES)
#[cfg_attr(feature = "ipc", ipc(client_ident="LightProviderClient"))]
pub trait Provider: Send + Sync {
/// Provide current blockchain info.
fn chain_info(&self) -> BlockChainInfo;