-
Notifications
You must be signed in to change notification settings - Fork 92
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* StaticClientState * Static{Validation,Execution}Context * improve static clientstate & contexts * StaticTmClientState scaffold * tentative separation of `ClientState` * remove chain_id * move `zero_custom_fields()` * adjust comment * changelog * Remove methods from staticclientstate * static client state for tendermint WIP * `ClientStateValidation` for tendermint `ClientState` * `StaticClientStateExecution` tendermint * use static contexts in handlers * `StaticConsensusState` trait for tm `ConsensusState` * Move `MockClientRecord` to context file * mock: make records use enums instead of dyn * mock context works * bunch of errors fixed * fix tm consensus state * clippy * fix todos * use derive_more * Remove old types * Remove old `ClientState` * move things around * Rename tendermint's ClientState * Rename ValidationContext * Rename ExecutionContext * rename ClientState traits * fix doc * Rename ConsensusState * ClientState derive macro scaffold * macro improvements + test setup * fmt * remove ibc dev-dependency * implement validate_proof_height * fix previous merge from main * crate-level `allow(non_snake_case)` * `Imports` struct * move ClientStateBase impl to a module * extern crate trick * outdated comments * latest_height * implement more `ClientStateBase` methods * finish `ClientStateBase` impl * rustdoc ignore * comment line * introduce darling * ClientStateInitializer impl * export attribute * ClientStateInitializer done * fmt * add mock mode * use `ClientState` macro in tests * no long path * clippy rust 1.70 * remove useless cruft * comment * impl ClientStateValidation * use core::result::Result * ClientStateExecution impl in macro * Supported -> Any * host -> generics * rename derive macro attrs * Remove `PartialEq` from `ClientState` traits * Remove `Debug` supertrait from `ClientState` * Remove `Clone` requirement on `ClientState` traits * Remove `Send + Sync` from `ClientStateBase` * Remove `Debug + Clone` from `ConsensusState` * Remove `EncodeError` associated type (ConsensusState) * client-state-derive: move to submodule client_state * client-state-derive -> ibc-derive * `ConsensusState` macro * move `ClientState` re-export * Fix `ConsensusState` macro * add `ConsensuState` to ibc-derive-test * remove ibc-derive-test * Remove `ClientStateInitializer` * Finish removing `ClientStateInitializer` * docs * Remove `store_update_{height,time}` from `ExecutionContext` * Revert "Remove `store_update_{height,time}` from `ExecutionContext`" This reverts commit 282424f. * update client: store update time/height in core * create client: store update height/time in core * Remove store_update_time/height from Tm Client Execution context * remove `store_{client,consensus}_state` from `ExecutionContext` * docs * tm client: `context` module * Rename tm client types * Rename TmConsensusState * Remove `dyn-clone` dependency * Remove erased-serde dependency * Remove `ErasedPartialEq` from `Header` * ClientStateCommon * `ClientExecutionContext` trait * Complete ClientExecutionContext * Rename Host{Consensus,Client}State * Move `ClientExecutionContext` * Use `ContextError` in `ClientExecutionContext` methods * mock: remove stale time/height update * mock: clients submodule * mock: application impls submodule * mock context: file reorg * ClientExecutionContext docs * `ClientState` derive macro docs * `ConsensusState` docs * `ClientState` docstring * docs * Remove unused method * tm docs * core context traits docs * refine tm client's contexts * move `get_client_execution_context` * Move `verify_consensus_state` * Remove useless match in recv_packet * fix typo in `UpgradeValidationContext` * blanket impl for TmExecutionContext * ClientState derive macro: document generic limitation * Upgrade Contexts associated types * fix * add ClientType test * chore: organize import calls * changelog * Add `CommonContext::ConversionError` --------- Co-authored-by: Farhad Shabani <[email protected]>
- Loading branch information
1 parent
5ceaef3
commit cd3a266
Showing
58 changed files
with
2,052 additions
and
1,022 deletions.
There are no files selected for viewing
3 changes: 3 additions & 0 deletions
3
.changelog/unreleased/breaking-changes/296-static-clientstate.md
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,3 @@ | ||
- Implement ADR 7, where `ClientState` objects are now statically dispatched instead | ||
of dynamically dispatched. | ||
([#296](https://github.com/cosmos/ibc-rs/issues/296)) |
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 |
---|---|---|
|
@@ -4,8 +4,9 @@ resolver = "2" | |
|
||
members = [ | ||
"crates/ibc", | ||
"crates/ibc-derive", | ||
] | ||
|
||
exclude = [ | ||
"ci/no-std-check", | ||
] | ||
] |
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,13 @@ | ||
[package] | ||
name = "ibc-derive" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[lib] | ||
proc-macro = true | ||
|
||
[dependencies] | ||
syn = "2" | ||
proc-macro2 = "1" | ||
quote = "1" | ||
darling = "0.20" |
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,78 @@ | ||
mod traits; | ||
|
||
use darling::FromDeriveInput; | ||
use proc_macro2::TokenStream; | ||
use quote::quote; | ||
use syn::DeriveInput; | ||
|
||
use traits::{ | ||
client_state_common::impl_ClientStateCommon, client_state_execution::impl_ClientStateExecution, | ||
client_state_validation::impl_ClientStateValidation, | ||
}; | ||
|
||
#[derive(FromDeriveInput)] | ||
#[darling(attributes(generics))] | ||
pub(crate) struct Opts { | ||
#[darling(rename = "ClientValidationContext")] | ||
client_validation_context: syn::ExprPath, | ||
#[darling(rename = "ClientExecutionContext")] | ||
client_execution_context: syn::ExprPath, | ||
} | ||
|
||
pub fn client_state_derive_impl(ast: DeriveInput) -> TokenStream { | ||
let opts = match Opts::from_derive_input(&ast) { | ||
Ok(opts) => opts, | ||
Err(e) => panic!( | ||
"{} must be annotated with #[generics(ClientValidationContext = <your ClientValidationContext>, ClientExecutionContext: <your ClientExecutionContext>)]: {e}", | ||
ast.ident | ||
), | ||
}; | ||
|
||
let enum_name = &ast.ident; | ||
let enum_variants = match ast.data { | ||
syn::Data::Enum(ref enum_data) => &enum_data.variants, | ||
_ => panic!("ClientState only supports enums"), | ||
}; | ||
|
||
let ClientStateCommon_impl_block = impl_ClientStateCommon(enum_name, enum_variants); | ||
let ClientStateValidation_impl_block = | ||
impl_ClientStateValidation(enum_name, enum_variants, &opts); | ||
let ClientStateExecution_impl_block = | ||
impl_ClientStateExecution(enum_name, enum_variants, &opts); | ||
|
||
let maybe_extern_crate_stmt = if is_mock(&ast) { | ||
// Note: we must add this statement when in "mock mode" | ||
// (i.e. in ibc-rs itself) because we don't have `ibc` as a dependency, | ||
// so we need to define the `ibc` symbol to mean "the `self` crate". | ||
quote! {extern crate self as ibc;} | ||
} else { | ||
quote! {} | ||
}; | ||
|
||
quote! { | ||
#maybe_extern_crate_stmt | ||
|
||
#ClientStateCommon_impl_block | ||
#ClientStateValidation_impl_block | ||
#ClientStateExecution_impl_block | ||
} | ||
} | ||
|
||
/// We are in "mock mode" (i.e. within ibc-rs crate itself) if the user added | ||
/// a #[mock] attribute | ||
fn is_mock(ast: &DeriveInput) -> bool { | ||
for attr in &ast.attrs { | ||
let path = match attr.meta { | ||
syn::Meta::Path(ref path) => path, | ||
_ => continue, | ||
}; | ||
|
||
for path_segment in path.segments.iter() { | ||
if path_segment.ident == "mock" { | ||
return true; | ||
} | ||
} | ||
} | ||
|
||
false | ||
} |
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,5 @@ | ||
//! Hosts the code generation of the `impl`s for the `ClientState` traits | ||
pub mod client_state_common; | ||
pub mod client_state_execution; | ||
pub mod client_state_validation; |
197 changes: 197 additions & 0 deletions
197
crates/ibc-derive/src/client_state/traits/client_state_common.rs
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,197 @@ | ||
use proc_macro2::{Ident, TokenStream}; | ||
use quote::quote; | ||
use syn::{ | ||
punctuated::{Iter, Punctuated}, | ||
token::Comma, | ||
Variant, | ||
}; | ||
|
||
use crate::utils::{get_enum_variant_type_path, Imports}; | ||
|
||
pub(crate) fn impl_ClientStateCommon( | ||
client_state_enum_name: &Ident, | ||
enum_variants: &Punctuated<Variant, Comma>, | ||
) -> TokenStream { | ||
let verify_consensus_state_impl = delegate_call_in_match( | ||
client_state_enum_name, | ||
enum_variants.iter(), | ||
quote! { verify_consensus_state(cs, consensus_state) }, | ||
); | ||
let client_type_impl = delegate_call_in_match( | ||
client_state_enum_name, | ||
enum_variants.iter(), | ||
quote! {client_type(cs)}, | ||
); | ||
let latest_height_impl = delegate_call_in_match( | ||
client_state_enum_name, | ||
enum_variants.iter(), | ||
quote! {latest_height(cs)}, | ||
); | ||
let validate_proof_height_impl = delegate_call_in_match( | ||
client_state_enum_name, | ||
enum_variants.iter(), | ||
quote! {validate_proof_height(cs, proof_height)}, | ||
); | ||
let confirm_not_frozen_impl = delegate_call_in_match( | ||
client_state_enum_name, | ||
enum_variants.iter(), | ||
quote! {confirm_not_frozen(cs)}, | ||
); | ||
let expired_impl = delegate_call_in_match( | ||
client_state_enum_name, | ||
enum_variants.iter(), | ||
quote! {expired(cs, elapsed)}, | ||
); | ||
let verify_upgrade_client_impl = delegate_call_in_match( | ||
client_state_enum_name, | ||
enum_variants.iter(), | ||
quote! {verify_upgrade_client(cs, upgraded_client_state, upgraded_consensus_state, proof_upgrade_client, proof_upgrade_consensus_state, root)}, | ||
); | ||
let verify_membership_impl = delegate_call_in_match( | ||
client_state_enum_name, | ||
enum_variants.iter(), | ||
quote! {verify_membership(cs, prefix, proof, root, path, value)}, | ||
); | ||
let verify_non_membership_impl = delegate_call_in_match( | ||
client_state_enum_name, | ||
enum_variants.iter(), | ||
quote! {verify_non_membership(cs, prefix, proof, root, path)}, | ||
); | ||
|
||
let HostClientState = client_state_enum_name; | ||
|
||
let Any = Imports::Any(); | ||
let CommitmentRoot = Imports::CommitmentRoot(); | ||
let CommitmentPrefix = Imports::CommitmentPrefix(); | ||
let CommitmentProofBytes = Imports::CommitmentProofBytes(); | ||
let ClientStateCommon = Imports::ClientStateCommon(); | ||
let ClientType = Imports::ClientType(); | ||
let ClientError = Imports::ClientError(); | ||
let Height = Imports::Height(); | ||
let MerkleProof = Imports::MerkleProof(); | ||
let Path = Imports::Path(); | ||
|
||
quote! { | ||
impl #ClientStateCommon for #HostClientState { | ||
fn verify_consensus_state(&self, consensus_state: #Any) -> Result<(), #ClientError> { | ||
match self { | ||
#(#verify_consensus_state_impl),* | ||
} | ||
} | ||
fn client_type(&self) -> #ClientType { | ||
match self { | ||
#(#client_type_impl),* | ||
} | ||
} | ||
|
||
fn latest_height(&self) -> #Height { | ||
match self { | ||
#(#latest_height_impl),* | ||
} | ||
} | ||
|
||
fn validate_proof_height(&self, proof_height: #Height) -> core::result::Result<(), #ClientError> { | ||
match self { | ||
#(#validate_proof_height_impl),* | ||
} | ||
} | ||
|
||
fn confirm_not_frozen(&self) -> core::result::Result<(), #ClientError> { | ||
match self { | ||
#(#confirm_not_frozen_impl),* | ||
} | ||
} | ||
|
||
fn expired(&self, elapsed: core::time::Duration) -> bool { | ||
match self { | ||
#(#expired_impl),* | ||
} | ||
} | ||
|
||
fn verify_upgrade_client( | ||
&self, | ||
upgraded_client_state: #Any, | ||
upgraded_consensus_state: #Any, | ||
proof_upgrade_client: #MerkleProof, | ||
proof_upgrade_consensus_state: #MerkleProof, | ||
root: &#CommitmentRoot, | ||
) -> core::result::Result<(), #ClientError> { | ||
match self { | ||
#(#verify_upgrade_client_impl),* | ||
} | ||
} | ||
|
||
fn verify_membership( | ||
&self, | ||
prefix: &#CommitmentPrefix, | ||
proof: &#CommitmentProofBytes, | ||
root: &#CommitmentRoot, | ||
path: #Path, | ||
value: Vec<u8>, | ||
) -> core::result::Result<(), #ClientError> { | ||
match self { | ||
#(#verify_membership_impl),* | ||
} | ||
} | ||
|
||
fn verify_non_membership( | ||
&self, | ||
prefix: &#CommitmentPrefix, | ||
proof: &#CommitmentProofBytes, | ||
root: &#CommitmentRoot, | ||
path: #Path, | ||
) -> core::result::Result<(), #ClientError> { | ||
match self { | ||
#(#verify_non_membership_impl),* | ||
} | ||
} | ||
} | ||
|
||
} | ||
} | ||
|
||
/// | ||
/// Generates the per-enum variant function call delegation token streams. | ||
/// | ||
/// enum_name: The user's enum identifier (e.g. `HostClientState`) | ||
/// enum_variants: An iterator of all enum variants (e.g. `[HostClientState::Tendermint, HostClientState::Mock]`) | ||
/// fn_call: The tokens for the function call. Fully-qualified syntax is assumed, where the name for `self` | ||
/// is `cs` (e.g. `client_type(cs)`). | ||
/// | ||
/// For example, | ||
/// | ||
/// ```ignore | ||
/// impl ClientStateCommon for HostClientState { | ||
/// fn client_type(&self) -> ClientType { | ||
/// match self { | ||
/// // BEGIN code generated | ||
/// | ||
/// // 1st TokenStream returned | ||
/// HostClientState::Tendermint(cs) => <TmClientState as ClientStateCommon>::client_type(cs), | ||
/// // 2nd TokenStream returned | ||
/// HostClientState::Mock(cs) => <MockClientState as ClientStateCommon>::client_type(cs), | ||
/// | ||
/// // END code generated | ||
/// } | ||
/// } | ||
/// } | ||
/// ``` | ||
/// | ||
fn delegate_call_in_match( | ||
enum_name: &Ident, | ||
enum_variants: Iter<'_, Variant>, | ||
fn_call: TokenStream, | ||
) -> Vec<TokenStream> { | ||
let ClientStateCommon = Imports::ClientStateCommon(); | ||
|
||
enum_variants | ||
.map(|variant| { | ||
let variant_name = &variant.ident; | ||
let variant_type_name = get_enum_variant_type_path(variant); | ||
|
||
quote! { | ||
#enum_name::#variant_name(cs) => <#variant_type_name as #ClientStateCommon>::#fn_call | ||
} | ||
}) | ||
.collect() | ||
} |
Oops, something went wrong.