Skip to content

Commit

Permalink
Prioritize batch messaging (#30)
Browse files Browse the repository at this point in the history
* batch messaging

* update docs

* let router process messages individually

* nit
  • Loading branch information
Wizdave97 authored Apr 20, 2023
1 parent fec7654 commit a33c513
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 98 deletions.
10 changes: 5 additions & 5 deletions src/consensus_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ pub trait ConsensusClient {
/// Return unbonding period
fn unbonding_period(&self) -> Duration;

/// Verify the merkle mountain range membership of proof of a request/response.
/// Verify the merkle mountain range membership proof of a batch of requests/responses.
fn verify_membership(
&self,
host: &dyn ISMPHost,
Expand All @@ -101,17 +101,17 @@ pub trait ConsensusClient {
proof: &Proof,
) -> Result<(), Error>;

/// Transform the request/response into it's key in the state trie.
fn state_trie_key(&self, request: RequestResponse) -> Vec<u8>;
/// Transform the requests/responses into their equivalent key in the state trie.
fn state_trie_key(&self, request: RequestResponse) -> Vec<Vec<u8>>;

/// Verify the state of proof of some arbitrary data. Should return the verified data
fn verify_state_proof(
&self,
host: &dyn ISMPHost,
key: Vec<u8>,
keys: Vec<Vec<u8>>,
root: StateCommitment,
proof: &Proof,
) -> Result<Option<Vec<u8>>, Error>;
) -> Result<Vec<Option<Vec<u8>>>, Error>;

/// Decode trusted state and check if consensus client is frozen
fn is_frozen(&self, trusted_consensus_state: &[u8]) -> Result<(), Error>;
Expand Down
20 changes: 6 additions & 14 deletions src/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@
use crate::{
consensus_client::{ConsensusClient, ConsensusClientId, StateMachineHeight},
error::Error,
host::{ISMPHost, StateMachine},
host::ISMPHost,
messaging::{Message, Proof},
router::DispatchResult,
};
use alloc::{boxed::Box, collections::BTreeSet};
use alloc::{boxed::Box, collections::BTreeSet, vec::Vec};

mod consensus;
mod request;
Expand All @@ -40,22 +41,13 @@ pub struct ConsensusClientCreatedResult {
pub consensus_client_id: ConsensusClientId,
}

pub struct RequestResponseResult {
/// 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,
}

/// Result returned when ismp messages are handled successfully
pub enum MessageResult {
ConsensusMessage(ConsensusUpdateResult),
Request(RequestResponseResult),
Response(RequestResponseResult),
Request(Vec<DispatchResult>),
Response(Vec<DispatchResult>),
ConsensusClientCreated(ConsensusClientCreatedResult),
Timeout(RequestResponseResult),
Timeout(Vec<DispatchResult>),
}

/// This function serves as an entry point to handle the message types provided by the ISMP protocol
Expand Down
12 changes: 3 additions & 9 deletions src/handlers/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

use crate::{
error::Error,
handlers::{validate_state_machine, MessageResult, RequestResponseResult},
handlers::{validate_state_machine, MessageResult},
host::ISMPHost,
messaging::RequestMessage,
router::RequestResponse,
Expand All @@ -33,20 +33,14 @@ where
let state = host.state_machine_commitment(msg.proof.height)?;
consensus_client.verify_membership(
host,
RequestResponse::Request(msg.request.clone()),
RequestResponse::Request(msg.requests.clone()),
state,
&msg.proof,
)?;

let router = host.ismp_router();

let result = RequestResponseResult {
dest_chain: msg.request.dest_chain(),
source_chain: msg.request.source_chain(),
nonce: msg.request.nonce(),
};

router.dispatch(msg.request)?;
let result = msg.requests.into_iter().map(|request| router.dispatch(request)).collect();

Ok(MessageResult::Request(result))
}
33 changes: 15 additions & 18 deletions src/handlers/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

use crate::{
error::Error,
handlers::{validate_state_machine, MessageResult, RequestResponseResult},
handlers::{validate_state_machine, MessageResult},
host::ISMPHost,
messaging::ResponseMessage,
router::RequestResponse,
Expand All @@ -30,35 +30,32 @@ where
H: ISMPHost,
{
let consensus_client = validate_state_machine(host, &msg.proof)?;
// For a response to be valid a request commitment must be present in storage
let commitment = host.request_commitment(&msg.response.request)?;

if commitment != hash_request::<H>(&msg.response.request) {
return Err(Error::RequestCommitmentNotFound {
nonce: msg.response.request.nonce(),
source: msg.response.request.source_chain(),
dest: msg.response.request.dest_chain(),
})
for response in &msg.responses {
// For a response to be valid a request commitment must be present in storage
let commitment = host.request_commitment(&response.request)?;

if commitment != hash_request::<H>(&response.request) {
return Err(Error::RequestCommitmentNotFound {
nonce: response.request.nonce(),
source: response.request.source_chain(),
dest: response.request.dest_chain(),
})
}
}

let state = host.state_machine_commitment(msg.proof.height)?;
// Verify membership proof
consensus_client.verify_membership(
host,
RequestResponse::Response(msg.response.clone()),
RequestResponse::Response(msg.responses.clone()),
state,
&msg.proof,
)?;

let router = host.ismp_router();

let result = RequestResponseResult {
dest_chain: msg.response.request.source_chain(),
source_chain: msg.response.request.dest_chain(),
nonce: msg.response.request.nonce(),
};

router.write_response(msg.response)?;
let result =
msg.responses.into_iter().map(|response| router.write_response(response)).collect();

Ok(MessageResult::Response(result))
}
54 changes: 25 additions & 29 deletions src/handlers/timeout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

use crate::{
error::Error,
handlers::{validate_state_machine, MessageResult, RequestResponseResult},
handlers::{validate_state_machine, MessageResult},
host::ISMPHost,
messaging::TimeoutMessage,
router::RequestResponse,
Expand All @@ -30,42 +30,38 @@ where
H: ISMPHost,
{
let consensus_client = validate_state_machine(host, &msg.timeout_proof)?;
let commitment = host.request_commitment(&msg.request)?;
if commitment != hash_request::<H>(&msg.request) {
return Err(Error::RequestCommitmentNotFound {
nonce: msg.request.nonce(),
source: msg.request.source_chain(),
dest: msg.request.dest_chain(),
})
}

let state = host.state_machine_commitment(msg.timeout_proof.height)?;
if !msg.request.timed_out(state.timestamp()) {
Err(Error::RequestTimeoutNotElapsed {
nonce: msg.request.nonce(),
source: msg.request.source_chain(),
dest: msg.request.dest_chain(),
timeout_timestamp: msg.request.timeout(),
state_machine_time: state.timestamp(),
})?
for request in &msg.requests {
let commitment = host.request_commitment(request)?;
if commitment != hash_request::<H>(request) {
return Err(Error::RequestCommitmentNotFound {
nonce: request.nonce(),
source: request.source_chain(),
dest: request.dest_chain(),
})
}

if !request.timed_out(state.timestamp()) {
Err(Error::RequestTimeoutNotElapsed {
nonce: request.nonce(),
source: request.source_chain(),
dest: request.dest_chain(),
timeout_timestamp: request.timeout(),
state_machine_time: state.timestamp(),
})?
}
}

let key = consensus_client.state_trie_key(RequestResponse::Request(msg.request.clone()));
let key = consensus_client.state_trie_key(RequestResponse::Request(msg.requests.clone()));

let request = consensus_client.verify_state_proof(host, key, state, &msg.timeout_proof)?;
let requests = consensus_client.verify_state_proof(host, key, state, &msg.timeout_proof)?;

if request.is_some() {
Err(Error::ImplementationSpecific("Request not timed out".into()))?
if requests.into_iter().any(|val| val.is_some()) {
Err(Error::ImplementationSpecific("Some Requests not timed out".into()))?
}

let result = RequestResponseResult {
dest_chain: msg.request.source_chain(),
source_chain: msg.request.dest_chain(),
nonce: msg.request.nonce(),
};

let router = host.ismp_router();
router.dispatch_timeout(msg.request)?;
let result = msg.requests.into_iter().map(|request| router.dispatch_timeout(request)).collect();

Ok(MessageResult::Timeout(result))
}
18 changes: 9 additions & 9 deletions src/messaging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,25 +42,25 @@ pub struct CreateConsensusClient {

#[derive(Debug, Clone, Encode, Decode, scale_info::TypeInfo, PartialEq, Eq)]
pub struct RequestMessage {
/// Request from source chain
pub request: Request,
/// Membership proof for this request
/// Requests from source chain
pub requests: Vec<Request>,
/// Membership batch proof for these requests
pub proof: Proof,
}

#[derive(Debug, Clone, Encode, Decode, scale_info::TypeInfo, PartialEq, Eq)]
pub struct ResponseMessage {
/// Response from sink chain
pub response: Response,
/// Membership proof for this response
/// Responses from sink chain
pub responses: Vec<Response>,
/// Membership batch proof for these responses
pub proof: Proof,
}

#[derive(Debug, Clone, Encode, Decode, scale_info::TypeInfo, PartialEq, Eq)]
pub struct TimeoutMessage {
/// Request timeout request
pub request: Request,
/// Non membership state Proof for the timeout
/// Request timeouts
pub requests: Vec<Request>,
/// Non membership batch proof for these requests
pub timeout_proof: Proof,
}

Expand Down
52 changes: 38 additions & 14 deletions src/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@

//! ISMPRouter definition

use crate::{consensus_client::StateMachineHeight, error::Error, host::StateMachine, prelude::Vec};
use crate::{consensus_client::StateMachineHeight, host::StateMachine, prelude::Vec};
use alloc::string::String;
use codec::{Decode, Encode};
use core::time::Duration;

Expand Down Expand Up @@ -141,20 +142,43 @@ pub type GetResponse = Vec<(Vec<u8>, Vec<u8>)>;

/// Convenience enum for membership verification.
pub enum RequestResponse {
Request(Request),
Response(Response),
Request(Vec<Request>),
Response(Vec<Response>),
}

pub trait ISMPRouter {
/// Dispatch a request from a module to the ISMP router.
/// If request source chain is the host, it should be committed in state as a sha256 hash
fn dispatch(&self, request: Request) -> Result<(), Error>;

/// Dispatch a request timeout from a module to the ISMP router.
/// If request source chain is the host, it should be committed in state as a sha256 hash
fn dispatch_timeout(&self, request: Request) -> Result<(), Error>;
#[derive(Debug, PartialEq, Eq)]
pub enum DispatchResult {
Error {
/// Descriptive error message
msg: String,
/// Request nonce
nonce: u64,
/// Source chain for request or response
source: StateMachine,
/// Destination chain for request or response
dest: StateMachine,
},
Success {
/// Destination chain for request or response
dest_chain: StateMachine,
/// Source chain for request or response
source_chain: StateMachine,
/// Request nonce
nonce: u64,
},
}

/// Provide a response to a previously received request.
/// If response source chain is the host, it should be committed in state as a sha256 hash
fn write_response(&self, response: Response) -> Result<(), Error>;
pub trait ISMPRouter {
/// Dispatch some requests to the ISMP router.
/// For outgoing requests, they should be committed in state as a keccak256 hash
/// For incoming requests, they should be dispatched to destination modules
fn dispatch(&self, request: Request) -> DispatchResult;

/// Dispatch request timeouts to the router which should dispatch them to modules
fn dispatch_timeout(&self, request: Request) -> DispatchResult;

/// Dispatch some responses to the ISMP router.
/// For outgoing responses, the router should commit them to host state as a keccak256 hash
/// For incoming responses, they should be dispatched to destination modules
fn write_response(&self, response: Response) -> DispatchResult;
}

0 comments on commit a33c513

Please sign in to comment.