Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

create custom rollkit ClientState type #22

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
309 changes: 79 additions & 230 deletions Cargo.lock

Large diffs are not rendered by default.

24 changes: 11 additions & 13 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,16 @@ optimize = """docker run --rm -v "$(pwd)":/code \

[dependencies]
base64 = "0.22.0"
cosmwasm-schema = "1.5.2"
cosmwasm-std = "1.5.2"
ibc-core = { git = "https://github.com/cosmos/ibc-rs.git", rev = "80b8084", default-features = false, features = ["schema"] }
ibc-client-tendermint = { git = "https://github.com/cosmos/ibc-rs.git", rev = "80b8084", default-features = false, features = ["schema"] }
ibc-client-cw = {git = "https://github.com/cosmos/ibc-rs.git", rev = "80b8084", default-features = false }
ibc-proto = { version = "0.42.2", default-features = false }
prost = "0.12.3"
tendermint = "0.34.1"
tendermint-light-client-verifier = "0.34.1"
cosmwasm-schema = "1.5.4"
cosmwasm-std = "1.5.4"
ibc-core = { git = "https://github.com/cosmos/ibc-rs.git", rev = "4ea4dcb", default-features = false, features = ["schema"] }
ibc-core-host = { git = "https://github.com/cosmos/ibc-rs.git", rev = "4ea4dcb", default-features = false, features = ["schema"] }
ibc-client-tendermint = { git = "https://github.com/cosmos/ibc-rs.git", rev = "4ea4dcb", default-features = false, features = ["schema"] }
ibc-client-cw = { git = "https://github.com/cosmos/ibc-rs.git", rev = "4ea4dcb", default-features = false }
ibc-proto = { version = "0.44.0", default-features = false }
prost = "0.12.4"
tendermint = "0.36.0"
tendermint-light-client-verifier = "0.36.0"

[patch.crates-io]
ibc-proto = { git = "https://github.com/cosmos/ibc-proto-rs.git", rev = "6cbe4c7ace5a688bc98831fa9c1cc2dabf3b2976", default-features = false } # "0.42.2"

[dev-dependencies]
cw-multi-test = "2.0.0"
ibc-proto = { git = "https://github.com/cosmos/ibc-proto-rs.git", rev = "a70f7e9cc896c1a707a907e09ec340771a50c326", default-features = false } # "0.42.2"
23 changes: 21 additions & 2 deletions proto/ibc/lightclients/rollkit/v1/rollkit.proto
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,27 @@ package ibc.lightclients.rollkit.v1;
import "gogoproto/gogo.proto";
import "ibc/lightclients/tendermint/v1/tendermint.proto";

// ClientState defines a Rollkit rollup client that tracks the
// consensus state of the counterparty rollup.
message ClientState {
ibc.lightclients.tendermint.v1.ClientState tendermint_client_state = 1 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "yaml:\"tendermint_client_state\""
];
DaParams da_params = 2 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "yaml:\"da_params\""
];
}

// DaParams defines the data-availability related parameters of a Rollkit rollup light client.
message DaParams {
// client ID of the DA light client
string client_id = 1;
// fraud dispute period window in nanoseconds
uint64 fraud_period_window = 2;
}

// Header defines the structure of the header for Rollkit light clients
// operating on a Data Availability layer. It encapsulates all the information
// necessary to update a client from a trusted Rollkit rollup ConsensusState.
Expand All @@ -30,8 +51,6 @@ message Header {
// DaData defines the information needed by Rollkit rollup light
// client to query the VerifyMembership RPC of the DA light client.
message DaData {
// client ID of the DA light client
string client_id = 1;
// the proof of inclusion of Rollkit rollup block data in DA block
bytes shared_proof = 2;
}
19 changes: 4 additions & 15 deletions src/types/da_data.rs → src/client_message/da_data.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
use base64::engine::general_purpose;
use base64::Engine;
use core::fmt::{Debug, Display, Error as FmtError, Formatter};
use core::str::FromStr;

use ibc_core::host::types::identifiers::ClientId;
use ibc_core::primitives::proto::Protobuf;
use ibc_proto::ibc::lightclients::rollkit::v1::DaData as RawDaData;

use crate::types::Error;

#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
/// Tendermint consensus header
#[derive(Clone, PartialEq, Eq)]
pub struct DaData {
pub client_id: ClientId,
pub shared_proof: Vec<u8>,
}

Expand All @@ -27,19 +23,15 @@ impl Display for DaData {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
write!(
f,
"DaData {{ client_id: {}, shared_proof: {} }}",
&self.client_id,
"DaData {{ shared_proof: {} }}",
&general_purpose::STANDARD.encode(&self.shared_proof)
)
}
}

impl DaData {
pub fn new(client_id: ClientId, shared_proof: Vec<u8>) -> Self {
Self {
client_id,
shared_proof,
}
pub fn new(shared_proof: Vec<u8>) -> Self {
Self { shared_proof }
}
}

Expand All @@ -49,16 +41,13 @@ impl TryFrom<RawDaData> for DaData {
type Error = Error;

fn try_from(raw: RawDaData) -> Result<Self, Self::Error> {
let client_id = ClientId::from_str(&raw.client_id).map_err(Error::source)?;

Ok(Self::new(client_id, raw.shared_proof))
Ok(Self::new(raw.shared_proof))
}
}

impl From<DaData> for RawDaData {
fn from(value: DaData) -> Self {
Self {
client_id: value.client_id.to_string(),
shared_proof: value.shared_proof,
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ use ibc_client_tendermint::types::TENDERMINT_MISBEHAVIOUR_TYPE_URL;
use ibc_core::primitives::proto::{Any, Protobuf};
use prost::Message;

use crate::types::{Error, Header, ROLLKIT_HEADER_TYPE_URL};
use crate::client_message::header::{Header, ROLLKIT_HEADER_TYPE_URL};
use crate::types::Error;

/// Defines the union ClientMessage type allowing to submit all possible
/// messages for updating clients or reporting misbehaviour.
Expand Down
2 changes: 1 addition & 1 deletion src/types/header.rs → src/client_message/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use ibc_proto::ibc::lightclients::rollkit::v1::Header as RawRollkitHeader;
use tendermint::crypto::Sha256;
use tendermint::merkle::MerkleHash;

use crate::types::DaData;
use crate::client_message::da_data::DaData;
use crate::types::Error;

pub const ROLLKIT_HEADER_TYPE_URL: &str = "/ibc.lightclients.rollkit.v1.Header";
Expand Down
5 changes: 5 additions & 0 deletions src/client_message/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
mod da_data;
mod definition;
mod header;

pub use header::*;
191 changes: 191 additions & 0 deletions src/client_state/common.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
use ibc_client_tendermint::consensus_state::ConsensusState as TendermintConsensusState;
use ibc_core::client::context::client_state::ClientStateCommon;
use ibc_core::client::types::error::{ClientError, UpgradeClientError};

use ibc_core::client::types::Height;
use ibc_core::commitment_types::commitment::{
CommitmentPrefix, CommitmentProofBytes, CommitmentRoot,
};
use ibc_core::host::types::identifiers::ClientType;
use ibc_core::host::types::path::{Path, UpgradeClientPath};
use ibc_core::primitives::proto::Any;
use ibc_core::primitives::ToVec;

use crate::client_state::{rollkit_client_type, ClientState};

impl ClientStateCommon for ClientState {
fn verify_consensus_state(&self, consensus_state: Any) -> Result<(), ClientError> {
self.tendermint_client_state
.verify_consensus_state(consensus_state)
}

fn client_type(&self) -> ClientType {
rollkit_client_type()
}

fn latest_height(&self) -> Height {
self.tendermint_client_state.inner().latest_height
}

fn validate_proof_height(&self, proof_height: Height) -> Result<(), ClientError> {
self.tendermint_client_state
.validate_proof_height(proof_height)
}

fn verify_upgrade_client(
&self,
upgraded_client_state: Any,
upgraded_consensus_state: Any,
proof_upgrade_client: CommitmentProofBytes,
proof_upgrade_consensus_state: CommitmentProofBytes,
root: &CommitmentRoot,
) -> Result<(), ClientError> {
verify_upgrade_client(
self,
upgraded_client_state,
upgraded_consensus_state,
proof_upgrade_client,
proof_upgrade_consensus_state,
root,
)
}

fn verify_membership(
&self,
prefix: &CommitmentPrefix,
proof: &CommitmentProofBytes,
root: &CommitmentRoot,
path: Path,
value: Vec<u8>,
) -> Result<(), ClientError> {
verify_membership(self, prefix, proof, root, path, value)
}

fn verify_non_membership(
&self,
prefix: &CommitmentPrefix,
proof: &CommitmentProofBytes,
root: &CommitmentRoot,
path: Path,
) -> Result<(), ClientError> {
verify_non_membership(self, prefix, proof, root, path)
}
}

/// Perform client-specific verifications and check all data in the new
/// client state to be the same across all valid Rollkit clients for the
/// new chain.
///
/// You can learn more about how to upgrade IBC-connected SDK chains in
/// [this](https://ibc.cosmos.network/main/ibc/upgrades/quick-guide.html)
/// guide.
///
/// Note that this function is typically implemented as part of the
/// [`ClientStateCommon`] trait, but has been made a standalone function
/// in order to make the ClientState APIs more flexible.
pub fn verify_upgrade_client(
client_state: &ClientState,
upgraded_client_state: Any,
upgraded_consensus_state: Any,
proof_upgrade_client: CommitmentProofBytes,
proof_upgrade_consensus_state: CommitmentProofBytes,
root: &CommitmentRoot,
) -> Result<(), ClientError> {
// TODO: is it ok that the chain commits a rollkit client state? Or is it better to let the chain commit a tendermint client state?

// Make sure that the client type is of Rollkit type `ClientState`
let upgraded_rollkit_client_state = ClientState::try_from(upgraded_client_state.clone())?;

// Make sure that the consensus type is of Tendermint type `ConsensusState`
TendermintConsensusState::try_from(upgraded_consensus_state.clone())?;

let latest_height = client_state.latest_height();
let upgraded_client_state_height = upgraded_rollkit_client_state.latest_height();

// Make sure the latest height of the current client is not greater then
// the upgrade height This condition checks both the revision number and
// the height
if latest_height >= upgraded_client_state_height {
Err(UpgradeClientError::LowUpgradeHeight {
upgraded_height: latest_height,
client_height: upgraded_client_state_height,
})?
}

// TODO: is it ok if we use the upgrade path from the tendermint client state?
// TODO: is it ok that in the tendermint upgrade path the chain commits to a rollkit client state?
// Check to see if the upgrade path is set
let mut upgrade_path = client_state
.tendermint_client_state
.inner()
.upgrade_path
.clone();

if upgrade_path.pop().is_none() {
return Err(ClientError::ClientSpecific {
description: "cannot upgrade client as no upgrade path has been set".to_string(),
});
};

let upgrade_path_prefix = CommitmentPrefix::try_from(upgrade_path[0].clone().into_bytes())
.map_err(ClientError::InvalidCommitmentProof)?;

let last_height = latest_height.revision_height();

// Verify the proof of the upgraded client state
verify_membership(
client_state,
&upgrade_path_prefix,
&proof_upgrade_client,
root,
Path::UpgradeClient(UpgradeClientPath::UpgradedClientState(last_height)),
upgraded_client_state.to_vec(),
)?;

// Verify the proof of the upgraded consensus state
verify_membership(
client_state,
&upgrade_path_prefix,
&proof_upgrade_consensus_state,
root,
Path::UpgradeClient(UpgradeClientPath::UpgradedClientConsensusState(last_height)),
upgraded_consensus_state.to_vec(),
)?;

Ok(())
}

/// Verify membership of the given value against the client's merkle proof.
///
/// Note that this function is typically implemented as part of the
/// [`ClientStateCommon`] trait, but has been made a standalone function
/// in order to make the ClientState APIs more flexible.
pub fn verify_membership(
client_state: &ClientState,
prefix: &CommitmentPrefix,
proof: &CommitmentProofBytes,
root: &CommitmentRoot,
path: Path,
value: Vec<u8>,
) -> Result<(), ClientError> {
client_state
.tendermint_client_state
.verify_membership(prefix, proof, root, path, value)
}

/// Verify that the given value does not belong in the client's merkle proof.
///
/// Note that this function is typically implemented as part of the
/// [`ClientStateCommon`] trait, but has been made a standalone function
/// in order to make the ClientState APIs more flexible.
pub fn verify_non_membership(
client_state: &ClientState,
prefix: &CommitmentPrefix,
proof: &CommitmentProofBytes,
root: &CommitmentRoot,
path: Path,
) -> Result<(), ClientError> {
client_state
.tendermint_client_state
.verify_non_membership(prefix, proof, root, path)
}
Loading
Loading