From fa29923fae50131f9e1db32eea3611c253732110 Mon Sep 17 00:00:00 2001 From: Gianmarco Fraccaroli Date: Wed, 15 Jan 2025 14:04:50 +0100 Subject: [PATCH 1/6] added better transfer classification --- .../down.sql | 2 + .../up.sql | 2 + orm/src/transactions.rs | 6 + shared/src/block.rs | 125 +++++++++++++++++- shared/src/ser.rs | 6 +- shared/src/transaction.rs | 75 +++++++++-- transactions/src/services/tx.rs | 15 ++- webserver/src/response/transaction.rs | 2 + 8 files changed, 207 insertions(+), 26 deletions(-) create mode 100644 orm/migrations/2025-01-15-130138_transaction_kind_mixed_transfer/down.sql create mode 100644 orm/migrations/2025-01-15-130138_transaction_kind_mixed_transfer/up.sql diff --git a/orm/migrations/2025-01-15-130138_transaction_kind_mixed_transfer/down.sql b/orm/migrations/2025-01-15-130138_transaction_kind_mixed_transfer/down.sql new file mode 100644 index 000000000..c7c9cbeb4 --- /dev/null +++ b/orm/migrations/2025-01-15-130138_transaction_kind_mixed_transfer/down.sql @@ -0,0 +1,2 @@ +-- This file should undo anything in `up.sql` +SELECT 1; \ No newline at end of file diff --git a/orm/migrations/2025-01-15-130138_transaction_kind_mixed_transfer/up.sql b/orm/migrations/2025-01-15-130138_transaction_kind_mixed_transfer/up.sql new file mode 100644 index 000000000..76cfe3b6f --- /dev/null +++ b/orm/migrations/2025-01-15-130138_transaction_kind_mixed_transfer/up.sql @@ -0,0 +1,2 @@ +-- Your SQL goes here +ALTER TYPE TRANSACTION_KIND ADD VALUE 'mixed_transfer'; \ No newline at end of file diff --git a/orm/src/transactions.rs b/orm/src/transactions.rs index c1191a961..10bef7387 100644 --- a/orm/src/transactions.rs +++ b/orm/src/transactions.rs @@ -16,6 +16,7 @@ pub enum TransactionKindDb { ShieldedTransfer, ShieldingTransfer, UnshieldingTransfer, + MixedTransfer, IbcMsgTransfer, Bond, Redelegation, @@ -41,6 +42,11 @@ impl From for TransactionKindDb { Self::TransparentTransfer } TransactionKind::ShieldedTransfer(_) => Self::ShieldedTransfer, + TransactionKind::UnshieldingTransfer(_) => { + Self::UnshieldingTransfer + } + TransactionKind::ShieldingTransfer(_) => Self::ShieldingTransfer, + TransactionKind::MixedTransfer(_) => Self::MixedTransfer, TransactionKind::IbcMsgTransfer(_) => Self::IbcMsgTransfer, TransactionKind::Bond(_) => Self::Bond, TransactionKind::Redelegation(_) => Self::Redelegation, diff --git a/shared/src/block.rs b/shared/src/block.rs index 24f0b7f4e..30d78376c 100644 --- a/shared/src/block.rs +++ b/shared/src/block.rs @@ -5,7 +5,7 @@ use namada_ibc::apps::transfer::types::packet::PacketData; use namada_ibc::core::channel::types::msgs::{MsgRecvPacket, PacketMsg}; use namada_ibc::core::handler::types::msgs::MsgEnvelope; use namada_ibc::IbcMessage; -use namada_sdk::address::Address; +use namada_sdk::address::{Address, InternalAddress}; use namada_sdk::borsh::BorshDeserialize; use namada_sdk::token::Transfer; use subtle_encoding::hex; @@ -112,13 +112,12 @@ impl Block { pub fn from( block_response: &TendermintBlockResponse, block_results: &BlockResult, - proposer_address_namada: &Option, /* Provide the namada address - * of the proposer, if - * available */ + proposer_address_namada: &Option, checksums: Checksums, epoch: Epoch, block_height: BlockHeight, ) -> Self { + let masp_address = Address::Internal(InternalAddress::Masp); let transactions = block_response .block .data @@ -131,6 +130,7 @@ impl Block { block_height, checksums.clone(), block_results, + &masp_address, ) .map_err(|reason| { tracing::info!("Couldn't deserialize tx due to {}", reason); @@ -208,8 +208,121 @@ impl Block { vec![] } } - TransactionKind::ShieldedTransfer(_shielded_transfer) => { - vec![] + TransactionKind::MixedTransfer(transparent_transfer) => { + if let Some(data) = transparent_transfer { + let sources = data + .sources + .0 + .keys() + .map(|account| { + TransactionTarget::sent( + tx.tx_id.clone(), + account.owner.to_string(), + ) + }) + .collect::>(); + let targets = data + .targets + .0 + .keys() + .map(|account| { + TransactionTarget::received( + tx.tx_id.clone(), + account.owner.to_string(), + ) + }) + .collect::>(); + [sources, targets].concat() + } else { + vec![] + } + } + TransactionKind::ShieldedTransfer(transparent_transfer) => { + if let Some(data) = transparent_transfer { + let sources = data + .sources + .0 + .keys() + .map(|account| { + TransactionTarget::sent( + tx.tx_id.clone(), + account.owner.to_string(), + ) + }) + .collect::>(); + let targets = data + .targets + .0 + .keys() + .map(|account| { + TransactionTarget::received( + tx.tx_id.clone(), + account.owner.to_string(), + ) + }) + .collect::>(); + [sources, targets].concat() + } else { + vec![] + } + } + TransactionKind::UnshieldingTransfer(transparent_transfer) => { + if let Some(data) = transparent_transfer { + let sources = data + .sources + .0 + .keys() + .map(|account| { + TransactionTarget::sent( + tx.tx_id.clone(), + account.owner.to_string(), + ) + }) + .collect::>(); + let targets = data + .targets + .0 + .keys() + .map(|account| { + TransactionTarget::received( + tx.tx_id.clone(), + account.owner.to_string(), + ) + }) + .collect::>(); + [sources, targets].concat() + } else { + vec![] + } + } + TransactionKind::ShieldingTransfer(transparent_transfer) => { + if let Some(data) = transparent_transfer { + let sources = data + .sources + .0 + .keys() + .map(|account| { + TransactionTarget::sent( + tx.tx_id.clone(), + account.owner.to_string(), + ) + }) + .collect::>(); + let targets = data + .targets + .0 + .keys() + .map(|account| { + TransactionTarget::received( + tx.tx_id.clone(), + account.owner.to_string(), + ) + }) + .collect::>(); + [sources, targets].concat() + } else { + vec![] + } } TransactionKind::IbcMsgTransfer(ibc_message) => { if let Some(data) = ibc_message { diff --git a/shared/src/ser.rs b/shared/src/ser.rs index a9e9ee609..27ef6588b 100644 --- a/shared/src/ser.rs +++ b/shared/src/ser.rs @@ -68,7 +68,7 @@ impl<'de> Deserialize<'de> for AccountsMap { } #[derive(Deserialize, Serialize, Debug, Clone)] -pub struct TransparentTransfer { +pub struct TransferData { /// Sources of this transfer pub sources: AccountsMap, /// Targets of this transfer @@ -77,13 +77,13 @@ pub struct TransparentTransfer { pub shielded_section_hash: Option, } -impl From for TransparentTransfer { +impl From for TransferData { fn from(transfer: NamadaTransfer) -> Self { let sources = AccountsMap(transfer.sources); let targets = AccountsMap(transfer.targets); let shielded_section_hash = transfer.shielded_section_hash; - TransparentTransfer { + TransferData { sources, targets, shielded_section_hash, diff --git a/shared/src/transaction.rs b/shared/src/transaction.rs index 5ab4ad344..bb5d73058 100644 --- a/shared/src/transaction.rs +++ b/shared/src/transaction.rs @@ -5,7 +5,6 @@ use namada_governance::{InitProposalData, VoteProposalData}; use namada_sdk::address::Address; use namada_sdk::borsh::BorshDeserialize; use namada_sdk::key::common::PublicKey; -use namada_sdk::masp::ShieldedTransfer; use namada_sdk::token::Transfer; use namada_sdk::uint::Uint; use namada_tx::data::pos::{ @@ -21,7 +20,7 @@ use crate::block::BlockHeight; use crate::block_result::{BlockResult, TxEventStatusCode}; use crate::checksums::Checksums; use crate::id::Id; -use crate::ser::{IbcMessage, TransparentTransfer}; +use crate::ser::{IbcMessage, TransferData}; // We wrap public key in a struct so we serialize data as object instead of // string @@ -33,10 +32,11 @@ pub struct RevealPkData { #[derive(Serialize, Debug, Clone)] #[serde(untagged)] pub enum TransactionKind { - TransparentTransfer(Option), - // TODO: remove once ShieldedTransfer can be serialized - #[serde(skip)] - ShieldedTransfer(Option), + TransparentTransfer(Option), + ShieldedTransfer(Option), + ShieldingTransfer(Option), + UnshieldingTransfer(Option), + MixedTransfer(Option), IbcMsgTransfer(Option>), Bond(Option), Redelegation(Option), @@ -60,16 +60,60 @@ impl TransactionKind { serde_json::to_string(&self).ok() } - pub fn from(tx_kind_name: &str, data: &[u8]) -> Self { + pub fn from( + tx_kind_name: &str, + data: &[u8], + masp_address: &Address, + ) -> Self { match tx_kind_name { "tx_transfer" => { - let data = if let Ok(data) = Transfer::try_from_slice(data) { - Some(TransparentTransfer::from(data)) + if let Ok(data) = Transfer::try_from_slice(data) { + let has_shielded_section = + data.shielded_section_hash.is_some(); + let all_sources_are_masp = data + .sources + .iter() + .all(|(acc, _)| acc.owner.eq(masp_address)); + let any_sources_are_masp = data + .sources + .iter() + .all(|(acc, _)| acc.owner.eq(masp_address)); + let all_targets_are_masp = data + .targets + .iter() + .all(|(acc, _)| acc.owner.eq(masp_address)); + let any_targets_are_masp = data + .targets + .iter() + .all(|(acc, _)| acc.owner.eq(masp_address)); + if all_sources_are_masp + && all_targets_are_masp + && has_shielded_section + { + TransactionKind::ShieldedTransfer(Some(data.into())) + } else if all_sources_are_masp + && !any_targets_are_masp + && has_shielded_section + { + TransactionKind::UnshieldingTransfer(Some(data.into())) + } else if !any_sources_are_masp + && all_targets_are_masp + && has_shielded_section + { + TransactionKind::ShieldingTransfer(Some(data.into())) + } else if !any_sources_are_masp + && !any_targets_are_masp + && !has_shielded_section + { + TransactionKind::TransparentTransfer(Some(data.into())) + } else { + TransactionKind::MixedTransfer(Some(data.into())) + } } else { - None - }; - TransactionKind::TransparentTransfer(data) + TransactionKind::Unknown + } } + "tx_bond" => { let data = if let Ok(data) = Bond::try_from_slice(data) { Some(data) @@ -299,6 +343,7 @@ impl Transaction { block_height: BlockHeight, checksums: Checksums, block_results: &BlockResult, + masp_address: &Address, ) -> Result<(WrapperTransaction, Vec), String> { let transaction = Tx::try_from(raw_tx_bytes).map_err(|e| e.to_string())?; @@ -379,7 +424,11 @@ impl Transaction { if let Some(tx_kind_name) = checksums.get_name_by_id(&id) { - TransactionKind::from(&tx_kind_name, &tx_data) + TransactionKind::from( + &tx_kind_name, + &tx_data, + masp_address, + ) } else { TransactionKind::Unknown } diff --git a/transactions/src/services/tx.rs b/transactions/src/services/tx.rs index 2ed2645c7..7b56c4e57 100644 --- a/transactions/src/services/tx.rs +++ b/transactions/src/services/tx.rs @@ -133,12 +133,10 @@ pub fn get_gas_estimates( && inner_tx.wrapper_id.eq(&wrapper_tx.tx_id) }) .for_each(|tx| match tx.kind { - TransactionKind::TransparentTransfer(_) => { + TransactionKind::TransparentTransfer(_) + | TransactionKind::MixedTransfer(_) => { gas_estimate.increase_transparent_transfer() } - TransactionKind::ShieldedTransfer(_) => { - gas_estimate.increase_shielded_transfer() - } TransactionKind::IbcMsgTransfer(_) => { gas_estimate.increase_ibc_msg_transfer() } @@ -161,6 +159,15 @@ pub fn get_gas_estimates( TransactionKind::RevealPk(_) => { gas_estimate.increase_reveal_pk() } + TransactionKind::ShieldedTransfer(_) => { + gas_estimate.increase_shielded_transfer() + } + TransactionKind::ShieldingTransfer(_) => { + gas_estimate.increase_shielding_transfer() + } + TransactionKind::UnshieldingTransfer(_) => { + gas_estimate.increase_unshielding_transfer() + } _ => (), }); gas_estimate diff --git a/webserver/src/response/transaction.rs b/webserver/src/response/transaction.rs index 4a96071ea..e24d746ac 100644 --- a/webserver/src/response/transaction.rs +++ b/webserver/src/response/transaction.rs @@ -18,6 +18,7 @@ pub enum TransactionKind { ShieldedTransfer, ShieldingTransfer, UnshieldingTransfer, + MixedTransfer, Bond, Redelegation, Unbond, @@ -100,6 +101,7 @@ impl From for TransactionKind { TransactionKindDb::ShieldedTransfer => Self::ShieldedTransfer, TransactionKindDb::ShieldingTransfer => Self::ShieldingTransfer, TransactionKindDb::UnshieldingTransfer => Self::UnshieldingTransfer, + TransactionKindDb::MixedTransfer => Self::MixedTransfer, TransactionKindDb::Bond => Self::Bond, TransactionKindDb::Redelegation => Self::Redelegation, TransactionKindDb::Unbond => Self::Unbond, From 92aec7b07eaf033f9de19c450ef3290a82904ff5 Mon Sep 17 00:00:00 2001 From: Gianmarco Fraccaroli Date: Wed, 15 Jan 2025 14:35:49 +0100 Subject: [PATCH 2/6] refactor --- shared/src/transaction.rs | 73 +++++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 34 deletions(-) diff --git a/shared/src/transaction.rs b/shared/src/transaction.rs index bb5d73058..c0554d311 100644 --- a/shared/src/transaction.rs +++ b/shared/src/transaction.rs @@ -70,44 +70,49 @@ impl TransactionKind { if let Ok(data) = Transfer::try_from_slice(data) { let has_shielded_section = data.shielded_section_hash.is_some(); - let all_sources_are_masp = data - .sources - .iter() - .all(|(acc, _)| acc.owner.eq(masp_address)); - let any_sources_are_masp = data + + let (all_sources_are_masp, any_sources_are_masp) = data .sources .iter() - .all(|(acc, _)| acc.owner.eq(masp_address)); - let all_targets_are_masp = data - .targets - .iter() - .all(|(acc, _)| acc.owner.eq(masp_address)); - let any_targets_are_masp = data + .fold((true, false), |(all, any), (acc, _)| { + let is_masp = acc.owner.eq(masp_address); + (all && is_masp, any || is_masp) + }); + + let (all_targets_are_masp, any_targets_are_masp) = data .targets .iter() - .all(|(acc, _)| acc.owner.eq(masp_address)); - if all_sources_are_masp - && all_targets_are_masp - && has_shielded_section - { - TransactionKind::ShieldedTransfer(Some(data.into())) - } else if all_sources_are_masp - && !any_targets_are_masp - && has_shielded_section - { - TransactionKind::UnshieldingTransfer(Some(data.into())) - } else if !any_sources_are_masp - && all_targets_are_masp - && has_shielded_section - { - TransactionKind::ShieldingTransfer(Some(data.into())) - } else if !any_sources_are_masp - && !any_targets_are_masp - && !has_shielded_section - { - TransactionKind::TransparentTransfer(Some(data.into())) - } else { - TransactionKind::MixedTransfer(Some(data.into())) + .fold((true, false), |(all, any), (acc, _)| { + let is_masp = acc.owner.eq(masp_address); + (all && is_masp, any || is_masp) + }); + + match ( + all_sources_are_masp, + any_sources_are_masp, + all_targets_are_masp, + any_targets_are_masp, + has_shielded_section, + ) { + (true, _, true, _, true) => { + TransactionKind::ShieldedTransfer(Some(data.into())) + } + (true, _, _, false, true) => { + TransactionKind::UnshieldingTransfer(Some( + data.into(), + )) + } + (false, _, true, _, true) => { + TransactionKind::ShieldingTransfer(Some( + data.into(), + )) + } + (false, _, false, _, false) => { + TransactionKind::TransparentTransfer(Some( + data.into(), + )) + } + _ => TransactionKind::MixedTransfer(Some(data.into())), } } else { TransactionKind::Unknown From 1228efa817253b5a8d0b1fb2ca95911df439889b Mon Sep 17 00:00:00 2001 From: Gianmarco Fraccaroli Date: Thu, 16 Jan 2025 17:01:55 +0100 Subject: [PATCH 3/6] added ibc transfers --- .../down.sql | 2 + .../up.sql | 4 + orm/src/transactions.rs | 12 ++ shared/src/block.rs | 195 ++++++++++++++++++ shared/src/transaction.rs | 150 +++++++++++++- webserver/src/response/transaction.rs | 12 ++ 6 files changed, 370 insertions(+), 5 deletions(-) create mode 100644 orm/migrations/2025-01-16-131336_transaction_ibc_types/down.sql create mode 100644 orm/migrations/2025-01-16-131336_transaction_ibc_types/up.sql diff --git a/orm/migrations/2025-01-16-131336_transaction_ibc_types/down.sql b/orm/migrations/2025-01-16-131336_transaction_ibc_types/down.sql new file mode 100644 index 000000000..c7c9cbeb4 --- /dev/null +++ b/orm/migrations/2025-01-16-131336_transaction_ibc_types/down.sql @@ -0,0 +1,2 @@ +-- This file should undo anything in `up.sql` +SELECT 1; \ No newline at end of file diff --git a/orm/migrations/2025-01-16-131336_transaction_ibc_types/up.sql b/orm/migrations/2025-01-16-131336_transaction_ibc_types/up.sql new file mode 100644 index 000000000..dd15f662a --- /dev/null +++ b/orm/migrations/2025-01-16-131336_transaction_ibc_types/up.sql @@ -0,0 +1,4 @@ +-- Your SQL goes here +ALTER TYPE TRANSACTION_KIND ADD VALUE 'ibc_transparent_transfer'; +ALTER TYPE TRANSACTION_KIND ADD VALUE 'ibc_shielding_transfer'; +ALTER TYPE TRANSACTION_KIND ADD VALUE 'ibc_unshielding_transfer'; \ No newline at end of file diff --git a/orm/src/transactions.rs b/orm/src/transactions.rs index 10bef7387..2892e18c1 100644 --- a/orm/src/transactions.rs +++ b/orm/src/transactions.rs @@ -18,6 +18,9 @@ pub enum TransactionKindDb { UnshieldingTransfer, MixedTransfer, IbcMsgTransfer, + IbcTransparentTransfer, + IbcShieldingTransfer, + IbcUnshieldingTransfer, Bond, Redelegation, Unbond, @@ -48,6 +51,15 @@ impl From for TransactionKindDb { TransactionKind::ShieldingTransfer(_) => Self::ShieldingTransfer, TransactionKind::MixedTransfer(_) => Self::MixedTransfer, TransactionKind::IbcMsgTransfer(_) => Self::IbcMsgTransfer, + TransactionKind::IbcTrasparentTransfer(_) => { + Self::IbcTransparentTransfer + } + TransactionKind::IbcShieldingTransfer(_) => { + Self::IbcShieldingTransfer + } + TransactionKind::IbcUnshieldingTransfer(_) => { + Self::IbcUnshieldingTransfer + } TransactionKind::Bond(_) => Self::Bond, TransactionKind::Redelegation(_) => Self::Redelegation, TransactionKind::Unbond(_) => Self::Unbond, diff --git a/shared/src/block.rs b/shared/src/block.rs index 30d78376c..4bacd70bb 100644 --- a/shared/src/block.rs +++ b/shared/src/block.rs @@ -389,6 +389,201 @@ impl Block { vec![] } } + TransactionKind::IbcTrasparentTransfer((ibc_message, _)) => { + if let Some(data) = ibc_message { + match data.0 { + IbcMessage::Transfer(transfer) => { + let sources = transfer + .clone() + .transfer + .unwrap_or_default() + .sources + .keys() + .map(|account| { + TransactionTarget::sent( + tx.tx_id.clone(), + account.owner.to_string(), + ) + }) + .collect::>(); + let targets = transfer + .transfer + .unwrap_or_default() + .targets + .keys() + .map(|account| { + TransactionTarget::sent( + tx.tx_id.clone(), + account.owner.to_string(), + ) + }) + .collect::>(); + [sources, targets].concat() + } + IbcMessage::NftTransfer(transfer) => { + let sources = transfer + .clone() + .transfer + .unwrap_or_default() + .sources + .keys() + .map(|account| { + TransactionTarget::sent( + tx.tx_id.clone(), + account.owner.to_string(), + ) + }) + .collect::>(); + let targets = transfer + .transfer + .unwrap_or_default() + .targets + .keys() + .map(|account| { + TransactionTarget::sent( + tx.tx_id.clone(), + account.owner.to_string(), + ) + }) + .collect::>(); + [sources, targets].concat() + } + _ => vec![], + } + } else { + vec![] + } + } + TransactionKind::IbcShieldingTransfer((ibc_message, _)) => { + if let Some(data) = ibc_message { + match data.0 { + IbcMessage::Transfer(transfer) => { + let sources = transfer + .clone() + .transfer + .unwrap_or_default() + .sources + .keys() + .map(|account| { + TransactionTarget::sent( + tx.tx_id.clone(), + account.owner.to_string(), + ) + }) + .collect::>(); + let targets = transfer + .transfer + .unwrap_or_default() + .targets + .keys() + .map(|account| { + TransactionTarget::sent( + tx.tx_id.clone(), + account.owner.to_string(), + ) + }) + .collect::>(); + [sources, targets].concat() + } + IbcMessage::NftTransfer(transfer) => { + let sources = transfer + .clone() + .transfer + .unwrap_or_default() + .sources + .keys() + .map(|account| { + TransactionTarget::sent( + tx.tx_id.clone(), + account.owner.to_string(), + ) + }) + .collect::>(); + let targets = transfer + .transfer + .unwrap_or_default() + .targets + .keys() + .map(|account| { + TransactionTarget::sent( + tx.tx_id.clone(), + account.owner.to_string(), + ) + }) + .collect::>(); + [sources, targets].concat() + } + _ => vec![], + } + } else { + vec![] + } + } + TransactionKind::IbcUnshieldingTransfer((ibc_message, _)) => { + if let Some(data) = ibc_message { + match data.0 { + IbcMessage::Transfer(transfer) => { + let sources = transfer + .clone() + .transfer + .unwrap_or_default() + .sources + .keys() + .map(|account| { + TransactionTarget::sent( + tx.tx_id.clone(), + account.owner.to_string(), + ) + }) + .collect::>(); + let targets = transfer + .transfer + .unwrap_or_default() + .targets + .keys() + .map(|account| { + TransactionTarget::sent( + tx.tx_id.clone(), + account.owner.to_string(), + ) + }) + .collect::>(); + [sources, targets].concat() + } + IbcMessage::NftTransfer(transfer) => { + let sources = transfer + .clone() + .transfer + .unwrap_or_default() + .sources + .keys() + .map(|account| { + TransactionTarget::sent( + tx.tx_id.clone(), + account.owner.to_string(), + ) + }) + .collect::>(); + let targets = transfer + .transfer + .unwrap_or_default() + .targets + .keys() + .map(|account| { + TransactionTarget::sent( + tx.tx_id.clone(), + account.owner.to_string(), + ) + }) + .collect::>(); + [sources, targets].concat() + } + _ => vec![], + } + } else { + vec![] + } + } TransactionKind::Bond(bond) => { if let Some(data) = bond { let source = diff --git a/shared/src/transaction.rs b/shared/src/transaction.rs index c0554d311..6186c3068 100644 --- a/shared/src/transaction.rs +++ b/shared/src/transaction.rs @@ -38,6 +38,9 @@ pub enum TransactionKind { UnshieldingTransfer(Option), MixedTransfer(Option), IbcMsgTransfer(Option>), + IbcTrasparentTransfer((Option>, TransferData)), + IbcShieldingTransfer((Option>, TransferData)), + IbcUnshieldingTransfer((Option>, TransferData)), Bond(Option), Redelegation(Option), Unbond(Option), @@ -222,15 +225,152 @@ impl TransactionKind { TransactionKind::ReactivateValidator(data) } "tx_ibc" => { - let data = if let Ok(data) = + if let Ok(ibc_data) = namada_ibc::decode_message::(data) { - Some(data) + match ibc_data.clone() { + namada_ibc::IbcMessage::Envelope(_msg_envelope) => { + TransactionKind::IbcMsgTransfer(Some(IbcMessage( + ibc_data, + ))) + } + namada_ibc::IbcMessage::Transfer(transfer) => { + if let Some(data) = transfer.transfer { + let has_shielded_section = + data.shielded_section_hash.is_some(); + + let ( + all_sources_are_masp, + any_sources_are_masp, + ) = data.sources.iter().fold( + (true, false), + |(all, any), (acc, _)| { + let is_masp = + acc.owner.eq(masp_address); + (all && is_masp, any || is_masp) + }, + ); + + let ( + all_targets_are_masp, + any_targets_are_masp, + ) = data.targets.iter().fold( + (true, false), + |(all, any), (acc, _)| { + let is_masp = + acc.owner.eq(masp_address); + (all && is_masp, any || is_masp) + }, + ); + + match ( + all_sources_are_masp, + any_sources_are_masp, + all_targets_are_masp, + any_targets_are_masp, + has_shielded_section, + ) { + (true, _, _, false, true) => { + TransactionKind::IbcUnshieldingTransfer( + ( + Some(IbcMessage(ibc_data)), + data.into(), + ), + ) + } + (false, _, true, _, true) => { + TransactionKind::IbcShieldingTransfer(( + Some(IbcMessage(ibc_data)), + data.into(), + )) + } + (false, _, false, _, false) => { + TransactionKind::IbcTrasparentTransfer( + ( + Some(IbcMessage(ibc_data)), + data.into(), + ), + ) + } + _ => TransactionKind::MixedTransfer(Some( + data.into(), + )), + } + } else { + TransactionKind::IbcMsgTransfer(None) + } + } + namada_ibc::IbcMessage::NftTransfer(transfer) => { + if let Some(data) = transfer.transfer { + let has_shielded_section = + data.shielded_section_hash.is_some(); + + let ( + all_sources_are_masp, + any_sources_are_masp, + ) = data.sources.iter().fold( + (true, false), + |(all, any), (acc, _)| { + let is_masp = + acc.owner.eq(masp_address); + (all && is_masp, any || is_masp) + }, + ); + + let ( + all_targets_are_masp, + any_targets_are_masp, + ) = data.targets.iter().fold( + (true, false), + |(all, any), (acc, _)| { + let is_masp = + acc.owner.eq(masp_address); + (all && is_masp, any || is_masp) + }, + ); + + match ( + all_sources_are_masp, + any_sources_are_masp, + all_targets_are_masp, + any_targets_are_masp, + has_shielded_section, + ) { + (true, _, _, false, true) => { + TransactionKind::IbcUnshieldingTransfer( + ( + Some(IbcMessage(ibc_data)), + data.into(), + ), + ) + } + (false, _, true, _, true) => { + TransactionKind::IbcShieldingTransfer(( + Some(IbcMessage(ibc_data)), + data.into(), + )) + } + (false, _, false, _, false) => { + TransactionKind::IbcTrasparentTransfer( + ( + Some(IbcMessage(ibc_data)), + data.into(), + ), + ) + } + _ => TransactionKind::MixedTransfer(Some( + data.into(), + )), + } + } else { + TransactionKind::IbcMsgTransfer(None) + } + } + } } else { tracing::warn!("Cannot deserialize IBC transfer"); - None - }; - TransactionKind::IbcMsgTransfer(data.map(IbcMessage)) + TransactionKind::IbcMsgTransfer(None) + } } "tx_unjail_validator" => { let data = if let Ok(data) = Address::try_from_slice(data) { diff --git a/webserver/src/response/transaction.rs b/webserver/src/response/transaction.rs index e24d746ac..b011e8d17 100644 --- a/webserver/src/response/transaction.rs +++ b/webserver/src/response/transaction.rs @@ -30,6 +30,9 @@ pub enum TransactionKind { ChangeCommission, RevealPk, IbcMsgTransfer, + IbcTransparentTransfer, + IbcShieldingTransfer, + IbcUnshieldingTransfer, BecomeValidator, DeactivateValidator, ReactivateValidator, @@ -114,6 +117,15 @@ impl From for TransactionKind { TransactionKindDb::RevealPk => Self::RevealPk, TransactionKindDb::Unknown => Self::Unknown, TransactionKindDb::IbcMsgTransfer => Self::IbcMsgTransfer, + TransactionKindDb::IbcTransparentTransfer => { + Self::IbcTransparentTransfer + } + TransactionKindDb::IbcShieldingTransfer => { + Self::IbcShieldingTransfer + } + TransactionKindDb::IbcUnshieldingTransfer => { + Self::IbcUnshieldingTransfer + } TransactionKindDb::BecomeValidator => Self::BecomeValidator, TransactionKindDb::ReactivateValidator => Self::ReactivateValidator, TransactionKindDb::DeactivateValidator => Self::DeactivateValidator, From de3175f7de6a4b45a1c344e315dac8e6acb70215 Mon Sep 17 00:00:00 2001 From: Gianmarco Fraccaroli Date: Mon, 20 Jan 2025 15:26:59 +0100 Subject: [PATCH 4/6] refactor --- shared/src/gas.rs | 18 ++++ shared/src/transaction.rs | 177 ++------------------------------ shared/src/utils.rs | 96 +++++++++++++++++ transactions/src/services/tx.rs | 7 +- 4 files changed, 128 insertions(+), 170 deletions(-) diff --git a/shared/src/gas.rs b/shared/src/gas.rs index 09f5f65fe..6399b683e 100644 --- a/shared/src/gas.rs +++ b/shared/src/gas.rs @@ -13,8 +13,11 @@ pub struct GasEstimation { pub transparent_transfer: u64, pub shielded_transfer: u64, pub shielding_transfer: u64, + pub ibc_unshielding_transfer: u64, + pub ibc_shielding_transfer: u64, pub unshielding_transfer: u64, pub ibc_msg_transfer: u64, + pub mixed_transfer: u64, pub bond: u64, pub redelegation: u64, pub unbond: u64, @@ -34,7 +37,10 @@ impl GasEstimation { shielded_transfer: 0, shielding_transfer: 0, unshielding_transfer: 0, + ibc_shielding_transfer: 0, + ibc_unshielding_transfer: 0, ibc_msg_transfer: 0, + mixed_transfer: 0, bond: 0, redelegation: 0, unbond: 0, @@ -63,6 +69,18 @@ impl GasEstimation { self.unshielding_transfer += 1 } + pub fn increase_mixed_transfer(&mut self) { + self.mixed_transfer += 1 + } + + pub fn increase_ibc_shielding_transfer(&mut self) { + self.ibc_shielding_transfer += 1 + } + + pub fn increase_ibc_unshielding_transfer(&mut self) { + self.ibc_unshielding_transfer += 1 + } + pub fn increase_ibc_msg_transfer(&mut self) { self.ibc_msg_transfer += 1 } diff --git a/shared/src/transaction.rs b/shared/src/transaction.rs index 6186c3068..4a22125c9 100644 --- a/shared/src/transaction.rs +++ b/shared/src/transaction.rs @@ -21,6 +21,7 @@ use crate::block_result::{BlockResult, TxEventStatusCode}; use crate::checksums::Checksums; use crate::id::Id; use crate::ser::{IbcMessage, TransferData}; +use crate::utils::{self, transfer_to_ibc_tx_kind}; // We wrap public key in a struct so we serialize data as object instead of // string @@ -70,58 +71,12 @@ impl TransactionKind { ) -> Self { match tx_kind_name { "tx_transfer" => { - if let Ok(data) = Transfer::try_from_slice(data) { - let has_shielded_section = - data.shielded_section_hash.is_some(); - - let (all_sources_are_masp, any_sources_are_masp) = data - .sources - .iter() - .fold((true, false), |(all, any), (acc, _)| { - let is_masp = acc.owner.eq(masp_address); - (all && is_masp, any || is_masp) - }); - - let (all_targets_are_masp, any_targets_are_masp) = data - .targets - .iter() - .fold((true, false), |(all, any), (acc, _)| { - let is_masp = acc.owner.eq(masp_address); - (all && is_masp, any || is_masp) - }); - - match ( - all_sources_are_masp, - any_sources_are_masp, - all_targets_are_masp, - any_targets_are_masp, - has_shielded_section, - ) { - (true, _, true, _, true) => { - TransactionKind::ShieldedTransfer(Some(data.into())) - } - (true, _, _, false, true) => { - TransactionKind::UnshieldingTransfer(Some( - data.into(), - )) - } - (false, _, true, _, true) => { - TransactionKind::ShieldingTransfer(Some( - data.into(), - )) - } - (false, _, false, _, false) => { - TransactionKind::TransparentTransfer(Some( - data.into(), - )) - } - _ => TransactionKind::MixedTransfer(Some(data.into())), - } + if let Ok(transfer) = Transfer::try_from_slice(data) { + utils::transfer_to_tx_kind(transfer, masp_address) } else { TransactionKind::Unknown } } - "tx_bond" => { let data = if let Ok(data) = Bond::try_from_slice(data) { Some(data) @@ -236,132 +191,18 @@ impl TransactionKind { } namada_ibc::IbcMessage::Transfer(transfer) => { if let Some(data) = transfer.transfer { - let has_shielded_section = - data.shielded_section_hash.is_some(); - - let ( - all_sources_are_masp, - any_sources_are_masp, - ) = data.sources.iter().fold( - (true, false), - |(all, any), (acc, _)| { - let is_masp = - acc.owner.eq(masp_address); - (all && is_masp, any || is_masp) - }, - ); - - let ( - all_targets_are_masp, - any_targets_are_masp, - ) = data.targets.iter().fold( - (true, false), - |(all, any), (acc, _)| { - let is_masp = - acc.owner.eq(masp_address); - (all && is_masp, any || is_masp) - }, - ); - - match ( - all_sources_are_masp, - any_sources_are_masp, - all_targets_are_masp, - any_targets_are_masp, - has_shielded_section, - ) { - (true, _, _, false, true) => { - TransactionKind::IbcUnshieldingTransfer( - ( - Some(IbcMessage(ibc_data)), - data.into(), - ), - ) - } - (false, _, true, _, true) => { - TransactionKind::IbcShieldingTransfer(( - Some(IbcMessage(ibc_data)), - data.into(), - )) - } - (false, _, false, _, false) => { - TransactionKind::IbcTrasparentTransfer( - ( - Some(IbcMessage(ibc_data)), - data.into(), - ), - ) - } - _ => TransactionKind::MixedTransfer(Some( - data.into(), - )), - } + utils::transfer_to_tx_kind(data, masp_address) } else { TransactionKind::IbcMsgTransfer(None) } } namada_ibc::IbcMessage::NftTransfer(transfer) => { if let Some(data) = transfer.transfer { - let has_shielded_section = - data.shielded_section_hash.is_some(); - - let ( - all_sources_are_masp, - any_sources_are_masp, - ) = data.sources.iter().fold( - (true, false), - |(all, any), (acc, _)| { - let is_masp = - acc.owner.eq(masp_address); - (all && is_masp, any || is_masp) - }, - ); - - let ( - all_targets_are_masp, - any_targets_are_masp, - ) = data.targets.iter().fold( - (true, false), - |(all, any), (acc, _)| { - let is_masp = - acc.owner.eq(masp_address); - (all && is_masp, any || is_masp) - }, - ); - - match ( - all_sources_are_masp, - any_sources_are_masp, - all_targets_are_masp, - any_targets_are_masp, - has_shielded_section, - ) { - (true, _, _, false, true) => { - TransactionKind::IbcUnshieldingTransfer( - ( - Some(IbcMessage(ibc_data)), - data.into(), - ), - ) - } - (false, _, true, _, true) => { - TransactionKind::IbcShieldingTransfer(( - Some(IbcMessage(ibc_data)), - data.into(), - )) - } - (false, _, false, _, false) => { - TransactionKind::IbcTrasparentTransfer( - ( - Some(IbcMessage(ibc_data)), - data.into(), - ), - ) - } - _ => TransactionKind::MixedTransfer(Some( - data.into(), - )), - } + transfer_to_ibc_tx_kind( + data, + masp_address, + ibc_data, + ) } else { TransactionKind::IbcMsgTransfer(None) } diff --git a/shared/src/utils.rs b/shared/src/utils.rs index 4cd834ae5..5876113dc 100644 --- a/shared/src/utils.rs +++ b/shared/src/utils.rs @@ -1,5 +1,11 @@ +use namada_ibc::IbcMessage; +use namada_sdk::address::Address; +use namada_sdk::token::Transfer; + use crate::id::Id; +use crate::ser; use crate::token::Token; +use crate::transaction::TransactionKind; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct BalanceChange { @@ -25,3 +31,93 @@ pub struct DelegationPair { pub validator_address: Id, pub delegator_address: Id, } + +pub fn transfer_to_tx_kind( + data: Transfer, + masp_address: &Address, +) -> TransactionKind { + let has_shielded_section = data.shielded_section_hash.is_some(); + + let (all_sources_are_masp, any_sources_are_masp) = data + .sources + .iter() + .fold((true, false), |(all, any), (acc, _)| { + let is_masp = acc.owner.eq(masp_address); + (all && is_masp, any || is_masp) + }); + + let (all_targets_are_masp, any_targets_are_masp) = data + .targets + .iter() + .fold((true, false), |(all, any), (acc, _)| { + let is_masp = acc.owner.eq(masp_address); + (all && is_masp, any || is_masp) + }); + + match ( + all_sources_are_masp, + any_sources_are_masp, + all_targets_are_masp, + any_targets_are_masp, + has_shielded_section, + ) { + (true, _, true, _, true) => { + TransactionKind::ShieldedTransfer(Some(data.into())) + } + (true, _, _, false, true) => { + TransactionKind::UnshieldingTransfer(Some(data.into())) + } + (false, _, true, _, true) => { + TransactionKind::ShieldingTransfer(Some(data.into())) + } + (false, _, false, _, false) => { + TransactionKind::TransparentTransfer(Some(data.into())) + } + _ => TransactionKind::MixedTransfer(Some(data.into())), + } +} + +pub fn transfer_to_ibc_tx_kind( + data: Transfer, + masp_address: &Address, + ibc_data: IbcMessage, +) -> TransactionKind { + let has_shielded_section = data.shielded_section_hash.is_some(); + + let (all_sources_are_masp, any_sources_are_masp) = data + .sources + .iter() + .fold((true, false), |(all, any), (acc, _)| { + let is_masp = acc.owner.eq(masp_address); + (all && is_masp, any || is_masp) + }); + + let (all_targets_are_masp, any_targets_are_masp) = data + .targets + .iter() + .fold((true, false), |(all, any), (acc, _)| { + let is_masp = acc.owner.eq(masp_address); + (all && is_masp, any || is_masp) + }); + + match ( + all_sources_are_masp, + any_sources_are_masp, + all_targets_are_masp, + any_targets_are_masp, + has_shielded_section, + ) { + (true, _, _, false, true) => TransactionKind::IbcUnshieldingTransfer(( + Some(ser::IbcMessage(ibc_data)), + data.into(), + )), + (false, _, true, _, true) => TransactionKind::IbcShieldingTransfer(( + Some(ser::IbcMessage(ibc_data)), + data.into(), + )), + (false, _, false, _, false) => TransactionKind::IbcTrasparentTransfer( + (Some(ser::IbcMessage(ibc_data)), data.into()), + ), + _ => TransactionKind::MixedTransfer(Some(data.into())), + } +} diff --git a/transactions/src/services/tx.rs b/transactions/src/services/tx.rs index 7b56c4e57..10ed89751 100644 --- a/transactions/src/services/tx.rs +++ b/transactions/src/services/tx.rs @@ -135,7 +135,7 @@ pub fn get_gas_estimates( .for_each(|tx| match tx.kind { TransactionKind::TransparentTransfer(_) | TransactionKind::MixedTransfer(_) => { - gas_estimate.increase_transparent_transfer() + gas_estimate.increase_mixed_transfer() } TransactionKind::IbcMsgTransfer(_) => { gas_estimate.increase_ibc_msg_transfer() @@ -166,7 +166,10 @@ pub fn get_gas_estimates( gas_estimate.increase_shielding_transfer() } TransactionKind::UnshieldingTransfer(_) => { - gas_estimate.increase_unshielding_transfer() + gas_estimate.increase_ibc_unshielding_transfer() + } + TransactionKind::IbcShieldingTransfer(_) => { + gas_estimate.increase_ibc_shielding_transfer() } _ => (), }); From 9a9e31564f547c765d659faba1be92ac7c1a623c Mon Sep 17 00:00:00 2001 From: Gianmarco Fraccaroli Date: Tue, 21 Jan 2025 10:07:46 +0100 Subject: [PATCH 5/6] fix ibc acks --- transactions/src/services/tx.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/transactions/src/services/tx.rs b/transactions/src/services/tx.rs index 10ed89751..7a0031a2f 100644 --- a/transactions/src/services/tx.rs +++ b/transactions/src/services/tx.rs @@ -3,10 +3,9 @@ use namada_sdk::ibc::core::channel::types::msgs::PacketMsg; use namada_sdk::ibc::core::handler::types::msgs::MsgEnvelope; use shared::block_result::{BlockResult, TxAttributesType}; use shared::gas::GasEstimation; -use shared::ser::IbcMessage; use shared::transaction::{ - IbcAck, IbcAckStatus, IbcSequence, InnerTransaction, TransactionExitStatus, - TransactionKind, WrapperTransaction, + IbcAck, IbcAckStatus, IbcSequence, InnerTransaction, TransactionKind, + WrapperTransaction, }; pub fn get_ibc_packets( @@ -18,8 +17,11 @@ pub fn get_ibc_packets( .filter_map(|tx| { if matches!( tx.kind, - TransactionKind::IbcMsgTransfer(Some(IbcMessage(_))) - ) && matches!(tx.exit_code, TransactionExitStatus::Applied) + TransactionKind::IbcMsgTransfer(Some(_)) + | TransactionKind::IbcTrasparentTransfer(_) + | TransactionKind::IbcUnshieldingTransfer(_) + | TransactionKind::IbcShieldingTransfer(_) + ) && tx.was_successful() { Some(tx.tx_id.clone()) } else { From 711be21a175ff7536840674be76167a5a44bf0e2 Mon Sep 17 00:00:00 2001 From: Gianmarco Fraccaroli Date: Tue, 21 Jan 2025 11:47:15 +0100 Subject: [PATCH 6/6] fix ibc ack --- shared/src/block_result.rs | 2 -- shared/src/transaction.rs | 10 ++++++++++ transactions/src/services/tx.rs | 9 +-------- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/shared/src/block_result.rs b/shared/src/block_result.rs index a140abe9d..42d47989a 100644 --- a/shared/src/block_result.rs +++ b/shared/src/block_result.rs @@ -159,8 +159,6 @@ impl TxAttributesType { .unwrap_or_default() .to_owned(); - tracing::error!("{}", timeout_timestamp); - Some(Self::SendPacket(SendPacket { source_port, dest_port, diff --git a/shared/src/transaction.rs b/shared/src/transaction.rs index 4a22125c9..a6360f100 100644 --- a/shared/src/transaction.rs +++ b/shared/src/transaction.rs @@ -311,6 +311,16 @@ impl InnerTransaction { pub fn was_successful(&self) -> bool { self.exit_code == TransactionExitStatus::Applied } + + pub fn is_ibc(&self) -> bool { + matches!( + self.kind, + TransactionKind::IbcMsgTransfer(_) + | TransactionKind::IbcTrasparentTransfer(_) + | TransactionKind::IbcUnshieldingTransfer(_) + | TransactionKind::IbcShieldingTransfer(_) + ) + } } #[derive(Debug, Clone)] diff --git a/transactions/src/services/tx.rs b/transactions/src/services/tx.rs index 7a0031a2f..2c534a2dc 100644 --- a/transactions/src/services/tx.rs +++ b/transactions/src/services/tx.rs @@ -15,14 +15,7 @@ pub fn get_ibc_packets( let mut ibc_txs = inner_txs .iter() .filter_map(|tx| { - if matches!( - tx.kind, - TransactionKind::IbcMsgTransfer(Some(_)) - | TransactionKind::IbcTrasparentTransfer(_) - | TransactionKind::IbcUnshieldingTransfer(_) - | TransactionKind::IbcShieldingTransfer(_) - ) && tx.was_successful() - { + if tx.is_ibc() && tx.was_successful() { Some(tx.tx_id.clone()) } else { None