Skip to content

Commit

Permalink
refactoring: add trace.rs
Browse files Browse the repository at this point in the history
  • Loading branch information
yito88 committed Jun 20, 2024
1 parent 05c584a commit a51f3eb
Show file tree
Hide file tree
Showing 16 changed files with 49 additions and 189 deletions.
3 changes: 1 addition & 2 deletions crates/apps_lib/src/cli/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ use namada::core::chain::ChainId;
use namada::core::ethereum_events::EthAddress;
use namada::core::key::*;
use namada::core::masp::*;
use namada::ibc::{is_ibc_denom, is_nft_trace};
use namada::ibc::trace::{ibc_token, is_ibc_denom, is_nft_trace};
use namada::io::Io;
use namada::ledger::ibc::storage::ibc_token;
use namada_sdk::masp::fs::FsShieldedUtils;
use namada_sdk::masp::ShieldedContext;
use namada_sdk::wallet::Wallet;
Expand Down
4 changes: 2 additions & 2 deletions crates/ibc/src/context/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use sha2::Digest;

use super::client::{AnyClientState, AnyConsensusState};
use super::storage::IbcStorageContext;
use crate::{storage, NftClass, NftMetadata};
use crate::{storage, trace, NftClass, NftMetadata};

/// Result of IBC common function call
pub type Result<T> = std::result::Result<T, ContextError>;
Expand Down Expand Up @@ -716,7 +716,7 @@ pub trait IbcCommonContext: IbcStorageContext {
token_id: &TokenId,
owner: &Address,
) -> Result<bool> {
let ibc_token = storage::ibc_token_for_nft(class_id, token_id);
let ibc_token = trace::ibc_token_for_nft(class_id, token_id);
let balance_key = balance_key(&ibc_token, owner);
let amount = self.read::<Amount>(&balance_key)?;
Ok(amount == Some(Amount::from_u64(1)))
Expand Down
16 changes: 8 additions & 8 deletions crates/ibc/src/context/nft_transfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use namada_core::address::Address;
use namada_core::token::Amount;

use super::common::IbcCommonContext;
use crate::{storage, NftClass, NftMetadata, IBC_ESCROW_ADDRESS};
use crate::{trace, NftClass, NftMetadata, IBC_ESCROW_ADDRESS};

/// NFT transfer context to handle tokens
#[derive(Debug)]
Expand Down Expand Up @@ -95,8 +95,8 @@ where
class_id: &PrefixedClassId,
token_id: &TokenId,
) -> Result<(), NftTransferError> {
let ibc_trace = format!("{class_id}/{token_id}");
let trace_hash = storage::calc_hash(&ibc_trace);
let ibc_trace = trace::ibc_trace_for_nft(class_id, token_id);
let trace_hash = trace::calc_hash(&ibc_trace);

self.inner
.borrow_mut()
Expand Down Expand Up @@ -241,7 +241,7 @@ where
class_id: &PrefixedClassId,
token_id: &TokenId,
) -> Option<String> {
Some(storage::calc_hash(format!("{class_id}/{token_id}")))
Some(trace::calc_hash(format!("{class_id}/{token_id}")))
}

/// Returns the NFT
Expand Down Expand Up @@ -300,7 +300,7 @@ where
token_id: &TokenId,
_memo: &Memo,
) -> Result<(), NftTransferError> {
let ibc_token = storage::ibc_token_for_nft(class_id, token_id);
let ibc_token = trace::ibc_token_for_nft(class_id, token_id);

self.add_withdraw(&ibc_token)?;

Expand All @@ -324,7 +324,7 @@ where
class_id: &PrefixedClassId,
token_id: &TokenId,
) -> Result<(), NftTransferError> {
let ibc_token = storage::ibc_token_for_nft(class_id, token_id);
let ibc_token = trace::ibc_token_for_nft(class_id, token_id);

self.add_deposit(&ibc_token)?;

Expand All @@ -347,7 +347,7 @@ where
token_uri: Option<&TokenUri>,
token_data: Option<&TokenData>,
) -> Result<(), NftTransferError> {
let ibc_token = storage::ibc_token_for_nft(class_id, token_id);
let ibc_token = trace::ibc_token_for_nft(class_id, token_id);

// create or update the metadata
let metadata = NftMetadata {
Expand Down Expand Up @@ -378,7 +378,7 @@ where
token_id: &TokenId,
_memo: &Memo,
) -> Result<(), NftTransferError> {
let ibc_token = storage::ibc_token_for_nft(class_id, token_id);
let ibc_token = trace::ibc_token_for_nft(class_id, token_id);

self.update_mint_amount(&ibc_token, false)?;
self.add_withdraw(&ibc_token)?;
Expand Down
8 changes: 4 additions & 4 deletions crates/ibc/src/context/token_transfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use namada_core::uint::Uint;
use namada_token::Amount;

use super::common::IbcCommonContext;
use crate::{storage, IBC_ESCROW_ADDRESS};
use crate::{trace, IBC_ESCROW_ADDRESS};

/// Token transfer context to handle tokens
#[derive(Debug)]
Expand Down Expand Up @@ -54,7 +54,7 @@ where
) -> Result<(Address, Amount), TokenTransferError> {
let token = match Address::decode(coin.denom.base_denom.as_str()) {
Ok(token_addr) if coin.denom.trace_path.is_empty() => token_addr,
_ => storage::ibc_token(coin.denom.to_string()),
_ => trace::ibc_token(coin.denom.to_string()),
};

// Convert IBC amount to Namada amount for the token
Expand Down Expand Up @@ -146,7 +146,7 @@ where
return Ok(());
}
let ibc_denom = coin.denom.to_string();
let trace_hash = storage::calc_hash(&ibc_denom);
let trace_hash = trace::calc_hash(&ibc_denom);

self.inner
.borrow_mut()
Expand Down Expand Up @@ -224,7 +224,7 @@ where
}

fn denom_hash_string(&self, denom: &PrefixedDenom) -> Option<String> {
Some(storage::calc_hash(denom.to_string()))
Some(trace::calc_hash(denom.to_string()))
}
}

Expand Down
44 changes: 5 additions & 39 deletions crates/ibc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ mod msg;
mod nft;
pub mod parameters;
pub mod storage;
pub mod trace;

use std::cell::RefCell;
use std::collections::BTreeSet;
use std::fmt::Debug;
use std::rc::Rc;
use std::str::FromStr;

pub use actions::transfer_over_ibc;
use borsh::BorshDeserialize;
Expand All @@ -48,16 +48,13 @@ use ibc::apps::nft_transfer::handler::{
use ibc::apps::nft_transfer::types::error::NftTransferError;
use ibc::apps::nft_transfer::types::{
ack_success_b64, is_receiver_chain_source as is_nft_receiver_chain_source,
PrefixedClassId, TokenId, TracePath as NftTracePath,
TracePrefix as NftTracePrefix,
PrefixedClassId, TokenId, TracePrefix as NftTracePrefix,
};
use ibc::apps::transfer::handler::{
send_transfer_execute, send_transfer_validate,
};
use ibc::apps::transfer::types::error::TokenTransferError;
use ibc::apps::transfer::types::{
is_receiver_chain_source, PrefixedDenom, TracePath, TracePrefix,
};
use ibc::apps::transfer::types::{is_receiver_chain_source, TracePrefix};
use ibc::core::channel::types::acknowledgement::{
Acknowledgement, AcknowledgementStatus,
};
Expand Down Expand Up @@ -385,7 +382,7 @@ fn received_ibc_trace(
}

if let Some((trace_path, base_class_id, token_id)) =
is_nft_trace(&base_trace)
trace::is_nft_trace(&base_trace)
{
let mut class_id = PrefixedClassId {
trace_path,
Expand Down Expand Up @@ -433,41 +430,10 @@ pub fn received_ibc_token(
dest_port_id,
dest_channel_id,
)?;
storage::convert_to_address(ibc_trace)
trace::convert_to_address(ibc_trace)
.map_err(|e| Error::Trace(format!("Invalid base token: {e}")))
}

/// Returns the trace path and the token string if the denom is an IBC
/// denom.
pub fn is_ibc_denom(denom: impl AsRef<str>) -> Option<(TracePath, String)> {
let prefixed_denom = PrefixedDenom::from_str(denom.as_ref()).ok()?;
let base_denom = prefixed_denom.base_denom.to_string();
if prefixed_denom.trace_path.is_empty() || base_denom.contains('/') {
// The denom is just a token or an NFT trace
return None;
}
// The base token isn't decoded because it could be non Namada token
Some((prefixed_denom.trace_path, base_denom))
}

/// Returns the trace path and the token string if the trace is an NFT one
pub fn is_nft_trace(
trace: impl AsRef<str>,
) -> Option<(NftTracePath, String, String)> {
// The trace should be {port}/{channel}/.../{class_id}/{token_id}
if let Some((class_id, token_id)) = trace.as_ref().rsplit_once('/') {
let prefixed_class_id = PrefixedClassId::from_str(class_id).ok()?;
// The base token isn't decoded because it could be non Namada token
Some((
prefixed_class_id.trace_path,
prefixed_class_id.base_class_id.to_string(),
token_id.to_string(),
))
} else {
None
}
}

#[cfg(any(test, feature = "testing"))]
/// Testing helpers ans strategies for IBC
pub mod testing {
Expand Down
114 changes: 3 additions & 111 deletions crates/ibc/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@

use std::str::FromStr;

use ibc::apps::nft_transfer::types::{
PrefixedClassId, TokenId, TracePath as NftTracePath,
};
use ibc::apps::transfer::types::{PrefixedDenom, TracePath};
use ibc::apps::nft_transfer::types::{PrefixedClassId, TokenId};
use ibc::core::client::types::Height;
use ibc::core::host::types::identifiers::{
ChannelId, ClientId, ConnectionId, PortId, Sequence,
Expand All @@ -15,19 +12,18 @@ use ibc::core::host::types::path::{
ClientStatePath, CommitmentPath, ConnectionPath, Path, PortPath,
ReceiptPath, SeqAckPath, SeqRecvPath, SeqSendPath,
};
use namada_core::address::{Address, InternalAddress, HASH_LEN, SHA_HASH_LEN};
use namada_core::ibc::IbcTokenHash;
use namada_core::address::{Address, InternalAddress};
use namada_core::storage::{DbKeySeg, Key, KeySeg};
use namada_core::token::Amount;
use namada_events::{EmitEvents, EventLevel};
use namada_state::{StorageRead, StorageResult, StorageWrite};
use namada_token as token;
use namada_token::event::{TokenEvent, TokenOperation, UserAccount};
use sha2::{Digest, Sha256};
use thiserror::Error;

use crate::event::TOKEN_EVENT_DESCRIPTOR;
use crate::parameters::IbcParameters;
use crate::trace::{ibc_token, ibc_token_for_nft};

const CLIENTS_COUNTER_PREFIX: &str = "clients";
const CONNECTIONS_COUNTER_PREFIX: &str = "connections";
Expand Down Expand Up @@ -483,110 +479,6 @@ pub fn ibc_trace_key(
.expect("Cannot obtain a storage key")
}

/// Hash the denom
#[inline]
pub fn calc_hash(denom: impl AsRef<str>) -> String {
calc_ibc_token_hash(denom).to_string()
}

/// Hash the denom
pub fn calc_ibc_token_hash(denom: impl AsRef<str>) -> IbcTokenHash {
let hash = {
let mut hasher = Sha256::new();
hasher.update(denom.as_ref());
hasher.finalize()
};

let input: &[u8; SHA_HASH_LEN] = hash.as_ref();
let mut output = [0; HASH_LEN];

output.copy_from_slice(&input[..HASH_LEN]);
IbcTokenHash(output)
}

/// Obtain the IbcToken with the hash from the given denom
pub fn ibc_token(denom: impl AsRef<str>) -> Address {
let hash = calc_ibc_token_hash(&denom);
Address::Internal(InternalAddress::IbcToken(hash))
}

/// Obtain the IbcToken with the hash from the given NFT class ID and NFT ID
pub fn ibc_token_for_nft(
class_id: &PrefixedClassId,
token_id: &TokenId,
) -> Address {
ibc_token(ibc_trace_for_nft(class_id, token_id))
}

/// Obtain the IBC trace from the given NFT class ID and NFT ID
pub fn ibc_trace_for_nft(
class_id: &PrefixedClassId,
token_id: &TokenId,
) -> String {
format!("{class_id}/{token_id}")
}

/// Convert the given IBC trace to [`Address`]
pub fn convert_to_address(ibc_trace: impl AsRef<str>) -> Result<Address> {
// validation
if is_ibc_denom(&ibc_trace).is_none() && is_nft_trace(&ibc_trace).is_none()
{
return Err(Error::InvalidIbcTrace(format!(
"Invalid IBC trace: {}",
ibc_trace.as_ref()
)));
}

if ibc_trace.as_ref().contains('/') {
Ok(ibc_token(ibc_trace.as_ref()))
} else {
Address::decode(ibc_trace.as_ref())
.map_err(|e| Error::InvalidIbcTrace(e.to_string()))
}
}

/// Returns the trace path and the token string if the denom is an IBC
/// denom.
pub fn is_ibc_denom(denom: impl AsRef<str>) -> Option<(TracePath, String)> {
let prefixed_denom = PrefixedDenom::from_str(denom.as_ref()).ok()?;
let base_denom = prefixed_denom.base_denom.to_string();
if prefixed_denom.trace_path.is_empty() || base_denom.contains('/') {
// The denom is just a token or an NFT trace
return None;
}
// The base token isn't decoded because it could be non Namada token
Some((prefixed_denom.trace_path, base_denom))
}

/// Returns the trace path and the token string if the trace is an NFT one
pub fn is_nft_trace(
trace: impl AsRef<str>,
) -> Option<(NftTracePath, String, String)> {
// The trace should be {port}/{channel}/.../{class_id}/{token_id}
if let Some((class_id, token_id)) = trace.as_ref().rsplit_once('/') {
let prefixed_class_id = PrefixedClassId::from_str(class_id).ok()?;
// The base token isn't decoded because it could be non Namada token
Some((
prefixed_class_id.trace_path,
prefixed_class_id.base_class_id.to_string(),
token_id.to_string(),
))
} else {
None
}
}

/// Return true if the source of the given IBC trace is this chain
pub fn is_sender_chain_source(
trace: impl AsRef<str>,
src_port_id: &PortId,
src_channel_id: &ChannelId,
) -> bool {
!trace
.as_ref()
.starts_with(&format!("{src_port_id}/{src_channel_id}"))
}

/// Returns true if the given key is for IBC
pub fn is_ibc_key(key: &Key) -> bool {
matches!(&key.segments[0],
Expand Down
2 changes: 1 addition & 1 deletion crates/namada/src/ledger/ibc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use namada_ibc::storage::{
channel_counter_key, client_counter_key, connection_counter_key,
deposit_prefix, withdraw_prefix,
};
pub use namada_ibc::{parameters, storage};
pub use namada_ibc::{parameters, storage, trace};
use namada_state::{
DBIter, Key, State, StorageError, StorageHasher, StorageRead, StorageWrite,
WlState, DB,
Expand Down
Loading

0 comments on commit a51f3eb

Please sign in to comment.