Skip to content

Commit

Permalink
fix denom update
Browse files Browse the repository at this point in the history
  • Loading branch information
yito88 committed Aug 1, 2023
1 parent c85f75d commit 52d4d68
Show file tree
Hide file tree
Showing 12 changed files with 198 additions and 65 deletions.
60 changes: 42 additions & 18 deletions core/src/ledger/ibc/context/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use prost::Message;
use sha2::Digest;

use super::storage::IbcStorageContext;
use crate::ibc::applications::transfer::denom::PrefixedDenom;
use crate::ibc::clients::ics07_tendermint::client_state::ClientState as TmClientState;
use crate::ibc::clients::ics07_tendermint::consensus_state::ConsensusState as TmConsensusState;
use crate::ibc::core::ics02_client::client_state::ClientState;
Expand Down Expand Up @@ -362,22 +361,36 @@ pub trait IbcCommonContext: IbcStorageContext {
/// Write the IBC denom
fn store_ibc_denom(
&mut self,
trace_hash: String,
denom: PrefixedDenom,
trace_hash: impl AsRef<str>,
denom: impl AsRef<str>,
) -> Result<(), ContextError> {
let key = storage::ibc_denom_key(trace_hash);
let bytes = denom
.to_string()
.try_to_vec()
.expect("encoding shouldn't fail");
self.write(&key, bytes).map_err(|_| {
let key = storage::ibc_denom_key(trace_hash.as_ref());
let has_key = self.has_key(&key).map_err(|_| {
ContextError::ChannelError(ChannelError::Other {
description: format!("Writing the denom failed: Key {}", key),
description: format!(
"Reading the IBC denom failed: Key {}",
key
),
})
})
})?;
if !has_key {
let bytes = denom
.as_ref()
.try_to_vec()
.expect("encoding shouldn't fail");
self.write(&key, bytes).map_err(|_| {
ContextError::ChannelError(ChannelError::Other {
description: format!(
"Writing the denom failed: Key {}",
key
),
})
})?;
}
Ok(())
}

/// Write the IBC denom
/// Read the token denom
fn read_token_denom(
&self,
token: &Address,
Expand Down Expand Up @@ -414,16 +427,27 @@ pub trait IbcCommonContext: IbcStorageContext {
token: &Address,
) -> Result<(), ContextError> {
let key = token::denom_key(token);
// IBC denomination should be zero for U256
let denom = token::Denomination::from(0);
let bytes = denom.try_to_vec().expect("encoding shouldn't fail");
self.write(&key, bytes).map_err(|_| {
let has_key = self.has_key(&key).map_err(|_| {
ContextError::ChannelError(ChannelError::Other {
description: format!(
"Writing the token denom failed: Key {}",
"Reading the token denom failed: Key {}",
key
),
})
})
})?;
if !has_key {
// IBC denomination should be zero for U256
let denom = token::Denomination::from(0);
let bytes = denom.try_to_vec().expect("encoding shouldn't fail");
self.write(&key, bytes).map_err(|_| {
ContextError::ChannelError(ChannelError::Other {
description: format!(
"Writing the token denom failed: Key {}",
key
),
})
})?;
}
Ok(())
}
}
9 changes: 9 additions & 0 deletions core/src/ledger/ibc/context/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ pub trait IbcStorageContext {
/// Read IBC-related data
fn read(&self, key: &Key) -> Result<Option<Vec<u8>>, Self::Error>;

/// Check if the given key is present
fn has_key(&self, key: &Key) -> Result<bool, Self::Error>;

/// Read IBC-related data with a prefix
fn iter_prefix<'iter>(
&'iter self,
Expand All @@ -52,6 +55,12 @@ pub trait IbcStorageContext {
/// Emit an IBC event
fn emit_ibc_event(&mut self, event: IbcEvent) -> Result<(), Self::Error>;

/// Get an IBC event
fn get_ibc_event(
&self,
event_type: impl AsRef<str>,
) -> Result<Option<IbcEvent>, Self::Error>;

/// Transfer token
fn transfer_token(
&mut self,
Expand Down
83 changes: 38 additions & 45 deletions core/src/ledger/ibc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,8 @@ pub use context::transfer_mod::{ModuleWrapper, TransferModule};
use prost::Message;
use thiserror::Error;

use crate::ibc::applications::transfer::denom::TracePrefix;
use crate::ibc::applications::transfer::error::TokenTransferError;
use crate::ibc::applications::transfer::msgs::transfer::MsgTransfer;
use crate::ibc::applications::transfer::packet::PacketData;
use crate::ibc::applications::transfer::{
send_transfer_execute, send_transfer_validate,
};
Expand Down Expand Up @@ -136,50 +134,45 @@ where
/// Store the denom when transfer with MsgRecvPacket
fn store_denom(&mut self, envelope: MsgEnvelope) -> Result<(), Error> {
match envelope {
MsgEnvelope::Packet(PacketMsg::Recv(msg)) => {
let data = match serde_json::from_slice::<PacketData>(
&msg.packet.data,
) {
Ok(data) => data,
// not token transfer data
Err(_) => return Ok(()),
};
let prefix = TracePrefix::new(
msg.packet.port_id_on_b.clone(),
msg.packet.chan_id_on_b,
);
let mut coin = data.token;
coin.denom.add_trace_prefix(prefix);
let trace_hash = storage::calc_hash(coin.denom.to_string());
self.ctx
.borrow_mut()
.store_ibc_denom(trace_hash, coin.denom.clone())
.map_err(|e| {
Error::Denom(format!(
"Writing the IBC denom failed: {}",
e
))
MsgEnvelope::Packet(PacketMsg::Recv(_)) => {
let result = self
.ctx
.borrow()
.get_ibc_event("denomination_trace")
.map_err(|_| {
Error::Denom(format!("Reading the IBC event failed",))
})?;

let token = storage::ibc_token(coin.denom.to_string());
let denom =
self.ctx.borrow().read_token_denom(&token).map_err(
|e| {
Error::Denom(format!(
"Reading the token denom failed: {}",
e
))
},
)?;
if denom.is_none() {
self.ctx.borrow_mut().store_token_denom(&token).map_err(
|e| {
Error::Denom(format!(
"Writing the token denom failed: {}",
e
))
},
)?;
if let Some(event) = result {
if let (Some(trace_hash), Some(ibc_denom)) = (
event.attributes.get("trace_hash"),
event.attributes.get("denom"),
) {
// If the denomination trace event has the trace hash
// and the IBC denom, a token has been minted. The raw
// IBC denom including the port ID, the channel ID and
// the base token is stored to be restored from the
// trace hash. The amount denomination is also set for
// the minting.
self.ctx
.borrow_mut()
.store_ibc_denom(trace_hash, ibc_denom)
.map_err(|e| {
Error::Denom(format!(
"Writing the IBC denom failed: {}",
e
))
})?;
let token = storage::ibc_token(ibc_denom);
self.ctx
.borrow_mut()
.store_token_denom(&token)
.map_err(|e| {
Error::Denom(format!(
"Writing the token denom failed: {}",
e
))
})?;
}
}
Ok(())
}
Expand Down
6 changes: 6 additions & 0 deletions core/src/ledger/tx_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,10 @@ pub trait TxEnv: StorageRead + StorageWrite {
&mut self,
event: &IbcEvent,
) -> Result<(), storage_api::Error>;

/// Get an IBC event with a event type
fn get_ibc_event(
&self,
event_type: impl AsRef<str>,
) -> Result<Option<IbcEvent>, storage_api::Error>;
}
28 changes: 28 additions & 0 deletions shared/src/ledger/ibc/vp/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ where
}
}

fn has_key(&self, key: &Key) -> Result<bool, Self::Error> {
Ok(self.store.contains_key(key)
|| self.ctx.has_key(key).map_err(Error::NativeVpError)?)
}

fn iter_prefix<'iter>(
&'iter self,
prefix: &Key,
Expand Down Expand Up @@ -113,6 +118,18 @@ where
Ok(())
}

fn get_ibc_event(
&self,
event_type: impl AsRef<str>,
) -> Result<Option<IbcEvent>, Self::Error> {
for event in &self.event {
if event.event_type == *event_type.as_ref() {
return Ok(Some(event.clone()));
}
}
Ok(None)
}

fn transfer_token(
&mut self,
src: &Address,
Expand Down Expand Up @@ -280,6 +297,10 @@ where
self.ctx.read_bytes(key).map_err(Error::NativeVpError)
}

fn has_key(&self, key: &Key) -> Result<bool, Self::Error> {
self.ctx.has_key(key).map_err(Error::NativeVpError)
}

fn iter_prefix<'iter>(
&'iter self,
prefix: &Key,
Expand All @@ -306,6 +327,13 @@ where
unimplemented!("Validation doesn't emit an event")
}

fn get_ibc_event(
&self,
_event_type: impl AsRef<str>,
) -> Result<Option<IbcEvent>, Self::Error> {
unimplemented!("Validation doesn't get an event")
}

fn transfer_token(
&mut self,
_src: &Address,
Expand Down
34 changes: 34 additions & 0 deletions shared/src/vm/host_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1007,6 +1007,40 @@ where
tx_add_gas(env, gas)
}

/// Getting an IBC event function exposed to the wasm VM Tx environment.
pub fn tx_get_ibc_event<MEM, DB, H, CA>(
env: &TxVmEnv<MEM, DB, H, CA>,
event_type_ptr: u64,
event_type_len: u64,
) -> TxResult<i64>
where
MEM: VmMemory,
DB: storage::DB + for<'iter> storage::DBIter<'iter>,
H: StorageHasher,
CA: WasmCacheAccess,
{
let (event_type, gas) = env
.memory
.read_string(event_type_ptr, event_type_len as _)
.map_err(|e| TxRuntimeError::MemoryError(Box::new(e)))?;
tx_add_gas(env, gas)?;
let write_log = unsafe { env.ctx.write_log.get() };
for event in write_log.get_ibc_events() {
if event.event_type == event_type {
let value =
event.try_to_vec().map_err(TxRuntimeError::EncodingError)?;
let len: i64 = value
.len()
.try_into()
.map_err(TxRuntimeError::NumConversionError)?;
let result_buffer = unsafe { env.ctx.result_buffer.get() };
result_buffer.replace(value);
return Ok(len);
}
}
Ok(HostEnvResult::Fail.to_i64())
}

/// Storage read prior state (before tx execution) function exposed to the wasm
/// VM VP environment. It will try to read from the storage.
///
Expand Down
1 change: 1 addition & 0 deletions shared/src/vm/wasm/host_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ where
"namada_tx_update_validity_predicate" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_update_validity_predicate),
"namada_tx_init_account" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_init_account),
"namada_tx_emit_ibc_event" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_emit_ibc_event),
"namada_tx_get_ibc_event" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_get_ibc_event),
"namada_tx_get_chain_id" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_get_chain_id),
"namada_tx_get_tx_index" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_get_tx_index),
"namada_tx_get_block_height" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_get_block_height),
Expand Down
1 change: 1 addition & 0 deletions tests/src/vm_host_env/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,7 @@ mod native_tx_host_env {
result_ptr: u64
));
native_host_fn!(tx_emit_ibc_event(event_ptr: u64, event_len: u64));
native_host_fn!(tx_get_ibc_event(event_type_ptr: u64, event_type_len: u64) -> i64);
native_host_fn!(tx_get_chain_id(result_ptr: u64));
native_host_fn!(tx_get_block_height() -> u64);
native_host_fn!(tx_get_tx_index() -> u32);
Expand Down
11 changes: 11 additions & 0 deletions tx_prelude/src/ibc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ impl IbcStorageContext for Ctx {
self.read_bytes(key)
}

fn has_key(&self, key: &Key) -> Result<bool, Self::Error> {
<Ctx as StorageRead>::has_key(self, key)
}

fn write(
&mut self,
key: &Key,
Expand Down Expand Up @@ -71,6 +75,13 @@ impl IbcStorageContext for Ctx {
<Ctx as TxEnv>::emit_ibc_event(self, &event)
}

fn get_ibc_event(
&self,
event_type: impl AsRef<str>,
) -> Result<Option<IbcEvent>, Self::Error> {
<Ctx as TxEnv>::get_ibc_event(self, &event_type)
}

fn transfer_token(
&mut self,
src: &Address,
Expand Down
20 changes: 20 additions & 0 deletions tx_prelude/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,4 +324,24 @@ impl TxEnv for Ctx {
};
Ok(())
}

fn get_ibc_event(
&self,
event_type: impl AsRef<str>,
) -> Result<Option<ibc::IbcEvent>, Error> {
let event_type = event_type.as_ref().to_string();
let read_result = unsafe {
namada_tx_get_ibc_event(
event_type.as_ptr() as _,
event_type.len() as _,
)
};
match read_from_buffer(read_result, namada_tx_result_buffer) {
Some(value) => Ok(Some(
ibc::IbcEvent::try_from_slice(&value[..])
.expect("The conversion shouldn't fail"),
)),
None => Ok(None),
}
}
}
6 changes: 6 additions & 0 deletions vm_env/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ pub mod tx {
// Emit an IBC event
pub fn namada_tx_emit_ibc_event(event_ptr: u64, event_len: u64);

// Get an IBC event
pub fn namada_tx_get_ibc_event(
event_type_ptr: u64,
event_type_len: u64,
) -> i64;

// Get the chain ID
pub fn namada_tx_get_chain_id(result_ptr: u64);

Expand Down
Loading

0 comments on commit 52d4d68

Please sign in to comment.