light: integrate with sync + serve_light CLI
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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::*;
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user