Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Light Client transaction queue, initial LightDispatcher #4501

Merged
merged 18 commits into from
Feb 15, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
84 changes: 51 additions & 33 deletions ethcore/light/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,22 @@

//! Light client implementation. Stores data from light sync

use std::sync::Arc;

use ethcore::block_import_error::BlockImportError;
use ethcore::block_status::BlockStatus;
use ethcore::client::ClientReport;
use ethcore::engines::Engine;
use ethcore::ids::BlockId;
use ethcore::header::Header;
use ethcore::verification::queue::{self, HeaderQueue};
use ethcore::transaction::{PendingTransaction, Condition as TransactionCondition};
use ethcore::blockchain_info::BlockChainInfo;
use ethcore::spec::Spec;
use ethcore::service::ClientIoMessage;
use ethcore::encoded;
use io::IoChannel;

use util::hash::{H256, H256FastMap};
use util::{Bytes, Mutex, RwLock};

use provider::Provider;
use request;
use util::{Bytes, H256, Mutex, RwLock};

use self::header_chain::HeaderChain;

Expand All @@ -58,6 +56,12 @@ pub trait LightChainClient: Send + Sync {
/// parent queued prior.
fn queue_header(&self, header: Header) -> Result<H256, BlockImportError>;

/// Attempt to get block header by block id.
fn block_header(&self, id: BlockId) -> Option<encoded::Header>;

/// Get the best block header.
fn best_block_header(&self) -> encoded::Header;

/// Query whether a block is known.
fn is_known(&self, hash: &H256) -> bool;

Expand All @@ -74,11 +78,26 @@ pub trait LightChainClient: Send + Sync {
fn cht_root(&self, i: usize) -> Option<H256>;
}

/// Something which can be treated as a `LightChainClient`.
pub trait AsLightClient {
/// The kind of light client this can be treated as.
type Client: LightChainClient;

/// Access the underlying light client.
fn as_light_client(&self) -> &Self::Client;
}

impl<T: LightChainClient> AsLightClient for T {
type Client = Self;

fn as_light_client(&self) -> &Self { self }
}

/// Light client implementation.
pub struct Client {
queue: HeaderQueue,
engine: Arc<Engine>,
chain: HeaderChain,
tx_pool: Mutex<H256FastMap<PendingTransaction>>,
report: RwLock<ClientReport>,
import_lock: Mutex<()>,
}
Expand All @@ -88,8 +107,8 @@ impl Client {
pub fn new(config: Config, spec: &Spec, io_channel: IoChannel<ClientIoMessage>) -> Self {
Client {
queue: HeaderQueue::new(config.queue, spec.engine.clone(), io_channel, true),
engine: spec.engine.clone(),
chain: HeaderChain::new(&::rlp::encode(&spec.genesis_header())),
tx_pool: Mutex::new(Default::default()),
report: RwLock::new(ClientReport::default()),
import_lock: Mutex::new(()),
}
Expand All @@ -100,25 +119,6 @@ impl Client {
self.queue.import(header).map_err(Into::into)
}

/// Import a local transaction.
pub fn import_own_transaction(&self, tx: PendingTransaction) {
self.tx_pool.lock().insert(tx.transaction.hash(), tx);
}

/// Fetch a vector of all pending transactions.
pub fn ready_transactions(&self) -> Vec<PendingTransaction> {
let best = self.chain.best_header();
self.tx_pool.lock()
.values()
.filter(|t| match t.condition {
Some(TransactionCondition::Number(x)) => x <= best.number(),
Some(TransactionCondition::Timestamp(x)) => x <= best.timestamp(),
None => true,
})
.cloned()
.collect()
}

/// Inquire about the status of a given header.
pub fn status(&self, hash: &H256) -> BlockStatus {
match self.queue.status(hash) {
Expand Down Expand Up @@ -159,6 +159,11 @@ impl Client {
self.chain.block_header(id)
}

/// Get the best block header.
pub fn best_block_header(&self) -> encoded::Header {
self.chain.best_header()
}

/// Flush the header queue.
pub fn flush_queue(&self) {
self.queue.flush()
Expand Down Expand Up @@ -207,6 +212,11 @@ impl Client {

self.chain.heap_size_of_children()
}

/// Get a handle to the verification engine.
pub fn engine(&self) -> &Engine {
&*self.engine
}
}

impl LightChainClient for Client {
Expand All @@ -216,6 +226,14 @@ impl LightChainClient for Client {
self.import_header(header)
}

fn block_header(&self, id: BlockId) -> Option<encoded::Header> {
Client::block_header(self, id)
}

fn best_block_header(&self) -> encoded::Header {
Client::best_block_header(self)
}

fn is_known(&self, hash: &H256) -> bool {
self.status(hash) == BlockStatus::InChain
}
Expand All @@ -237,8 +255,8 @@ impl LightChainClient for Client {
}
}

// dummy implementation -- may draw from canonical cache further on.
impl Provider for Client {
// dummy implementation, should be removed when a `TestClient` is added.
impl ::provider::Provider for Client {
fn chain_info(&self) -> BlockChainInfo {
Client::chain_info(self)
}
Expand All @@ -263,19 +281,19 @@ impl Provider for Client {
None
}

fn state_proof(&self, _req: request::StateProof) -> Vec<Bytes> {
fn state_proof(&self, _req: ::request::StateProof) -> Vec<Bytes> {
Vec::new()
}

fn contract_code(&self, _req: request::ContractCode) -> Bytes {
fn contract_code(&self, _req: ::request::ContractCode) -> Bytes {
Vec::new()
}

fn header_proof(&self, _req: request::HeaderProof) -> Option<(encoded::Header, Vec<Bytes>)> {
fn header_proof(&self, _req: ::request::HeaderProof) -> Option<(encoded::Header, Vec<Bytes>)> {
None
}

fn ready_transactions(&self) -> Vec<PendingTransaction> {
fn ready_transactions(&self) -> Vec<::ethcore::transaction::PendingTransaction> {
Vec::new()
}
}
2 changes: 2 additions & 0 deletions ethcore/light/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ pub mod client;
pub mod cht;
pub mod net;
pub mod on_demand;
pub mod transaction_queue;

#[cfg(not(feature = "ipc"))]
pub mod provider;
Expand All @@ -54,6 +55,7 @@ pub mod remote {
mod types;

pub use self::provider::Provider;
pub use self::transaction_queue::TransactionQueue;
pub use types::les_request as request;

#[macro_use]
Expand Down
75 changes: 74 additions & 1 deletion ethcore/light/src/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,19 @@
//! A provider for the LES protocol. This is typically a full node, who can
//! give as much data as necessary to its peers.

use std::sync::Arc;

use ethcore::blockchain_info::BlockChainInfo;
use ethcore::client::{BlockChainClient, ProvingBlockChainClient};
use ethcore::transaction::PendingTransaction;
use ethcore::ids::BlockId;
use ethcore::encoded;
use util::{Bytes, RwLock, H256};

use cht::{self, BlockInfo};
use client::{LightChainClient, AsLightClient};
use transaction_queue::TransactionQueue;

use util::{Bytes, H256};

use request;

Expand Down Expand Up @@ -284,6 +288,75 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
}
}

/// The light client "provider" implementation. This wraps a `LightClient` and
/// a light transaction queue.
pub struct LightProvider<L> {
client: Arc<L>,
txqueue: Arc<RwLock<TransactionQueue>>,
}

impl<L> LightProvider<L> {
/// Create a new `LightProvider` from the given client and transaction queue.
pub fn new(client: Arc<L>, txqueue: Arc<RwLock<TransactionQueue>>) -> Self {
LightProvider {
client: client,
txqueue: txqueue,
}
}
}

// TODO: draw from cache (shared between this and the RPC layer)
impl<L: AsLightClient + Send + Sync> Provider for LightProvider<L> {
fn chain_info(&self) -> BlockChainInfo {
self.client.as_light_client().chain_info()
}

fn reorg_depth(&self, _a: &H256, _b: &H256) -> Option<u64> {
None
}

fn earliest_state(&self) -> Option<u64> {
None
}

fn block_header(&self, id: BlockId) -> Option<encoded::Header> {
self.client.as_light_client().block_header(id)
}

fn block_body(&self, _id: BlockId) -> Option<encoded::Body> {
None
}

fn block_receipts(&self, _hash: &H256) -> Option<Bytes> {
None
}

fn state_proof(&self, _req: request::StateProof) -> Vec<Bytes> {
Vec::new()
}

fn contract_code(&self, _req: request::ContractCode) -> Bytes {
Vec::new()
}

fn header_proof(&self, _req: request::HeaderProof) -> Option<(encoded::Header, Vec<Bytes>)> {
None
}

fn ready_transactions(&self) -> Vec<PendingTransaction> {
let chain_info = self.chain_info();
self.txqueue.read().ready_transactions(chain_info.best_block_number, chain_info.best_block_timestamp)
}
}

impl<L: AsLightClient> AsLightClient for LightProvider<L> {
type Client = L::Client;

fn as_light_client(&self) -> &L::Client {
self.client.as_light_client()
}
}

#[cfg(test)]
mod tests {
use ethcore::client::{EachBlockWith, TestBlockChainClient};
Expand Down