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

Make the sender set MASP transaction to IBC memo #3444

Merged
merged 40 commits into from
Jul 5, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
e02fe43
Now hash the TransferTarget into Transaction transparent outputs.
murisi May 28, 2024
6cbe813
Modified the MASP VP to check the IBC receivers.
murisi May 31, 2024
20d113b
Created a separate type that is either an Address or IBC receiver.
murisi Jun 1, 2024
2b49dc0
Now check that the IBC events are valid with respect to storage changes.
murisi Jun 4, 2024
abbf3b2
Split up the IBC validation logic in MASP.
murisi Jun 7, 2024
b55f5bc
Centralized the construction of TransparentAddresses to ensure that e…
murisi Jun 11, 2024
5547f09
Handle the is_sender_chain_source case in the MASP VP.
murisi Jun 11, 2024
423ee7f
Ensure that native tokens can always be decoded.
murisi Jun 12, 2024
0ae6f2b
Reduced the dependence on IBC events.
murisi Jun 12, 2024
438a4ab
Merge branch 'base' into murisi/masp-ibc-replay-protection-using-txda…
murisi Jun 12, 2024
08e5664
Subdivided some functions involved in processing IBC packets.
murisi Jun 14, 2024
a2854e7
Now map denominations to tokens using ibc_token instead of reverse_qu…
murisi Jun 19, 2024
6739f0b
Removed is_any_shielded_action_balance_key and related code since tha…
murisi Jun 19, 2024
18fe989
Simplify checking packet acknowledgement by assuming the uniqueness o…
murisi Jun 19, 2024
8de2ec0
Added more comments and improved function naming.
murisi Jun 19, 2024
0c999bd
Start using IBC ports to determine message formats.
murisi Jun 19, 2024
d0b4f3d
Now charge gas in IBC denom query.
murisi Jun 19, 2024
0a5d480
Update balances in the MASP using a non-mutating style.
murisi Jun 19, 2024
7ff94bd
Added changelog entry.
murisi Jun 20, 2024
d44fc56
support NftTransfer
yito88 Jun 18, 2024
320e9ed
fix for apply_recv_msg
yito88 Jun 19, 2024
60ea876
refactoring: add trace.rs
yito88 Jun 20, 2024
a942176
reduce assumptions for IBC VP
yito88 Jun 21, 2024
9c51728
add ibc trace file
yito88 Jun 21, 2024
fb19c25
fix convert_to_address
yito88 Jun 21, 2024
210f34b
fix tests
yito88 Jun 21, 2024
5c3b3ab
fix the port and channel for is_receiving_success
yito88 Jun 24, 2024
8d23661
memo for masp tx
yito88 Jun 26, 2024
5c0c424
extract masp_tx in MASP VP
yito88 Jun 26, 2024
6520631
add CLI ibc-gen-shielding
yito88 Jun 26, 2024
c74c583
fix e2e tests
yito88 Jun 28, 2024
3176b01
fix gen_masp_tx in test
yito88 Jul 1, 2024
d6fc2f2
workaround wasm compilation error
yito88 Jul 1, 2024
a59131d
add IbcShielding action
yito88 Jul 1, 2024
ad065b0
add changelog
yito88 Jul 1, 2024
da7aff4
IbcShieldingData
yito88 Jul 2, 2024
cbf27b1
update Hermes
yito88 Jul 2, 2024
be2e7df
fix refund source
yito88 Jul 2, 2024
ca79554
extract_memo_from_packet
yito88 Jul 3, 2024
7212f7e
remove --refund
yito88 Jul 4, 2024
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Fix IBC shielding transfer for the receiver not to be replaced by a malicious
relayer ([\#3438](https://github.com/anoma/namada/issues/3438))
2 changes: 1 addition & 1 deletion .github/workflows/scripts/hermes.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.8.2-namada-beta11-rc2
1.9.0-namada-beta13-rc
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 34 additions & 6 deletions crates/apps_lib/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ pub mod cmds {
// Actions
.subcommand(SignTx::def().display_order(6))
.subcommand(ShieldedSync::def().display_order(6))
.subcommand(GenIbcShieldingTransfer::def().display_order(6))
// Utils
.subcommand(ClientUtils::def().display_order(7))
}
Expand Down Expand Up @@ -380,6 +381,8 @@ pub mod cmds {
Self::parse_with_ctx(matches, AddToEthBridgePool);
let sign_tx = Self::parse_with_ctx(matches, SignTx);
let shielded_sync = Self::parse_with_ctx(matches, ShieldedSync);
let gen_ibc_shielding =
Self::parse_with_ctx(matches, GenIbcShieldingTransfer);
let utils = SubCmd::parse(matches).map(Self::WithoutContext);
tx_custom
.or(tx_transparent_transfer)
Expand Down Expand Up @@ -434,6 +437,7 @@ pub mod cmds {
.or(query_account)
.or(sign_tx)
.or(shielded_sync)
.or(gen_ibc_shielding)
.or(utils)
}
}
Expand Down Expand Up @@ -524,6 +528,7 @@ pub mod cmds {
QueryRewards(QueryRewards),
SignTx(SignTx),
ShieldedSync(ShieldedSync),
GenIbcShieldingTransfer(GenIbcShieldingTransfer),
}

#[allow(clippy::large_enum_variant)]
Expand Down Expand Up @@ -2259,6 +2264,29 @@ pub mod cmds {
}
}

#[derive(Clone, Debug)]
pub struct GenIbcShieldingTransfer(
pub args::GenIbcShieldingTransfer<args::CliTypes>,
);

impl SubCmd for GenIbcShieldingTransfer {
const CMD: &'static str = "ibc-gen-shielding";

fn parse(matches: &ArgMatches) -> Option<Self> {
matches.subcommand_matches(Self::CMD).map(|matches| {
GenIbcShieldingTransfer(args::GenIbcShieldingTransfer::parse(
matches,
))
})
}

fn def() -> App {
App::new(Self::CMD)
.about("Generate shielding transfer for IBC.")
.add_args::<args::GenIbcShieldingTransfer<args::CliTypes>>()
}
}

#[derive(Clone, Debug)]
pub struct EpochSleep(pub args::Query<args::CliTypes>);

Expand Down Expand Up @@ -6432,19 +6460,19 @@ pub mod args {
}
}

impl CliToSdk<GenIbcShieldedTransfer<SdkTypes>>
for GenIbcShieldedTransfer<CliTypes>
impl CliToSdk<GenIbcShieldingTransfer<SdkTypes>>
for GenIbcShieldingTransfer<CliTypes>
{
type Error = std::convert::Infallible;

fn to_sdk(
self,
ctx: &mut Context,
) -> Result<GenIbcShieldedTransfer<SdkTypes>, Self::Error> {
) -> Result<GenIbcShieldingTransfer<SdkTypes>, Self::Error> {
let query = self.query.to_sdk(ctx)?;
let chain_ctx = ctx.borrow_chain_or_exit();

Ok(GenIbcShieldedTransfer::<SdkTypes> {
Ok(GenIbcShieldingTransfer::<SdkTypes> {
query,
output_folder: self.output_folder,
target: chain_ctx.get(&self.target),
Expand All @@ -6457,7 +6485,7 @@ pub mod args {
}
}

impl Args for GenIbcShieldedTransfer<CliTypes> {
impl Args for GenIbcShieldingTransfer<CliTypes> {
fn parse(matches: &ArgMatches) -> Self {
let query = Query::parse(matches);
let output_folder = OUTPUT_FOLDER_PATH.parse(matches);
Expand Down Expand Up @@ -6498,7 +6526,7 @@ pub mod args {
"The channel ID via which the token is received."
)))
.arg(REFUND.def().help(wrap!(
"Generate the shielded transfer for refunding."
"Generate the shielding transfer for refunding."
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is used to generate both the refunding tx and the actual shielding transfer on the destination chain, correct? If that's the case maybe we can change the message here

Copy link
Member Author

@yito88 yito88 Jul 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, Hermes used the argument. Now build_ibc_transfer generates the masp tx for the refunding.
Users don't have to generate it with this command anymore.
I'll remove this argument.

)))
}
}
Expand Down
14 changes: 14 additions & 0 deletions crates/apps_lib/src/cli/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,20 @@ impl CliApi {
)
.await?;
}
Sub::GenIbcShieldingTransfer(GenIbcShieldingTransfer(
args,
)) => {
let chain_ctx = ctx.borrow_mut_chain_or_exit();
let ledger_address =
chain_ctx.get(&args.query.ledger_address);
let client = client.unwrap_or_else(|| {
C::from_tendermint_address(&ledger_address)
});
client.wait_until_node_is_synced(&io).await?;
let args = args.to_sdk(&mut ctx)?;
let namada = ctx.to_sdk(client, io);
tx::gen_ibc_shielding_transfer(&namada, args).await?;
}
#[cfg(feature = "namada-eth-bridge")]
Sub::AddToEthBridgePool(args) => {
let args = args.0;
Expand Down
31 changes: 31 additions & 0 deletions crates/apps_lib/src/client/tx.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::fs::File;
use std::io::Write;

use borsh::BorshDeserialize;
use borsh_ext::BorshSerializeExt;
Expand All @@ -11,6 +12,7 @@ use namada::core::key::*;
use namada::governance::cli::onchain::{
DefaultProposal, PgfFundingProposal, PgfStewardProposal,
};
use namada::ibc::convert_masp_tx_to_ibc_memo;
use namada::io::Io;
use namada::state::EPOCH_SWITCH_BLOCKS_DELAY;
use namada::tx::{CompressedAuthorization, Section, Signer, Tx};
Expand Down Expand Up @@ -1352,3 +1354,32 @@ pub async fn submit_tx(
) -> Result<TxResponse, error::Error> {
tx::submit_tx(namada, to_broadcast).await
}

/// Generate MASP transaction and output it
pub async fn gen_ibc_shielding_transfer(
context: &impl Namada,
args: args::GenIbcShieldingTransfer,
) -> Result<(), error::Error> {
if let Some(masp_tx) =
tx::gen_ibc_shielding_transfer(context, args.clone()).await?
{
let tx_id = masp_tx.txid().to_string();
let filename = format!("ibc_masp_tx_{}.memo", tx_id);
let output_path = match &args.output_folder {
Some(path) => path.join(filename),
None => filename.into(),
};
let mut out = File::create(&output_path)
.expect("Creating a new file for IBC MASP transaction failed.");
let bytes = convert_masp_tx_to_ibc_memo(&masp_tx);
out.write_all(bytes.as_bytes())
.expect("Writing IBC MASP transaction file failed.");
println!(
"Output IBC shielding transfer for {tx_id} to {}",
output_path.to_string_lossy()
);
} else {
eprintln!("No shielded transfer for this IBC transfer.")
}
Ok(())
}
1 change: 1 addition & 0 deletions crates/ibc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ namada_storage = { path = "../storage" }
namada_token = { path = "../token" }

borsh.workspace = true
data-encoding.workspace = true
konst.workspace = true
linkme = {workspace = true, optional = true}
ibc.workspace = true
Expand Down
116 changes: 42 additions & 74 deletions crates/ibc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ use ibc::core::host::types::identifiers::{ChannelId, PortId, Sequence};
use ibc::core::router::types::error::RouterError;
use ibc::primitives::proto::Any;
pub use ibc::*;
use masp_primitives::transaction::Transaction as MaspTransaction;
pub use msg::*;
use namada_core::address::{self, Address};
use namada_core::arith::checked;
Expand Down Expand Up @@ -151,7 +152,8 @@ where
pub fn execute(
&mut self,
tx_data: &[u8],
) -> Result<Option<ShieldingTransfer>, Error> {
) -> Result<(Option<ShieldingTransfer>, Option<MaspTransaction>), Error>
{
let message = decode_message(tx_data)?;
match &message {
IbcMessage::Transfer(msg) => {
Expand All @@ -166,7 +168,7 @@ where
msg.message.clone(),
)
.map_err(Error::TokenTransfer)?;
Ok(msg.transfer.clone())
Ok((msg.transfer.clone(), None))
}
IbcMessage::NftTransfer(msg) => {
let mut nft_transfer_ctx =
Expand All @@ -177,47 +179,45 @@ where
msg.message.clone(),
)
.map_err(Error::NftTransfer)?;
Ok(msg.transfer.clone())
}
IbcMessage::RecvPacket(msg) => {
let envelope =
MsgEnvelope::Packet(PacketMsg::Recv(msg.message.clone()));
execute(&mut self.ctx, &mut self.router, envelope)
.map_err(|e| Error::Context(Box::new(e)))?;
let transfer = if self.is_receiving_success(&msg.message)? {
// For receiving the token to a shielded address
msg.transfer.clone()
} else {
None
};
Ok(transfer)
}
IbcMessage::AckPacket(msg) => {
let envelope =
MsgEnvelope::Packet(PacketMsg::Ack(msg.message.clone()));
execute(&mut self.ctx, &mut self.router, envelope)
.map_err(|e| Error::Context(Box::new(e)))?;
let transfer =
if !is_ack_successful(&msg.message.acknowledgement)? {
// For refunding the token to a shielded address
msg.transfer.clone()
} else {
None
};
Ok(transfer)
}
IbcMessage::Timeout(msg) => {
let envelope = MsgEnvelope::Packet(PacketMsg::Timeout(
msg.message.clone(),
));
execute(&mut self.ctx, &mut self.router, envelope)
.map_err(|e| Error::Context(Box::new(e)))?;
Ok(msg.transfer.clone())
Ok((msg.transfer.clone(), None))
}
IbcMessage::Envelope(envelope) => {
execute(&mut self.ctx, &mut self.router, *envelope.clone())
execute(&mut self.ctx, &mut self.router, envelope.clone())
.map_err(|e| Error::Context(Box::new(e)))?;
Ok(None)
// Extract MASP tx from the memo in the packet if needed
let masp_tx = match envelope {
MsgEnvelope::Packet(packet_msg) => {
match packet_msg {
PacketMsg::Recv(msg) => {
if self.is_receiving_success(msg)? {
extract_masp_tx_from_packet(
&msg.packet,
false,
)
} else {
None
}
}
PacketMsg::Ack(msg) => {
if is_ack_successful(&msg.acknowledgement)? {
// No refund
None
} else {
extract_masp_tx_from_packet(
&msg.packet,
true,
)
}
}
PacketMsg::Timeout(msg) => {
extract_masp_tx_from_packet(&msg.packet, true)
}
_ => None,
}
}
_ => None,
};
Ok((None, masp_tx))
}
}
}
Expand Down Expand Up @@ -275,26 +275,8 @@ where
)
.map_err(Error::NftTransfer)
}
IbcMessage::RecvPacket(msg) => validate(
&self.ctx,
&self.router,
MsgEnvelope::Packet(PacketMsg::Recv(msg.message)),
)
.map_err(|e| Error::Context(Box::new(e))),
IbcMessage::AckPacket(msg) => validate(
&self.ctx,
&self.router,
MsgEnvelope::Packet(PacketMsg::Ack(msg.message)),
)
.map_err(|e| Error::Context(Box::new(e))),
IbcMessage::Timeout(msg) => validate(
&self.ctx,
&self.router,
MsgEnvelope::Packet(PacketMsg::Timeout(msg.message)),
)
.map_err(|e| Error::Context(Box::new(e))),
IbcMessage::Envelope(envelope) => {
validate(&self.ctx, &self.router, *envelope)
validate(&self.ctx, &self.router, envelope)
.map_err(|e| Error::Context(Box::new(e)))
}
}
Expand Down Expand Up @@ -326,7 +308,7 @@ pub fn decode_message(tx_data: &[u8]) -> Result<IbcMessage, Error> {
// ibc-rs message
if let Ok(any_msg) = Any::decode(tx_data) {
if let Ok(envelope) = MsgEnvelope::try_from(any_msg) {
return Ok(IbcMessage::Envelope(Box::new(envelope)));
return Ok(IbcMessage::Envelope(envelope));
}
}

Expand All @@ -340,20 +322,6 @@ pub fn decode_message(tx_data: &[u8]) -> Result<IbcMessage, Error> {
return Ok(IbcMessage::NftTransfer(msg));
}

// Receiving packet message with `IbcShieldedTransfer`
if let Ok(msg) = MsgRecvPacket::try_from_slice(tx_data) {
return Ok(IbcMessage::RecvPacket(msg));
}

// Acknowledge packet message with `IbcShieldedTransfer`
if let Ok(msg) = MsgAcknowledgement::try_from_slice(tx_data) {
return Ok(IbcMessage::AckPacket(msg));
}
// Timeout packet message with `IbcShieldedTransfer`
if let Ok(msg) = MsgTimeout::try_from_slice(tx_data) {
return Ok(IbcMessage::Timeout(msg));
}

Err(Error::DecodingData)
}

Expand Down
Loading
Loading