Skip to content

Commit

Permalink
governance: add actions to freeze/thaw ibc clients (#3403)
Browse files Browse the repository at this point in the history
Co-authored-by: erwanor <[email protected]>
  • Loading branch information
zbuc and erwanor authored Jan 5, 2024
1 parent abe8585 commit 239096f
Show file tree
Hide file tree
Showing 13 changed files with 964 additions and 441 deletions.
21 changes: 11 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file modified crates/cnidarium/src/gen/proto_descriptor.bin.no_lfs
Binary file not shown.
27 changes: 27 additions & 0 deletions crates/core/app/src/action_handler/actions/submit.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::str::FromStr;
use std::sync::Arc;

use anyhow::{Context, Result};
Expand All @@ -6,10 +7,12 @@ use async_trait::async_trait;
use cnidarium::{StateDelta, StateRead, StateWrite};
use decaf377::Fq;
use decaf377_rdsa::{VerificationKey, VerificationKeyBytes};
use ibc_types::core::client::ClientId;
use once_cell::sync::Lazy;
use penumbra_asset::STAKING_TOKEN_DENOM;
use penumbra_chain::component::StateReadExt as _;
use penumbra_community_pool::component::StateReadExt as _;
use penumbra_ibc::component::ClientStateReadExt;
use penumbra_keys::keys::{FullViewingKey, NullifierKey};
use penumbra_proto::DomainType;
use penumbra_sct::component::StateReadExt as _;
Expand Down Expand Up @@ -133,6 +136,14 @@ impl ActionHandler for ProposalSubmit {
}
}
UpgradePlan { .. } => {}
FreezeIbcClient { client_id } => {
let _ = &ClientId::from_str(client_id)
.context("can't decode client id from IBC proposal")?;
}
UnfreezeIbcClient { client_id } => {
let _ = &ClientId::from_str(client_id)
.context("can't decode client id from IBC proposal")?;
}
}

Ok(())
Expand Down Expand Up @@ -203,6 +214,22 @@ impl ActionHandler for ProposalSubmit {
ProposalPayload::UpgradePlan { .. } => {
// TODO(erwan): no stateful checks for upgrade plan.
}
ProposalPayload::FreezeIbcClient { client_id } => {
// Check that the client ID is valid and that there is a corresponding
// client state. If the client state is already frozen, then freezing it
// is a no-op.
let client_id = &ClientId::from_str(client_id)
.map_err(|e| tonic::Status::aborted(format!("invalid client id: {e}")))?;
let _ = state.get_client_state(client_id).await?;
}
ProposalPayload::UnfreezeIbcClient { client_id } => {
// Check that the client ID is valid and that there is a corresponding
// client state. If the client state is not frozen, then unfreezing it
// is a no-op.
let client_id = &ClientId::from_str(client_id)
.map_err(|e| tonic::Status::aborted(format!("invalid client id: {e}")))?;
let _ = state.get_client_state(client_id).await?;
}
}

Ok(())
Expand Down
3 changes: 2 additions & 1 deletion crates/core/component/governance/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ component = [
]
# proving-keys = ["penumbra-proof-params/proving-keys"]
default = ["std", "component"]
std = ["ark-ff/std"]
std = ["ark-ff/std", "ibc-types/std"]
parallel = [
"penumbra-tct/parallel",
"ark-ff/parallel",
Expand Down Expand Up @@ -78,6 +78,7 @@ futures = "0.3"
pbjson-types = "0.6"
once_cell = "1.8"
rand_chacha = "0.3"
ibc-types = { version = "0.11.0", default-features = false }

# Component dependencies
tokio = { version = "1.21.1", features = ["full", "tracing"], optional = true }
Expand Down
23 changes: 21 additions & 2 deletions crates/core/component/governance/src/component/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ use anyhow::{Context, Result};
use async_trait::async_trait;
use cnidarium::{StateRead, StateWrite};
use futures::StreamExt;
use ibc_types::core::client::ClientId;
use penumbra_asset::{asset, Value, STAKING_TOKEN_DENOM};
use penumbra_chain::component::{StateReadExt as _, StateWriteExt as _};
use penumbra_ibc::component::ClientStateReadExt as _;
use penumbra_ibc::component::ClientStateWriteExt as _;
use penumbra_num::Amount;
use penumbra_proto::{StateReadProto, StateWriteProto};
use penumbra_sct::{component::StateReadExt as _, Nullifier};
Expand Down Expand Up @@ -558,7 +561,7 @@ pub trait StateReadExt: StateRead + penumbra_stake::StateReadExt {
impl<T: StateRead + penumbra_stake::StateReadExt + ?Sized> StateReadExt for T {}

#[async_trait]
pub trait StateWriteExt: StateWrite {
pub trait StateWriteExt: StateWrite + penumbra_ibc::component::ConnectionStateWriteExt {
/// Writes the provided governance parameters to the JMT.
fn put_governance_params(&mut self, params: GovernanceParameters) {
// Note that the governance params have been updated:
Expand Down Expand Up @@ -875,8 +878,24 @@ pub trait StateWriteExt: StateWrite {
tracing::info!(target_height = height, "upgrade plan proposal passed");
self.signal_upgrade(*height).await?;
}
}
ProposalPayload::FreezeIbcClient { client_id } => {
let client_id = &ClientId::from_str(client_id)
.map_err(|e| tonic::Status::aborted(format!("invalid client id: {e}")))?;
let client_state = self.get_client_state(client_id).await?;
let client_height = client_state.latest_height();

let frozen_client = client_state.with_frozen_height(client_height);
self.put_client(client_id, frozen_client);
}
ProposalPayload::UnfreezeIbcClient { client_id } => {
let client_id = &ClientId::from_str(client_id)
.map_err(|e| tonic::Status::aborted(format!("invalid client id: {e}")))?;
let client_state = self.get_client_state(client_id).await?;

let unfrozen_client = client_state.unfrozen();
self.put_client(client_id, unfrozen_client);
}
}
Ok(Ok(()))
}

Expand Down
46 changes: 46 additions & 0 deletions crates/core/component/governance/src/proposal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,16 @@ impl From<Proposal> for pb::Proposal {
ProposalPayload::UpgradePlan { height } => {
proposal.upgrade_plan = Some(pb::proposal::UpgradePlan { height });
}
ProposalPayload::FreezeIbcClient { client_id } => {
proposal.freeze_ibc_client = Some(pb::proposal::FreezeIbcClient {
client_id: client_id.into(),
});
}
ProposalPayload::UnfreezeIbcClient { client_id } => {
proposal.unfreeze_ibc_client = Some(pb::proposal::UnfreezeIbcClient {
client_id: client_id.into(),
});
}
}
proposal
}
Expand Down Expand Up @@ -202,6 +212,12 @@ pub enum ProposalKind {
/// An upgrade proposal.
#[cfg_attr(feature = "clap", clap(display_order = 500))]
UpgradePlan,
/// A proposal to freeze an IBC client.
#[cfg_attr(feature = "clap", clap(display_order = 600))]
FreezeIbcClient,
/// A proposal to unfreeze an IBC client.
#[cfg_attr(feature = "clap", clap(display_order = 700))]
UnfreezeIbcClient,
}

impl FromStr for ProposalKind {
Expand All @@ -228,6 +244,8 @@ impl Proposal {
ProposalPayload::ParameterChange { .. } => ProposalKind::ParameterChange,
ProposalPayload::CommunityPoolSpend { .. } => ProposalKind::CommunityPoolSpend,
ProposalPayload::UpgradePlan { .. } => ProposalKind::UpgradePlan,
ProposalPayload::FreezeIbcClient { .. } => ProposalKind::FreezeIbcClient,
ProposalPayload::UnfreezeIbcClient { .. } => ProposalKind::UnfreezeIbcClient,
}
}
}
Expand Down Expand Up @@ -276,6 +294,16 @@ pub enum ProposalPayload {
/// An upgrade plan proposal describes a planned upgrade to the chain. If ratified, the chain
/// will halt at the specified height, trigger an epoch transition, and halt the chain.
UpgradePlan { height: u64 },
/// A proposal to freeze a specific IBC client.
FreezeIbcClient {
/// The identifier of the client to freeze.
client_id: String,
},
/// A proposal to unfreeze a specific IBC client.
UnfreezeIbcClient {
/// The identifier of the client to unfreeze.
client_id: String,
},
}

/// A TOML-serializable version of `ProposalPayload`, meant for human consumption.
Expand All @@ -298,6 +326,12 @@ pub enum ProposalPayloadToml {
UpgradePlan {
height: u64,
},
FreezeIbcClient {
client_id: String,
},
UnfreezeIbcClient {
client_id: String,
},
}

impl TryFrom<ProposalPayloadToml> for ProposalPayload {
Expand Down Expand Up @@ -325,6 +359,12 @@ impl TryFrom<ProposalPayloadToml> for ProposalPayload {
}
}
ProposalPayloadToml::UpgradePlan { height } => ProposalPayload::UpgradePlan { height },
ProposalPayloadToml::FreezeIbcClient { client_id } => {
ProposalPayload::FreezeIbcClient { client_id }
}
ProposalPayloadToml::UnfreezeIbcClient { client_id } => {
ProposalPayload::UnfreezeIbcClient { client_id }
}
})
}
}
Expand All @@ -348,6 +388,12 @@ impl From<ProposalPayload> for ProposalPayloadToml {
}
}
ProposalPayload::UpgradePlan { height } => ProposalPayloadToml::UpgradePlan { height },
ProposalPayload::FreezeIbcClient { client_id } => {
ProposalPayloadToml::FreezeIbcClient { client_id }
}
ProposalPayload::UnfreezeIbcClient { client_id } => {
ProposalPayloadToml::UnfreezeIbcClient { client_id }
}
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions crates/core/component/ibc/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ use msg_handler::MsgHandler;
pub use self::metrics::register_metrics;
pub use channel::StateReadExt as ChannelStateReadExt;
pub use client::StateReadExt as ClientStateReadExt;
pub use client::StateWriteExt as ClientStateWriteExt;
pub use connection::StateReadExt as ConnectionStateReadExt;
pub use connection::StateWriteExt as ConnectionStateWriteExt;
pub use view::{StateReadExt, StateWriteExt};

pub use ibc_component::IBCComponent;
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use async_trait::async_trait;

use ibc_proto::ibc::core::client;
use ibc_proto::ibc::core::client::v1::{Height, IdentifiedClientState};
use ibc_proto::ibc::core::connection::v1::query_server::Query as ConnectionQuery;
use ibc_proto::ibc::core::connection::v1::{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,10 @@ pub struct Proposal {
pub community_pool_spend: ::core::option::Option<proposal::CommunityPoolSpend>,
#[prost(message, optional, tag = "9")]
pub upgrade_plan: ::core::option::Option<proposal::UpgradePlan>,
#[prost(message, optional, tag = "10")]
pub freeze_ibc_client: ::core::option::Option<proposal::FreezeIbcClient>,
#[prost(message, optional, tag = "11")]
pub unfreeze_ibc_client: ::core::option::Option<proposal::UnfreezeIbcClient>,
}
/// Nested message and enum types in `Proposal`.
pub mod proposal {
Expand Down Expand Up @@ -776,6 +780,38 @@ pub mod proposal {
)
}
}
/// Freeze an existing IBC client.
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct FreezeIbcClient {
#[prost(string, tag = "1")]
pub client_id: ::prost::alloc::string::String,
}
impl ::prost::Name for FreezeIbcClient {
const NAME: &'static str = "FreezeIbcClient";
const PACKAGE: &'static str = "penumbra.core.component.governance.v1alpha1";
fn full_name() -> ::prost::alloc::string::String {
::prost::alloc::format!(
"penumbra.core.component.governance.v1alpha1.Proposal.{}", Self::NAME
)
}
}
/// Unfreeze an existing IBC client.
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct UnfreezeIbcClient {
#[prost(string, tag = "1")]
pub client_id: ::prost::alloc::string::String,
}
impl ::prost::Name for UnfreezeIbcClient {
const NAME: &'static str = "UnfreezeIbcClient";
const PACKAGE: &'static str = "penumbra.core.component.governance.v1alpha1";
fn full_name() -> ::prost::alloc::string::String {
::prost::alloc::format!(
"penumbra.core.component.governance.v1alpha1.Proposal.{}", Self::NAME
)
}
}
}
impl ::prost::Name for Proposal {
const NAME: &'static str = "Proposal";
Expand Down
Loading

0 comments on commit 239096f

Please sign in to comment.