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 IBC ack and FungibleTokenData #261

Merged
merged 4 commits into from
Nov 14, 2022
Merged
Show file tree
Hide file tree
Changes from 2 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
79 changes: 50 additions & 29 deletions shared/src/ledger/ibc/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -675,9 +675,17 @@ pub trait IbcActions {
msg: &MsgRecvPacket,
) -> std::result::Result<(), Self::Error> {
// check the packet data
if let Ok(data) = serde_json::from_slice(&msg.packet.data) {
self.receive_token(&msg.packet, &data)?;
}
let packet_ack =
if let Ok(data) = serde_json::from_slice(&msg.packet.data) {
match self.receive_token(&msg.packet, &data) {
Ok(_) => PacketAck::result_success(),
Err(_) => PacketAck::result_error(
"receiving a token failed".to_string(),
),
}
} else {
PacketAck::result_error("unknown packet data".to_string())
};

// store the receipt
let receipt_key = storage::receipt_key(
Expand All @@ -693,7 +701,7 @@ pub trait IbcActions {
&msg.packet.destination_channel,
msg.packet.sequence,
);
let ack = PacketAck::default().encode_to_vec();
let ack = packet_ack.encode_to_vec();
let ack_commitment = sha2::Sha256::digest(&ack).to_vec();
self.write_ibc_data(&ack_key, ack_commitment)?;

Expand All @@ -718,13 +726,29 @@ pub trait IbcActions {
&mut self,
msg: &MsgAcknowledgement,
) -> std::result::Result<(), Self::Error> {
let ack = PacketAck::try_from(msg.acknowledgement.clone())
.map_err(Error::IbcData)?;
if !ack.is_success() {
if let Ok(data) = serde_json::from_slice(&msg.packet.data) {
self.refund_token(&msg.packet, &data)?;
}
}

let commitment_key = storage::commitment_key(
&msg.packet.source_port,
&msg.packet.source_channel,
msg.packet.sequence,
);
self.delete_ibc_data(&commitment_key)?;

// get and increment the next sequence ack
let port_channel_id = port_channel_id(
msg.packet.source_port.clone(),
msg.packet.source_channel,
);
let seq_key = storage::next_sequence_ack_key(&port_channel_id);
self.get_and_inc_sequence(&seq_key)?;

let event = make_ack_event(msg.packet.clone()).try_into().unwrap();
self.emit_ibc_event(event)?;

Expand Down Expand Up @@ -917,13 +941,12 @@ pub trait IbcActions {
data.sender, e
))
})?;
let token_str =
data.denomination.split('/').last().ok_or_else(|| {
Error::SendingToken(format!(
"No token was specified: {}",
data.denomination
))
})?;
let token_str = data.denom.split('/').last().ok_or_else(|| {
Error::SendingToken(format!(
"No token was specified: {}",
data.denom
))
})?;
let token = Address::decode(token_str).map_err(|e| {
Error::SendingToken(format!(
"Invalid token address: token {}, error {}",
Expand All @@ -937,13 +960,13 @@ pub trait IbcActions {
))
})?;

// check the denomination field
// check the denom field
let prefix = format!(
"{}/{}/",
msg.source_port.clone(),
msg.source_channel.clone()
);
if data.denomination.starts_with(&prefix) {
if data.denom.starts_with(&prefix) {
// sink zone
let burn = Address::Internal(InternalAddress::IbcBurn);
self.transfer_token(&source, &burn, &token, amount)?;
Expand Down Expand Up @@ -982,13 +1005,12 @@ pub trait IbcActions {
data.receiver, e
))
})?;
let token_str =
data.denomination.split('/').last().ok_or_else(|| {
Error::ReceivingToken(format!(
"No token was specified: {}",
data.denomination
))
})?;
let token_str = data.denom.split('/').last().ok_or_else(|| {
Error::ReceivingToken(format!(
"No token was specified: {}",
data.denom
))
})?;
let token = Address::decode(token_str).map_err(|e| {
Error::ReceivingToken(format!(
"Invalid token address: token {}, error {}",
Expand All @@ -1007,7 +1029,7 @@ pub trait IbcActions {
packet.source_port.clone(),
packet.source_channel.clone()
);
if data.denomination.starts_with(&prefix) {
if data.denom.starts_with(&prefix) {
// unescrow the token because this chain is the source
let escrow =
Address::Internal(InternalAddress::ibc_escrow_address(
Expand Down Expand Up @@ -1035,13 +1057,12 @@ pub trait IbcActions {
data.sender, e
))
})?;
let token_str =
data.denomination.split('/').last().ok_or_else(|| {
Error::ReceivingToken(format!(
"No token was specified: {}",
data.denomination
))
})?;
let token_str = data.denom.split('/').last().ok_or_else(|| {
Error::ReceivingToken(format!(
"No token was specified: {}",
data.denom
))
})?;
let token = Address::decode(token_str).map_err(|e| {
Error::ReceivingToken(format!(
"Invalid token address: token {}, error {}",
Expand All @@ -1060,7 +1081,7 @@ pub trait IbcActions {
packet.source_port.clone(),
packet.source_channel.clone()
);
if data.denomination.starts_with(&prefix) {
if data.denom.starts_with(&prefix) {
// mint the token because the sender chain is the sink zone
let mint = Address::Internal(InternalAddress::IbcMint);
self.transfer_token(&mint, &dest, &token, amount)?;
Expand Down
8 changes: 4 additions & 4 deletions shared/src/ledger/ibc/vp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1570,7 +1570,7 @@ mod tests {
.write(&key, PacketReceipt::default().as_bytes().to_vec())
.expect("write failed");
let key = ack_key(&get_port_id(), &get_channel_id(), sequence);
let ack = PacketAck::default().encode_to_vec();
let ack = PacketAck::result_success().encode_to_vec();
write_log.write(&key, ack).expect("write failed");

let tx_code = vec![];
Expand Down Expand Up @@ -1648,7 +1648,7 @@ mod tests {
write_log.commit_block(&mut storage).expect("commit failed");

// prepare data
let ack = PacketAck::default().encode_to_vec();
let ack = PacketAck::result_success().encode_to_vec();
let proof_packet = CommitmentProofBytes::try_from(vec![0]).unwrap();
let proofs =
Proofs::new(proof_packet, None, None, None, Height::new(0, 1))
Expand Down Expand Up @@ -1837,7 +1837,7 @@ mod tests {
&msg.packet.destination_channel,
msg.packet.sequence,
);
let ack = PacketAck::default().encode_to_vec();
let ack = PacketAck::result_success().encode_to_vec();
write_log.write(&ack_key, ack).expect("write failed");
write_log.commit_tx();

Expand Down Expand Up @@ -1886,7 +1886,7 @@ mod tests {
.expect("write failed");
let ack_key =
ack_key(&get_port_id(), &get_channel_id(), Sequence::from(1));
let ack = PacketAck::default().encode_to_vec();
let ack = PacketAck::result_success().encode_to_vec();
write_log.write(&ack_key, ack).expect("write failed");
write_log.commit_tx();

Expand Down
22 changes: 11 additions & 11 deletions shared/src/ledger/ibc/vp/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ where
Ics26Envelope::Ics4PacketMsg(PacketMsg::RecvPacket(msg)) => {
self.validate_receiving_token(&msg.packet)
}
Ics26Envelope::Ics4PacketMsg(PacketMsg::AckPacket(msg)) => {
self.validate_refunding_token(&msg.packet)
}
Ics26Envelope::Ics4PacketMsg(PacketMsg::ToPacket(msg)) => {
self.validate_refunding_token(&msg.packet)
}
Expand All @@ -121,18 +124,17 @@ where
{
fn validate_sending_token(&self, msg: &MsgTransfer) -> Result<bool> {
let data = FungibleTokenPacketData::from(msg.clone());
let token_str =
data.denomination.split('/').last().ok_or(Error::NoToken)?;
let token_str = data.denom.split('/').last().ok_or(Error::NoToken)?;
let token = Address::decode(token_str).map_err(Error::Address)?;
let amount = Amount::from_str(&data.amount).map_err(Error::Amount)?;

// check the denomination field
// check the denom field
let prefix = format!(
"{}/{}/",
msg.source_port.clone(),
msg.source_channel.clone()
);
let change = if data.denomination.starts_with(&prefix) {
let change = if data.denom.starts_with(&prefix) {
// sink zone
let target = Address::Internal(InternalAddress::IbcBurn);
let target_key = token::balance_key(&token, &target);
Expand Down Expand Up @@ -174,8 +176,7 @@ where
let data: FungibleTokenPacketData =
serde_json::from_slice(&packet.data)
.map_err(Error::DecodingPacketData)?;
let token_str =
data.denomination.split('/').last().ok_or(Error::NoToken)?;
let token_str = data.denom.split('/').last().ok_or(Error::NoToken)?;
let token = Address::decode(token_str).map_err(Error::Address)?;
let amount = Amount::from_str(&data.amount).map_err(Error::Amount)?;

Expand All @@ -184,7 +185,7 @@ where
packet.source_port.clone(),
packet.source_channel.clone()
);
let change = if data.denomination.starts_with(&prefix) {
let change = if data.denom.starts_with(&prefix) {
// this chain is the source
let source =
Address::Internal(InternalAddress::ibc_escrow_address(
Expand Down Expand Up @@ -226,18 +227,17 @@ where
let data: FungibleTokenPacketData =
serde_json::from_slice(&packet.data)
.map_err(Error::DecodingPacketData)?;
let token_str =
data.denomination.split('/').last().ok_or(Error::NoToken)?;
let token_str = data.denom.split('/').last().ok_or(Error::NoToken)?;
let token = Address::decode(token_str).map_err(Error::Address)?;
let amount = Amount::from_str(&data.amount).map_err(Error::Amount)?;

// check the denomination field
// check the denom field
let prefix = format!(
"{}/{}/",
packet.source_port.clone(),
packet.source_channel.clone()
);
let change = if data.denomination.starts_with(&prefix) {
let change = if data.denom.starts_with(&prefix) {
// sink zone: mint the token for the refund
let source = Address::Internal(InternalAddress::IbcMint);
let source_key = token::balance_key(&token, &source);
Expand Down
63 changes: 48 additions & 15 deletions shared/src/types/ibc/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ use crate::ibc::core::ics03_connection::msgs::conn_open_confirm::MsgConnectionOp
use crate::ibc::core::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit;
use crate::ibc::core::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry;
use crate::ibc::core::ics03_connection::msgs::ConnectionMsg;
use crate::ibc::core::ics04_channel::msgs::acknowledgement::MsgAcknowledgement;
use crate::ibc::core::ics04_channel::msgs::acknowledgement::{
Acknowledgement, MsgAcknowledgement,
};
use crate::ibc::core::ics04_channel::msgs::chan_close_confirm::MsgChannelCloseConfirm;
use crate::ibc::core::ics04_channel::msgs::chan_close_init::MsgChannelCloseInit;
use crate::ibc::core::ics04_channel::msgs::chan_open_ack::MsgChannelOpenAck;
Expand All @@ -32,14 +34,14 @@ use crate::ibc::core::ics26_routing::error::Error as Ics26Error;
use crate::ibc::core::ics26_routing::msgs::Ics26Envelope;
use crate::ibc::downcast;
use crate::ibc_proto::google::protobuf::Any;
use crate::ibc_proto::ibc::core::channel::v1::acknowledgement::Response;
use crate::ibc_proto::ibc::core::channel::v1::Acknowledgement;

#[allow(missing_docs)]
#[derive(Error, Debug)]
pub enum Error {
#[error("Decoding IBC data error: {0}")]
DecodingData(prost::DecodeError),
#[error("Decoding Json data error: {0}")]
DecodingJsonData(serde_json::Error),
#[error("Decoding message error: {0}")]
DecodingMessage(Ics26Error),
#[error("Downcast error: {0}")]
Expand Down Expand Up @@ -326,39 +328,70 @@ impl Default for PacketReceipt {
}

/// Acknowledgement for a packet
#[derive(Clone, Debug)]
pub struct PacketAck(pub Acknowledgement);
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum PacketAck {
/// Success Acknowledgement
Result(String),
/// Error Acknowledgement
Error(String),
}

/// Success acknowledgement
const ACK_SUCCESS_B64: &str = "AQ==";
/// Error acknowledgement
const ACK_ERR_STR: &str =
"error handling packet on destination chain: see events for details";

// TODO temporary type. add a new type for ack to ibc-rs
impl PacketAck {
/// Success acknowledgement
pub fn result_success() -> Self {
Self::Result(ACK_SUCCESS_B64.to_string())
}

/// Acknowledgement with an error
pub fn result_error(err: String) -> Self {
Self::Error(format!("{}: {}", ACK_ERR_STR, err))
}

/// Check if the ack is for success
pub fn is_success(&self) -> bool {
match self {
Self::Result(_) => true,
Self::Error(_) => false,
}
}

/// Encode the ack
pub fn encode_to_vec(&self) -> Vec<u8> {
serde_json::to_vec(&self.0)
serde_json::to_vec(&self)
.expect("Encoding acknowledgement shouldn't fail")
}
}

impl Default for PacketAck {
fn default() -> Self {
Self(Acknowledgement {
response: Some(Response::Result(vec![1_u8])),
})
impl TryFrom<Acknowledgement> for PacketAck {
type Error = Error;

fn try_from(ack: Acknowledgement) -> Result<Self> {
serde_json::from_slice(&ack.into_bytes())
.map_err(Error::DecodingJsonData)
}
}

// for the string to be used by the current reader
impl Display for PacketAck {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", serde_json::to_string(&self.0).unwrap())
write!(f, "{}", serde_json::to_string(&self).unwrap())
}
}

// TODO temporary type. add a new type for ack to ibc-rs
// TODO temporary type. add a new type for packet data to ibc-rs
/// Data to transfer a token
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct FungibleTokenPacketData {
/// the token denomination to be transferred
pub denomination: String,
pub denom: String,
/// the token amount to be transferred
pub amount: String,
/// the sender address
Expand All @@ -372,7 +405,7 @@ impl From<MsgTransfer> for FungibleTokenPacketData {
// TODO validation
let token = msg.token.unwrap();
Self {
denomination: token.denom,
denom: token.denom,
amount: token.amount,
sender: msg.sender.to_string(),
receiver: msg.receiver.to_string(),
Expand Down
7 changes: 2 additions & 5 deletions shared/src/types/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -411,11 +411,8 @@ impl TryFrom<FungibleTokenPacketData> for Transfer {
Address::decode(&data.sender).map_err(TransferError::Address)?;
let target =
Address::decode(&data.receiver).map_err(TransferError::Address)?;
let token_str = data
.denomination
.split('/')
.last()
.ok_or(TransferError::NoToken)?;
let token_str =
data.denom.split('/').last().ok_or(TransferError::NoToken)?;
let token =
Address::decode(token_str).map_err(TransferError::Address)?;
let amount =
Expand Down
Loading