Skip to content

Static ClientState API #683

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Merged
merged 137 commits into from
Jul 5, 2023
Merged
Changes from all commits
Commits
Show all changes
137 commits
Select commit Hold shift + click to select a range
c3b8585
StaticClientState
plafer May 17, 2023
167671a
Static{Validation,Execution}Context
plafer May 17, 2023
af1047a
improve static clientstate & contexts
plafer May 17, 2023
1c97a11
StaticTmClientState scaffold
plafer May 17, 2023
d0608e3
tentative separation of `ClientState`
plafer May 17, 2023
a521754
remove chain_id
plafer May 17, 2023
c4edfc2
move `zero_custom_fields()`
plafer May 17, 2023
d7fce36
adjust comment
plafer May 17, 2023
2e5a771
changelog
plafer May 17, 2023
3791150
Merge branch 'plafer/681-client-state-methods' into plafer/296-static…
plafer May 17, 2023
edd4212
Remove methods from staticclientstate
plafer May 17, 2023
93d797e
Merge branch 'main' into plafer/296-static-client-interface
plafer May 17, 2023
be379e7
static client state for tendermint WIP
plafer May 17, 2023
a54cae8
`ClientStateValidation` for tendermint `ClientState`
plafer May 17, 2023
212a3e0
`StaticClientStateExecution` tendermint
plafer May 22, 2023
0cfe195
use static contexts in handlers
plafer May 22, 2023
faed5df
`StaticConsensusState` trait for tm `ConsensusState`
plafer May 23, 2023
9a9b8bf
Move `MockClientRecord` to context file
plafer May 23, 2023
b039c80
mock: make records use enums instead of dyn
plafer May 23, 2023
e657f5e
mock context works
plafer May 23, 2023
cbc30f7
bunch of errors fixed
plafer May 24, 2023
500ee80
fix tm consensus state
plafer May 24, 2023
b385463
clippy
plafer May 24, 2023
e5740d0
fix todos
plafer May 24, 2023
b2845aa
use derive_more
plafer May 24, 2023
bfa224d
Remove old types
plafer May 24, 2023
1e18e9c
Remove old `ClientState`
plafer May 24, 2023
c72afe5
Merge branch 'main' into plafer/296-static-client-interface
plafer May 24, 2023
4f6e380
move things around
plafer May 24, 2023
28eace8
Rename tendermint's ClientState
plafer May 24, 2023
fd27485
Rename ValidationContext
plafer May 24, 2023
495df85
Rename ExecutionContext
plafer May 24, 2023
571d015
rename ClientState traits
plafer May 24, 2023
9f467f7
fix doc
plafer May 24, 2023
ed567fc
Rename ConsensusState
plafer May 24, 2023
480df9d
ClientState derive macro scaffold
plafer May 25, 2023
eff71a0
macro improvements + test setup
plafer May 25, 2023
9c7f6f2
fmt
plafer May 25, 2023
39c5b2e
Merge branch 'main' into plafer/296-static-client-interface
plafer May 31, 2023
0a74ba2
remove ibc dev-dependency
plafer May 31, 2023
a96c5fe
implement validate_proof_height
plafer May 31, 2023
863b6e6
fix previous merge from main
plafer May 31, 2023
c9cd76c
crate-level `allow(non_snake_case)`
plafer May 31, 2023
d123862
`Imports` struct
plafer May 31, 2023
b2add21
move ClientStateBase impl to a module
plafer May 31, 2023
8201719
extern crate trick
plafer May 31, 2023
e2e23a4
outdated comments
plafer May 31, 2023
a9693df
latest_height
plafer May 31, 2023
0f81045
implement more `ClientStateBase` methods
plafer May 31, 2023
82cdf0d
finish `ClientStateBase` impl
plafer May 31, 2023
3ba55ea
rustdoc ignore
plafer Jun 1, 2023
1f6451f
comment line
plafer Jun 1, 2023
5719170
introduce darling
plafer Jun 1, 2023
a862422
ClientStateInitializer impl
plafer Jun 1, 2023
28d3a94
export attribute
plafer Jun 1, 2023
7e62866
ClientStateInitializer done
plafer Jun 1, 2023
f7a86f0
fmt
plafer Jun 1, 2023
40dbeaf
add mock mode
plafer Jun 1, 2023
d893236
use `ClientState` macro in tests
plafer Jun 1, 2023
904bf90
no long path
plafer Jun 1, 2023
a77014e
clippy rust 1.70
plafer Jun 2, 2023
16357d9
remove useless cruft
plafer Jun 2, 2023
627cb1d
comment
plafer Jun 2, 2023
239d4db
impl ClientStateValidation
plafer Jun 2, 2023
881350b
use core::result::Result
plafer Jun 2, 2023
9bc3901
ClientStateExecution impl in macro
plafer Jun 2, 2023
e1b6511
Supported -> Any
plafer Jun 5, 2023
aae77cf
host -> generics
plafer Jun 5, 2023
0156495
rename derive macro attrs
plafer Jun 6, 2023
dc5f098
Remove `PartialEq` from `ClientState` traits
plafer Jun 7, 2023
227268d
Remove `Debug` supertrait from `ClientState`
plafer Jun 7, 2023
2cc3e52
Remove `Clone` requirement on `ClientState` traits
plafer Jun 7, 2023
979021e
Remove `Send + Sync` from `ClientStateBase`
plafer Jun 7, 2023
0451e88
Remove `Debug + Clone` from `ConsensusState`
plafer Jun 7, 2023
df3232e
Remove `EncodeError` associated type (ConsensusState)
plafer Jun 7, 2023
8b401ce
Merge branch 'main' into plafer/296-static-client-interface
plafer Jun 7, 2023
ce30126
client-state-derive: move to submodule client_state
plafer Jun 7, 2023
cc2f935
client-state-derive -> ibc-derive
plafer Jun 7, 2023
b9eefaa
`ConsensusState` macro
plafer Jun 7, 2023
7786374
move `ClientState` re-export
plafer Jun 7, 2023
8bd5749
Fix `ConsensusState` macro
plafer Jun 7, 2023
1da4dc8
add `ConsensuState` to ibc-derive-test
plafer Jun 7, 2023
9fc98c9
remove ibc-derive-test
plafer Jun 7, 2023
8a330a7
Remove `ClientStateInitializer`
plafer Jun 8, 2023
e222510
Finish removing `ClientStateInitializer`
plafer Jun 8, 2023
ce012c6
docs
plafer Jun 8, 2023
282424f
Remove `store_update_{height,time}` from `ExecutionContext`
plafer Jun 8, 2023
90ae6b1
Revert "Remove `store_update_{height,time}` from `ExecutionContext`"
plafer Jun 9, 2023
dcbfbee
update client: store update time/height in core
plafer Jun 9, 2023
6749be5
create client: store update height/time in core
plafer Jun 9, 2023
e24da68
Remove store_update_time/height from Tm Client Execution context
plafer Jun 9, 2023
71de518
remove `store_{client,consensus}_state` from `ExecutionContext`
plafer Jun 9, 2023
9686fc7
docs
plafer Jun 9, 2023
9c33e0e
tm client: `context` module
plafer Jun 9, 2023
1b29d0c
Rename tm client types
plafer Jun 9, 2023
76e38f6
Rename TmConsensusState
plafer Jun 9, 2023
29b57a7
Merge branch 'main' into plafer/296-static-client-interface
plafer Jun 12, 2023
66ac486
Merge branch 'main' into plafer/296-static-client-interface
plafer Jun 12, 2023
4d333ee
Remove `dyn-clone` dependency
plafer Jun 12, 2023
eec7b1a
Remove erased-serde dependency
plafer Jun 12, 2023
f517800
Remove `ErasedPartialEq` from `Header`
plafer Jun 12, 2023
078928d
ClientStateCommon
plafer Jun 12, 2023
bcba003
`ClientExecutionContext` trait
plafer Jun 13, 2023
8e2a117
Complete ClientExecutionContext
plafer Jun 13, 2023
4c7e989
Rename Host{Consensus,Client}State
plafer Jun 13, 2023
617f642
Move `ClientExecutionContext`
plafer Jun 13, 2023
011f0d0
Use `ContextError` in `ClientExecutionContext` methods
plafer Jun 13, 2023
db55dad
mock: remove stale time/height update
plafer Jun 13, 2023
5702b8d
mock: clients submodule
plafer Jun 13, 2023
edcd08c
mock: application impls submodule
plafer Jun 13, 2023
6318f37
mock context: file reorg
plafer Jun 13, 2023
a6dabe0
ClientExecutionContext docs
plafer Jun 13, 2023
5db8a59
`ClientState` derive macro docs
plafer Jun 13, 2023
b53b512
`ConsensusState` docs
plafer Jun 13, 2023
4cf3e1a
`ClientState` docstring
plafer Jun 13, 2023
0578c60
docs
plafer Jun 13, 2023
1d46026
Remove unused method
plafer Jun 13, 2023
1fbf824
tm docs
plafer Jun 13, 2023
437892a
core context traits docs
plafer Jun 13, 2023
7460356
refine tm client's contexts
plafer Jun 13, 2023
ce64959
move `get_client_execution_context`
plafer Jun 20, 2023
c1fcbf0
Merge branch 'main' into plafer/296-static-client-interface
plafer Jun 21, 2023
a157110
Move `verify_consensus_state`
plafer Jun 21, 2023
084fb86
Remove useless match in recv_packet
plafer Jun 22, 2023
8602543
Merge branch 'main' into plafer/296-static-client-interface
plafer Jun 26, 2023
996030d
fix typo in `UpgradeValidationContext`
plafer Jun 26, 2023
29142ed
blanket impl for TmExecutionContext
plafer Jun 26, 2023
58ac179
ClientState derive macro: document generic limitation
plafer Jun 26, 2023
fbd3ccc
Upgrade Contexts associated types
plafer Jun 26, 2023
e044556
fix
plafer Jun 26, 2023
7e921a4
Merge branch 'main' into plafer/296-static-client-interface
plafer Jun 26, 2023
934ad76
add ClientType test
plafer Jun 26, 2023
fcd45ba
Merge branch 'main' into plafer/296-static-client-interface
plafer Jun 28, 2023
9d2dc7b
chore: organize import calls
Farhad-Shabani Jun 28, 2023
bf69139
changelog
plafer Jun 28, 2023
0cb3657
Add `CommonContext::ConversionError`
plafer Jun 28, 2023
ee4e888
Merge branch 'main' into plafer/296-static-client-interface
plafer Jul 5, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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))
3 changes: 2 additions & 1 deletion Cargo.toml
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",
]
]
13 changes: 13 additions & 0 deletions crates/ibc-derive/Cargo.toml
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"
78 changes: 78 additions & 0 deletions crates/ibc-derive/src/client_state.rs
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
}
5 changes: 5 additions & 0 deletions crates/ibc-derive/src/client_state/traits.rs
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 crates/ibc-derive/src/client_state/traits/client_state_common.rs
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()
}
Loading