Skip to content

Commit

Permalink
Refactor routing (#57)
Browse files Browse the repository at this point in the history
  • Loading branch information
Wizdave97 authored Jun 8, 2023
1 parent 4012192 commit 3c138d7
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 77 deletions.
45 changes: 24 additions & 21 deletions ismp-testsuite/src/mocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ use ismp::{
error::Error,
host::{IsmpHost, StateMachine},
messaging::{Proof, StateCommitmentHeight},
module::{DispatchError, DispatchResult, DispatchSuccess, IsmpModule},
router::{
DispatchError, DispatchRequest, DispatchResult, DispatchSuccess, Get, IsmpDispatcher,
IsmpRouter, Post, PostResponse, Request, RequestResponse, Response,
DispatchRequest, Get, IsmpDispatcher, IsmpRouter, Post, PostResponse, Request,
RequestResponse, Response,
},
util::{hash_request, hash_response},
};
Expand Down Expand Up @@ -266,38 +267,40 @@ impl IsmpHost for Host {
}
}

pub struct MockRouter(pub Host);
#[derive(Default)]
pub struct MockModule;

impl IsmpRouter for MockRouter {
fn handle_request(&self, request: Post) -> DispatchResult {
let host = &self.0.clone();
let request = Request::Post(request);
if request.dest_chain() != host.host_state_machine() {
} else {
host.store_request_receipt(&request).unwrap();
}
impl IsmpModule for MockModule {
fn on_accept(&self, request: Post) -> DispatchResult {
Ok(DispatchSuccess {
dest_chain: request.dest_chain,
source_chain: request.source_chain,
nonce: request.nonce,
})
}

fn on_response(&self, response: Response) -> DispatchResult {
Ok(DispatchSuccess {
dest_chain: request.dest_chain(),
source_chain: request.source_chain(),
nonce: request.nonce(),
dest_chain: response.dest_chain(),
source_chain: response.source_chain(),
nonce: response.nonce(),
})
}

fn handle_timeout(&self, request: Request) -> DispatchResult {
fn on_timeout(&self, request: Request) -> DispatchResult {
Ok(DispatchSuccess {
dest_chain: request.dest_chain(),
source_chain: request.source_chain(),
nonce: request.nonce(),
})
}
}

fn handle_response(&self, response: Response) -> DispatchResult {
Ok(DispatchSuccess {
dest_chain: response.dest_chain(),
source_chain: response.source_chain(),
nonce: response.nonce(),
})
pub struct MockRouter(pub Host);

impl IsmpRouter for MockRouter {
fn module_for_id(&self, _bytes: Vec<u8>) -> Result<Box<dyn IsmpModule>, Error> {
Ok(Box::new(MockModule))
}
}

Expand Down
4 changes: 3 additions & 1 deletion ismp/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::{
consensus::{ConsensusClientId, StateMachineHeight},
host::StateMachine,
};
use alloc::string::String;
use alloc::{string::String, vec::Vec};
use core::time::Duration;

/// Errors that may be encountered by the ISMP module
Expand Down Expand Up @@ -135,4 +135,6 @@ pub enum Error {
},
/// Supplied proof height is invalid
InsufficientProofHeight,
/// An Ismp Module was not found for the given raw id
ModuleNotFound(Vec<u8>),
}
2 changes: 1 addition & 1 deletion ismp/src/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ use crate::{
error::Error,
host::IsmpHost,
messaging::Message,
router::DispatchResult,
};

use crate::module::DispatchResult;
use alloc::{boxed::Box, collections::BTreeSet, vec::Vec};
pub use consensus::create_client;

Expand Down
3 changes: 2 additions & 1 deletion ismp/src/handlers/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ where
host.request_receipt(&req).is_none() && !req.timed_out(state.timestamp())
})
.map(|request| {
let res = router.handle_request(request.clone());
let cb = router.module_for_id(request.to.clone())?;
let res = cb.on_accept(request.clone());
host.store_request_receipt(&Request::Post(request))?;
Ok(res)
})
Expand Down
6 changes: 4 additions & 2 deletions ismp/src/handlers/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ where
.into_iter()
.filter(|res| host.response_receipt(res).is_none())
.map(|response| {
let res = router.handle_response(response.clone());
let cb = router.module_for_id(response.destination_module())?;
let res = cb.on_response(response.clone());
host.store_response_receipt(&response)?;
Ok(res)
})
Expand All @@ -84,7 +85,8 @@ where
let values = state_machine.verify_state_proof(host, keys, state, &proof)?;

let router = host.ismp_router();
let res = router.handle_response(Response::Get(GetResponse {
let cb = router.module_for_id(request.source_module())?;
let res = cb.on_response(Response::Get(GetResponse {
get: request.get_request()?,
values,
}));
Expand Down
6 changes: 4 additions & 2 deletions ismp/src/handlers/timeout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ where
requests
.into_iter()
.map(|request| {
let res = router.handle_timeout(request.clone());
let cb = router.module_for_id(request.source_module())?;
let res = cb.on_timeout(request.clone());
host.delete_request_commitment(&request)?;
Ok(res)
})
Expand Down Expand Up @@ -99,7 +100,8 @@ where
requests
.into_iter()
.map(|request| {
let res = router.handle_timeout(request.clone());
let cb = router.module_for_id(request.source_module())?;
let res = cb.on_timeout(request.clone());
host.delete_request_commitment(&request)?;
Ok(res)
})
Expand Down
48 changes: 38 additions & 10 deletions ismp/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,50 @@
//! ISMPModule definition

use crate::{
error::Error,
host::StateMachine,
router::{Post as PostRequest, Request, Response},
};
use alloc::string::String;

/// The result of successfully dispatching a request or response
#[derive(Debug, PartialEq, Eq)]
pub struct DispatchSuccess {
/// Destination chain for request or response
pub dest_chain: StateMachine,
/// Source chain for request or response
pub source_chain: StateMachine,
/// Request nonce
pub nonce: u64,
}

/// The result of unsuccessfully dispatching a request or response
#[derive(Debug, PartialEq, Eq)]
pub struct DispatchError {
/// Descriptive error message
pub msg: String,
/// Request nonce
pub nonce: u64,
/// Source chain for request or response
pub source: StateMachine,
/// Destination chain for request or response
pub dest: StateMachine,
}

/// A type alias for dispatch results
pub type DispatchResult = Result<DispatchSuccess, DispatchError>;

/// Individual modules which live on a state machine must conform to this interface in order to send
/// and receive ISMP requests and reponses
/// and receive ISMP requests and responses
pub trait IsmpModule {
/// Called by the local ISMP router on a module, to notify module of a new POST request
/// Called by the message handler on a module, to notify module of a new POST request
/// the module may choose to respond immediately, or in a later block
fn on_accept(request: PostRequest) -> Result<(), Error>;
fn on_accept(&self, request: PostRequest) -> DispatchResult;

/// Called by the router on a module, to notify module of a response to a previously sent out
/// request
fn on_response(response: Response) -> Result<(), Error>;
/// Called by the message handler on a module, to notify module of a response to a previously
/// sent out request
fn on_response(&self, response: Response) -> DispatchResult;

/// Called by the router on a module, to notify module of requests that were previously sent but
/// have now timed-out
fn on_timeout(request: Request) -> Result<(), Error>;
/// Called by the message handler on a module, to notify module of requests that were previously
/// sent but have now timed-out
fn on_timeout(&self, request: Request) -> DispatchResult;
}
73 changes: 34 additions & 39 deletions ismp/src/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@

//! IsmpRouter definition

use crate::{error::Error, host::StateMachine, prelude::Vec};
use alloc::{
collections::BTreeMap,
string::{String, ToString},
use crate::{
error::Error,
host::StateMachine,
module::{DispatchResult, IsmpModule},
prelude::Vec,
};
use alloc::{boxed::Box, collections::BTreeMap, string::ToString};
use codec::{Decode, Encode};
use core::time::Duration;

Expand Down Expand Up @@ -92,6 +94,22 @@ impl Request {
}
}

/// Module where this request originated on source chain
pub fn source_module(&self) -> Vec<u8> {
match self {
Request::Get(get) => get.from.clone(),
Request::Post(post) => post.from.clone(),
}
}

/// Module that this request will be routed to on destination chain
pub fn destination_module(&self) -> Vec<u8> {
match self {
Request::Get(get) => get.from.clone(),
Request::Post(post) => post.to.clone(),
}
}

/// Get the destination chain
pub fn dest_chain(&self) -> StateMachine {
match self {
Expand Down Expand Up @@ -202,6 +220,14 @@ impl Response {
}
}

/// Module that this response will be routed to on destination chain
pub fn destination_module(&self) -> Vec<u8> {
match self {
Response::Get(get) => get.get.from.clone(),
Response::Post(post) => post.post.from.clone(),
}
}

/// Get the source chain for this response
pub fn source_chain(&self) -> StateMachine {
match self {
Expand Down Expand Up @@ -235,43 +261,12 @@ pub enum RequestResponse {
Response(Vec<Response>),
}

/// The result of successfully dispatching a request or response
#[derive(Debug, PartialEq, Eq)]
pub struct DispatchSuccess {
/// Destination chain for request or response
pub dest_chain: StateMachine,
/// Source chain for request or response
pub source_chain: StateMachine,
/// Request nonce
pub nonce: u64,
}

/// The result of unsuccessfully dispatching a request or response
#[derive(Debug, PartialEq, Eq)]
pub struct DispatchError {
/// Descriptive error message
pub msg: String,
/// Request nonce
pub nonce: u64,
/// Source chain for request or response
pub source: StateMachine,
/// Destination chain for request or response
pub dest: StateMachine,
}

/// A type alias for dispatch results
pub type DispatchResult = Result<DispatchSuccess, DispatchError>;

/// The Ismp router dictates how messsages are routed to [`IsmpModules`]
pub trait IsmpRouter {
/// Dispatch the incoming request to destination modules
fn handle_request(&self, request: Post) -> DispatchResult;

/// Dispatch the request timeouts to destination modules
fn handle_timeout(&self, request: Request) -> DispatchResult;

/// Dispatch the incoming response to destination modules
fn handle_response(&self, response: Response) -> DispatchResult;
/// Get module handler by id
/// Should decode the module id and return a handler to the appropriate `IsmpModule`
/// implementation
fn module_for_id(&self, bytes: Vec<u8>) -> Result<Box<dyn IsmpModule>, Error>;
}

/// Simplified POST request, intended to be used for sending outgoing requests
Expand Down

0 comments on commit 3c138d7

Please sign in to comment.