-
Notifications
You must be signed in to change notification settings - Fork 331
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ADR 003: Handler implementation (#197)
* Add doc comments and error types to ICS 02 module * Rename ics02_client::client module to ics02_client::raw * Replace message traits with structs * Fix formatting error * Add implementation specific error kind * Fixup client message structs definitions * Fix clippy warnings * Add basic handler definitions * Add initial implementation of CreateClient handler * Add implementation of ClientDef for Tendermint * Re-use existing traits * Add valid test for create_client handler * Add tests for case where client already exists * WIP: Update client handler * Add initial proposal for ADR 003 * Rename file to adr-003-handler-implementation.md * Replace "handler" with "message processor" in plain text * Formatting * Fix create client handler tests * Rename module handler to dispatch * Formatting * Add sketch of update client processor * Move mocks into their own module * Remove genericity over client def in client submodule * Lift chain specific data into an enum * Update ADR to match new handling of chain-specific data * Fix the connection specifics in ADR * Added Tendermint to the new "Any*" enums Added client state to MsgCreateAnyClient, result, keeper, etc Test for concrete tendermint MsgCreateClient Updated TM client and consensus states, MsgCreateClient Extract client and consensus states from MsgCreateClient for TM Extract consensus state from MsgUpdateClient for TM Co-authored-by: Adi Seredinschi <[email protected]> Co-authored-by: Anca Zamfir <[email protected]>
- Loading branch information
1 parent
cd6c0a0
commit 788c36b
Showing
33 changed files
with
1,744 additions
and
168 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
use std::marker::PhantomData; | ||
|
||
#[derive(Clone, Debug, PartialEq, Eq)] | ||
pub struct Attribute { | ||
key: String, | ||
value: String, | ||
} | ||
|
||
impl Attribute { | ||
pub fn new(key: String, value: String) -> Self { | ||
Self { key, value } | ||
} | ||
} | ||
|
||
#[derive(Clone, Debug, PartialEq, Eq)] | ||
pub enum EventType { | ||
Message, | ||
Custom(String), | ||
} | ||
|
||
#[derive(Clone, Debug, PartialEq, Eq)] | ||
pub struct Event { | ||
tpe: EventType, | ||
attributes: Vec<Attribute>, | ||
} | ||
|
||
impl Event { | ||
pub fn new(tpe: EventType, attrs: Vec<(String, String)>) -> Self { | ||
Self { | ||
tpe, | ||
attributes: attrs | ||
.into_iter() | ||
.map(|(k, v)| Attribute::new(k, v)) | ||
.collect(), | ||
} | ||
} | ||
} | ||
|
||
pub type HandlerResult<T, E> = Result<HandlerOutput<T>, E>; | ||
|
||
#[derive(Clone, Debug, PartialEq, Eq)] | ||
pub struct HandlerOutput<T> { | ||
pub result: T, | ||
pub log: Vec<String>, | ||
pub events: Vec<Event>, | ||
} | ||
|
||
impl<T> HandlerOutput<T> { | ||
pub fn builder() -> HandlerOutputBuilder<T> { | ||
HandlerOutputBuilder::new() | ||
} | ||
} | ||
|
||
#[derive(Clone, Debug, Default, PartialEq, Eq)] | ||
pub struct HandlerOutputBuilder<T> { | ||
log: Vec<String>, | ||
events: Vec<Event>, | ||
marker: PhantomData<T>, | ||
} | ||
|
||
impl<T> HandlerOutputBuilder<T> { | ||
pub fn new() -> Self { | ||
Self { | ||
log: vec![], | ||
events: vec![], | ||
marker: PhantomData, | ||
} | ||
} | ||
|
||
pub fn with_log(mut self, log: impl Into<Vec<String>>) -> Self { | ||
self.log.append(&mut log.into()); | ||
self | ||
} | ||
|
||
pub fn log(&mut self, log: impl Into<String>) { | ||
self.log.push(log.into()); | ||
} | ||
|
||
pub fn with_events(mut self, events: impl Into<Vec<Event>>) -> Self { | ||
self.events.append(&mut events.into()); | ||
self | ||
} | ||
|
||
pub fn emit(&mut self, event: impl Into<Event>) { | ||
self.events.push(event.into()); | ||
} | ||
|
||
pub fn with_result(self, result: T) -> HandlerOutput<T> { | ||
HandlerOutput { | ||
result, | ||
log: self.log, | ||
events: self.events, | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
use serde_derive::{Deserialize, Serialize}; | ||
|
||
use crate::ics02_client::client_type::ClientType; | ||
use crate::ics02_client::header::Header; | ||
use crate::ics02_client::state::{ClientState, ConsensusState}; | ||
use crate::ics23_commitment::CommitmentRoot; | ||
use crate::Height; | ||
|
||
use crate::ics02_client::mocks; | ||
use crate::ics07_tendermint as tendermint; | ||
use crate::ics07_tendermint::client_def::TendermintClient; | ||
|
||
pub trait ClientDef: Clone { | ||
type Header: Header; | ||
type ClientState: ClientState; | ||
type ConsensusState: ConsensusState; | ||
} | ||
|
||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] // TODO: Add Eq | ||
#[allow(clippy::large_enum_variant)] | ||
pub enum AnyHeader { | ||
Mock(mocks::MockHeader), | ||
Tendermint(tendermint::header::Header), | ||
} | ||
|
||
impl Header for AnyHeader { | ||
fn client_type(&self) -> ClientType { | ||
match self { | ||
Self::Mock(header) => header.client_type(), | ||
Self::Tendermint(header) => header.client_type(), | ||
} | ||
} | ||
|
||
fn height(&self) -> Height { | ||
match self { | ||
Self::Mock(header) => header.height(), | ||
Self::Tendermint(header) => header.height(), | ||
} | ||
} | ||
} | ||
|
||
#[derive(Clone, Debug, PartialEq)] | ||
pub enum AnyClientState { | ||
Mock(mocks::MockClientState), | ||
Tendermint(crate::ics07_tendermint::client_state::ClientState), | ||
} | ||
|
||
impl ClientState for AnyClientState { | ||
fn chain_id(&self) -> String { | ||
todo!() | ||
} | ||
|
||
fn client_type(&self) -> ClientType { | ||
todo!() | ||
} | ||
|
||
fn get_latest_height(&self) -> Height { | ||
match self { | ||
AnyClientState::Tendermint(tm_state) => tm_state.get_latest_height(), | ||
AnyClientState::Mock(mock_state) => mock_state.get_latest_height(), | ||
} | ||
} | ||
|
||
fn is_frozen(&self) -> bool { | ||
todo!() | ||
} | ||
|
||
fn verify_client_consensus_state( | ||
&self, | ||
_root: &CommitmentRoot, | ||
) -> Result<(), Box<dyn std::error::Error>> { | ||
todo!() | ||
} | ||
} | ||
|
||
#[derive(Clone, Debug, PartialEq)] | ||
pub enum AnyConsensusState { | ||
Mock(mocks::MockConsensusState), | ||
Tendermint(crate::ics07_tendermint::consensus_state::ConsensusState), | ||
} | ||
|
||
impl ConsensusState for AnyConsensusState { | ||
fn client_type(&self) -> ClientType { | ||
todo!() | ||
} | ||
|
||
fn height(&self) -> Height { | ||
todo!() | ||
} | ||
|
||
fn root(&self) -> &CommitmentRoot { | ||
todo!() | ||
} | ||
|
||
fn validate_basic(&self) -> Result<(), Box<dyn std::error::Error>> { | ||
todo!() | ||
} | ||
} | ||
|
||
#[derive(Clone, Debug, PartialEq, Eq)] | ||
pub enum AnyClient { | ||
Mock(mocks::MockClient), | ||
Tendermint(TendermintClient), | ||
} | ||
|
||
impl ClientDef for AnyClient { | ||
type Header = AnyHeader; | ||
type ClientState = AnyClientState; | ||
type ConsensusState = AnyConsensusState; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
#![allow(unused_imports)] | ||
|
||
use crate::handler::{Event, EventType, HandlerOutput}; | ||
use crate::ics02_client::client_def::{AnyClient, AnyClientState, AnyConsensusState, ClientDef}; | ||
use crate::ics02_client::client_type::ClientType; | ||
use crate::ics02_client::error::Error; | ||
use crate::ics02_client::msgs::{MsgCreateAnyClient, MsgUpdateAnyClient}; | ||
use crate::ics02_client::state::{ClientState, ConsensusState}; | ||
use crate::ics24_host::identifier::ClientId; | ||
|
||
use crate::Height; | ||
|
||
pub mod create_client; | ||
pub mod update_client; | ||
|
||
pub trait ClientReader { | ||
fn client_type(&self, client_id: &ClientId) -> Option<ClientType>; | ||
fn client_state(&self, client_id: &ClientId) -> Option<AnyClientState>; | ||
fn consensus_state(&self, client_id: &ClientId, height: Height) -> Option<AnyConsensusState>; | ||
} | ||
|
||
pub trait ClientKeeper { | ||
fn store_client_type( | ||
&mut self, | ||
client_id: ClientId, | ||
client_type: ClientType, | ||
) -> Result<(), Error>; | ||
|
||
fn store_client_state( | ||
&mut self, | ||
client_id: ClientId, | ||
client_state: AnyClientState, | ||
) -> Result<(), Error>; | ||
|
||
fn store_consensus_state( | ||
&mut self, | ||
client_id: ClientId, | ||
consensus_state: AnyConsensusState, | ||
) -> Result<(), Error>; | ||
} | ||
|
||
#[derive(Clone, Debug, PartialEq, Eq)] | ||
pub enum ClientEvent { | ||
ClientCreated(ClientId), | ||
ClientUpdated(ClientId), | ||
} | ||
|
||
impl From<ClientEvent> for Event { | ||
fn from(ce: ClientEvent) -> Event { | ||
match ce { | ||
ClientEvent::ClientCreated(client_id) => Event::new( | ||
EventType::Custom("ClientCreated".to_string()), | ||
vec![("client_id".to_string(), client_id.to_string())], | ||
), | ||
ClientEvent::ClientUpdated(client_id) => Event::new( | ||
EventType::Custom("ClientUpdated".to_string()), | ||
vec![("client_id".to_string(), client_id.to_string())], | ||
), | ||
} | ||
} | ||
} | ||
|
||
pub enum ClientMsg<CD: ClientDef> { | ||
CreateClient(MsgCreateAnyClient<CD>), | ||
UpdateClient(MsgUpdateAnyClient<CD>), | ||
} | ||
|
||
pub fn dispatch<Ctx>(ctx: &mut Ctx, msg: ClientMsg<AnyClient>) -> Result<HandlerOutput<()>, Error> | ||
where | ||
Ctx: ClientReader + ClientKeeper, | ||
{ | ||
match msg { | ||
ClientMsg::CreateClient(msg) => { | ||
let HandlerOutput { | ||
result, | ||
log, | ||
events, | ||
} = create_client::process(ctx, msg)?; | ||
|
||
create_client::keep(ctx, result)?; | ||
|
||
Ok(HandlerOutput::builder() | ||
.with_log(log) | ||
.with_events(events) | ||
.with_result(())) | ||
} | ||
ClientMsg::UpdateClient(msg) => { | ||
let HandlerOutput { | ||
result, | ||
log, | ||
events, | ||
} = update_client::process(ctx, msg)?; | ||
|
||
update_client::keep(ctx, result)?; | ||
|
||
Ok(HandlerOutput::builder() | ||
.with_log(log) | ||
.with_events(events) | ||
.with_result(())) | ||
} | ||
} | ||
} |
Oops, something went wrong.