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

fix penumbra-specific timestamp reads in ibc module #4822

Merged
merged 8 commits into from
Aug 21, 2024
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
24 changes: 21 additions & 3 deletions crates/core/app/src/action_handler/actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,13 @@ impl AppActionHandler for Action {
.check_stateless(())
.await
}
Action::Ics20Withdrawal(action) => action.check_stateless(()).await,
Action::Ics20Withdrawal(action) => {
action
.clone()
.with_handler::<PenumbraHost>()
.check_stateless(())
.await
}
Action::CommunityPoolSpend(action) => action.check_stateless(()).await,
Action::CommunityPoolOutput(action) => action.check_stateless(()).await,
Action::CommunityPoolDeposit(action) => action.check_stateless(()).await,
Expand Down Expand Up @@ -78,7 +84,13 @@ impl AppActionHandler for Action {
.check_historical(state)
.await
}
Action::Ics20Withdrawal(action) => action.check_historical(state).await,
Action::Ics20Withdrawal(action) => {
action
.clone()
.with_handler::<PenumbraHost>()
.check_historical(state)
.await
}
Action::CommunityPoolSpend(action) => action.check_historical(state).await,
Action::CommunityPoolOutput(action) => action.check_historical(state).await,
Action::CommunityPoolDeposit(action) => action.check_historical(state).await,
Expand Down Expand Up @@ -113,7 +125,13 @@ impl AppActionHandler for Action {
.check_and_execute(state)
.await
}
Action::Ics20Withdrawal(action) => action.check_and_execute(state).await,
Action::Ics20Withdrawal(action) => {
action
.clone()
.with_handler::<PenumbraHost>()
.check_and_execute(state)
.await
}
Action::CommunityPoolSpend(action) => action.check_and_execute(state).await,
Action::CommunityPoolOutput(action) => action.check_and_execute(state).await,
Action::CommunityPoolDeposit(action) => action.check_and_execute(state).await,
Expand Down
2 changes: 1 addition & 1 deletion crates/core/app/src/penumbra_host_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use penumbra_sct::component::clock::EpochRead;

use crate::app::StateReadExt;

/// The implementation of [`penumbr_ibc::component::HostInterface`] for Penumbra.
/// The implementation of [`penumbra_ibc::component::HostInterface`] for Penumbra.
/// It encapsulates all of the chain-specific data that the ibc implementation needs.
#[derive(Clone)]
pub struct PenumbraHost {}
Expand Down
15 changes: 6 additions & 9 deletions crates/core/component/ibc/src/component/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ pub trait StateWriteExt: StateWrite + StateReadExt {
impl<T: StateWrite + ?Sized> StateWriteExt for T {}

#[async_trait]
pub trait StateReadExt: StateRead + penumbra_sct::component::clock::EpochRead {
pub trait StateReadExt: StateRead {
async fn client_counter(&self) -> Result<ClientCounter> {
self.get("ibc_client_counter")
.await
Expand All @@ -266,7 +266,11 @@ pub trait StateReadExt: StateRead + penumbra_sct::component::clock::EpochRead {
client_state.context(format!("could not find client state for {client_id}"))
}

async fn get_client_status(&self, client_id: &ClientId) -> ClientStatus {
async fn get_client_status(
&self,
client_id: &ClientId,
current_block_time: tendermint::Time,
) -> ClientStatus {
let client_type = self.get_client_type(client_id).await;

if client_type.is_err() {
Expand Down Expand Up @@ -303,13 +307,6 @@ pub trait StateReadExt: StateRead + penumbra_sct::component::clock::EpochRead {

let latest_consensus_state = latest_consensus_state.expect("latest consensus state is Ok");

let current_block_time = self.get_current_block_timestamp().await;

if current_block_time.is_err() {
return ClientStatus::Unknown;
}

let current_block_time = current_block_time.expect("current block time is Ok");
let time_elapsed = current_block_time.duration_since(latest_consensus_state.timestamp);
if time_elapsed.is_err() {
return ClientStatus::Unknown;
Expand Down
9 changes: 6 additions & 3 deletions crates/core/component/ibc/src/component/packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use ibc_types::core::{
channel::{channel::State as ChannelState, events, ChannelId, Packet, PortId},
client::Height,
};
use penumbra_sct::component::clock::EpochRead;
use tendermint::Time;

use crate::component::{
channel::{StateReadExt as _, StateWriteExt as _},
Expand Down Expand Up @@ -96,7 +96,11 @@ impl<S: CheckStatus> IBCPacket<S> {
#[async_trait]
pub trait SendPacketRead: StateRead {
/// send_packet_check verifies that a packet can be sent using the provided parameters.
async fn send_packet_check(&self, packet: IBCPacket<Unchecked>) -> Result<IBCPacket<Checked>> {
async fn send_packet_check(
&self,
packet: IBCPacket<Unchecked>,
current_block_time: Time,
) -> Result<IBCPacket<Checked>> {
let channel = self
.get_channel(&packet.source_channel, &packet.source_port)
.await?
Expand Down Expand Up @@ -134,7 +138,6 @@ pub trait SendPacketRead: StateRead {
.get_verified_consensus_state(&client_state.latest_height(), &connection.client_id)
.await?;

let current_block_time = self.get_current_block_timestamp().await?;
let time_elapsed = current_block_time.duration_since(latest_consensus_state.timestamp)?;

if client_state.expired(time_elapsed) {
Expand Down
6 changes: 4 additions & 2 deletions crates/core/component/ibc/src/component/rpc/client_query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,10 @@ impl<HI: HostInterface + Send + Sync + 'static> ClientQuery for IbcQuery<HI> {
let snapshot = self.storage.latest_snapshot();
let client_id = ClientId::from_str(&request.get_ref().client_id)
.map_err(|e| tonic::Status::invalid_argument(format!("invalid client id: {e}")))?;

let client_status = snapshot.get_client_status(&client_id).await;
let timestamp = HI::get_block_timestamp(snapshot.clone())
.await
.map_err(|e| tonic::Status::aborted(format!("couldn't get block timestamp: {e}")))?;
let client_status = snapshot.get_client_status(&client_id, timestamp).await;
let resp = QueryClientStatusResponse {
status: client_status.to_string(),
};
Expand Down
2 changes: 2 additions & 0 deletions crates/core/component/shielded-pool/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
mod action_handler;
mod assets;
mod fmd;
mod ics20_withdrawal_with_handler;
mod metrics;
mod note_manager;
mod shielded_pool;
Expand All @@ -11,6 +12,7 @@ mod transfer;
pub use self::metrics::register_metrics;
pub use assets::{AssetRegistry, AssetRegistryRead};
pub use fmd::ClueManager;
pub use ics20_withdrawal_with_handler::Ics20WithdrawalWithHandler;
pub use note_manager::NoteManager;
pub use shielded_pool::{ShieldedPool, StateReadExt, StateWriteExt};
pub use transfer::Ics20Transfer;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,18 @@
use std::sync::Arc;

use anyhow::{ensure, Result};
use async_trait::async_trait;
use cnidarium::{StateRead, StateWrite};
use cnidarium_component::ActionHandler;
use penumbra_ibc::StateReadExt as _;
use penumbra_ibc::{component::HostInterface, StateReadExt as _};

use crate::{
component::transfer::{Ics20TransferReadExt as _, Ics20TransferWriteExt as _},
Ics20Withdrawal,
};
use crate::component::transfer::{Ics20TransferReadExt as _, Ics20TransferWriteExt as _};
use crate::component::Ics20WithdrawalWithHandler;

#[async_trait]
impl ActionHandler for Ics20Withdrawal {
type CheckStatelessContext = ();
async fn check_stateless(&self, _context: ()) -> Result<()> {
self.validate()
impl<HI: HostInterface> Ics20WithdrawalWithHandler<HI> {
pub async fn check_stateless(&self, _context: ()) -> Result<()> {
self.action().validate()
}

async fn check_historical<S: StateRead + 'static>(&self, state: Arc<S>) -> Result<()> {
pub async fn check_historical<S: StateRead + 'static>(&self, state: Arc<S>) -> Result<()> {
ensure!(
state
.get_ibc_params()
Expand All @@ -29,8 +23,11 @@ impl ActionHandler for Ics20Withdrawal {
Ok(())
}

async fn check_and_execute<S: StateWrite>(&self, mut state: S) -> Result<()> {
state.withdrawal_check(self).await?;
state.withdrawal_execute(self).await
pub async fn check_and_execute<S: StateWrite>(&self, mut state: S) -> Result<()> {
let current_block_time = HI::get_block_timestamp(&state).await?;
state
.withdrawal_check(self.action(), current_block_time)
.await?;
state.withdrawal_execute(self.action()).await
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use crate::Ics20Withdrawal;
use penumbra_ibc::component::HostInterface;
use std::marker::PhantomData;

pub struct Ics20WithdrawalWithHandler<HI>(Ics20Withdrawal, PhantomData<HI>);

impl<HI> Ics20WithdrawalWithHandler<HI> {
pub fn new(action: Ics20Withdrawal) -> Self {
Self(action, PhantomData)
}

pub fn action(&self) -> &Ics20Withdrawal {
&self.0
}

pub fn into_inner(self) -> Ics20Withdrawal {
self.0
}
}

impl<HI> From<Ics20WithdrawalWithHandler<HI>> for Ics20Withdrawal {
fn from(value: Ics20WithdrawalWithHandler<HI>) -> Self {
value.0
}
}

impl Ics20Withdrawal {
pub fn with_handler<HI: HostInterface>(self) -> Ics20WithdrawalWithHandler<HI> {
Ics20WithdrawalWithHandler::new(self)
}
}
9 changes: 7 additions & 2 deletions crates/core/component/shielded-pool/src/component/transfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ use penumbra_ibc::component::{
},
state_key,
};
use tendermint::Time;

// returns a bool indicating if the provided denom was issued locally or if it was bridged in.
// this logic is a bit tricky, and adapted from https://github.com/cosmos/ibc/tree/main/spec/app/ics-020-fungible-token-transfer (sendFungibleTokens).
Expand Down Expand Up @@ -68,12 +69,16 @@ pub struct Ics20Transfer {}

#[async_trait]
pub trait Ics20TransferReadExt: StateRead {
async fn withdrawal_check(&self, withdrawal: &Ics20Withdrawal) -> Result<()> {
async fn withdrawal_check(
&self,
withdrawal: &Ics20Withdrawal,
current_block_time: Time,
) -> Result<()> {
// create packet
let packet: IBCPacket<Unchecked> = withdrawal.clone().into();

// send packet
self.send_packet_check(packet).await?;
self.send_packet_check(packet, current_block_time).await?;

Ok(())
}
Expand Down
Loading