Skip to content

Commit

Permalink
light-client: turn Handle into a trait
Browse files Browse the repository at this point in the history
As we start to depend on the surface of the `Handle` we benefit from it
being a trait that can be implemented on a per need basis. This will
result in less overhead constructing object graphs in places where we
wannt to assert behaviour of other types in remote places, i.e. the
light-node rpc server. Overall we hope for an increased ease in writing
tests on module level.

Ref #219
  • Loading branch information
xla committed Jun 30, 2020
1 parent ebda75b commit 04b9373
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 49 deletions.
18 changes: 9 additions & 9 deletions light-client/examples/light_client.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
use std::collections::HashMap;
use std::{
path::{Path, PathBuf},
time::Duration,
};

use gumdrop::Options;

use tendermint_light_client::supervisor::{Handle as _, Instance, Supervisor};
use tendermint_light_client::{
components::{
clock::SystemClock,
Expand All @@ -11,18 +20,9 @@ use tendermint_light_client::{
peer_list::PeerList,
state::State,
store::{sled::SledStore, LightStore},
supervisor::{Instance, Supervisor},
types::{Height, PeerId, Status, Time, TrustThreshold},
};

use gumdrop::Options;

use std::collections::HashMap;
use std::{
path::{Path, PathBuf},
time::Duration,
};

#[derive(Debug, Options)]
struct CliOptions {
#[options(help = "print this help message")]
Expand Down
102 changes: 62 additions & 40 deletions light-client/src/supervisor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,39 @@ use crate::{
types::{Height, LightBlock, PeerId, Status},
};

pub trait Handle {
/// Get latest trusted block from the [`Supervisor`].
fn latest_trusted(&mut self) -> Result<Option<LightBlock>, Error>;

/// Verify to the highest block.
fn verify_to_highest(&mut self) -> Result<LightBlock, Error>;

/// Verify to the block at the given height.
fn verify_to_target(&mut self, height: Height) -> Result<LightBlock, Error>;

/// Async version of `verify_to_highest`.
///
/// The given `callback` will be called asynchronously with the
/// verification result.
fn verify_to_highest_async(
&mut self,
callback: impl FnOnce(Result<LightBlock, Error>) -> () + Send + 'static,
);

/// Async version of `verify_to_target`.
///
/// The given `callback` will be called asynchronously with the
/// verification result.
fn verify_to_target_async(
&mut self,
height: Height,
callback: impl FnOnce(Result<LightBlock, Error>) -> () + Send + 'static,
);

/// Terminate the underlying [`Supervisor`].
fn terminate(&mut self);
}

/// Input events sent by the [`Handle`]s to the [`Supervisor`]. They carry a [`Callback`] which is
/// used to communicate back the responses of the requests.
#[derive(Debug)]
Expand Down Expand Up @@ -134,8 +167,8 @@ impl Supervisor {
}

/// Create a new handle to this supervisor.
pub fn handle(&mut self) -> Handle {
Handle::new(self.sender.clone())
pub fn handle(&mut self) -> impl Handle {
SupervisorHandle::new(self.sender.clone())
}

#[pre(self.peers.primary().is_some())]
Expand Down Expand Up @@ -308,21 +341,38 @@ impl Supervisor {
}
}

/// A handle to a `Supervisor` which allows to communicate with
/// A [`Handle`] to the [`Supervisor`] which allows to communicate with
/// the supervisor across thread boundaries via message passing.
pub struct Handle {
struct SupervisorHandle {
sender: channel::Sender<HandleInput>,
}

impl Handle {
impl SupervisorHandle {
/// Crate a new handle that sends events to the supervisor via
/// the given channel. For internal use only.
fn new(sender: channel::Sender<HandleInput>) -> Self {
Self { sender }
}

/// Get latest trusted block from the [`Supervisor`].
pub fn latest_trusted(&mut self) -> Result<Option<LightBlock>, Error> {
fn verify(
&mut self,
make_event: impl FnOnce(Callback<Result<LightBlock, Error>>) -> HandleInput,
) -> Result<LightBlock, Error> {
let (sender, receiver) = channel::bounded::<Result<LightBlock, Error>>(1);

let callback = Callback::new(move |result| {
sender.send(result).unwrap();
});

let event = make_event(callback);
self.sender.send(event).unwrap();

receiver.recv().unwrap()
}
}

impl Handle for SupervisorHandle {
fn latest_trusted(&mut self) -> Result<Option<LightBlock>, Error> {
let (sender, receiver) = channel::bounded::<Result<Option<LightBlock>, Error>>(1);

let callback = Callback::new(move |result| {
Expand All @@ -338,50 +388,23 @@ impl Handle {
receiver.recv().unwrap()
}

/// Verify to the highest block.
pub fn verify_to_highest(&mut self) -> Result<LightBlock, Error> {
fn verify_to_highest(&mut self) -> Result<LightBlock, Error> {
self.verify(HandleInput::VerifyToHighest)
}

/// Verify to the block at the given height.
pub fn verify_to_target(&mut self, height: Height) -> Result<LightBlock, Error> {
fn verify_to_target(&mut self, height: Height) -> Result<LightBlock, Error> {
self.verify(|callback| HandleInput::VerifyToTarget(height, callback))
}

/// Verify either to the latest block (if `height == None`) or to a given block (if `height == Some(height)`).
fn verify(
&mut self,
make_event: impl FnOnce(Callback<Result<LightBlock, Error>>) -> HandleInput,
) -> Result<LightBlock, Error> {
let (sender, receiver) = channel::bounded::<Result<LightBlock, Error>>(1);

let callback = Callback::new(move |result| {
sender.send(result).unwrap();
});

let event = make_event(callback);
self.sender.send(event).unwrap();

receiver.recv().unwrap()
}

/// Async version of `verify_to_highest`.
///
/// The given `callback` will be called asynchronously with the
/// verification result.
pub fn verify_to_highest_async(
fn verify_to_highest_async(
&mut self,
callback: impl FnOnce(Result<LightBlock, Error>) -> () + Send + 'static,
) {
let event = HandleInput::VerifyToHighest(Callback::new(callback));
self.sender.send(event).unwrap();
}

/// Async version of `verify_to_target`.
///
/// The given `callback` will be called asynchronously with the
/// verification result.
pub fn verify_to_target_async(
fn verify_to_target_async(
&mut self,
height: Height,
callback: impl FnOnce(Result<LightBlock, Error>) -> () + Send + 'static,
Expand All @@ -390,8 +413,7 @@ impl Handle {
self.sender.send(event).unwrap();
}

/// Terminate the underlying supervisor.
pub fn terminate(&mut self) {
fn terminate(&mut self) {
let (sender, receiver) = channel::bounded::<()>(1);

let callback = Callback::new(move |_| {
Expand Down

0 comments on commit 04b9373

Please sign in to comment.