Skip to content

Commit

Permalink
Added asset type decodings to the MaspBuilder section. Now use readab…
Browse files Browse the repository at this point in the history
…le token name in Ledger vectors.
  • Loading branch information
Murisi Tarusenga committed Apr 19, 2023
1 parent 1ff057a commit 4b65a73
Show file tree
Hide file tree
Showing 18 changed files with 153 additions and 37 deletions.
6 changes: 3 additions & 3 deletions Cargo.lock

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

61 changes: 52 additions & 9 deletions apps/src/lib/client/signing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ use namada::types::address::masp;
use namada::ibc::core::ics26_routing::msgs::Ics26Envelope;
use std::env;
use std::fs::File;
use std::collections::HashMap;
use masp_primitives::transaction::components::sapling::fees::{OutputView, InputView};
use masp_primitives::asset_type::AssetType;
use namada::types::masp::{PaymentAddress, ExtendedViewingKey};

use super::rpc;
Expand All @@ -36,6 +38,7 @@ use crate::client::tendermint_rpc_types::TxBroadcastData;
use crate::facade::tendermint_config::net::Address as TendermintAddress;
use crate::facade::tendermint_rpc::HttpClient;
use crate::wallet::Wallet;
use crate::client::tx::make_asset_type;
use crate::client::tx::{
TX_BOND_WASM, TX_CHANGE_COMMISSION_WASM, TX_IBC_WASM, TX_INIT_ACCOUNT_WASM,
TX_INIT_PROPOSAL, TX_INIT_VALIDATOR_WASM, TX_REVEAL_PK, TX_TRANSFER_WASM,
Expand Down Expand Up @@ -370,8 +373,13 @@ struct LedgerVector {
valid: bool,
}

/// Adds a Ledger output line describing a given transaction amount
fn make_ledger_amount(output: &mut Vec<String>, amount: Amount, token: &Address, prefix: &str) {
/// Adds a Ledger output line describing a given transaction amount and address
fn make_ledger_amount_addr(
output: &mut Vec<String>,
amount: Amount,
token: &Address,
prefix: &str,
) {
// To facilitate lookups of human-readable token names
let tokens = tokens();

Expand All @@ -386,6 +394,38 @@ fn make_ledger_amount(output: &mut Vec<String>, amount: Amount, token: &Address,
}
}

/// Adds a Ledger output line describing a given transaction amount and asset
/// type
fn make_ledger_amount_asset(
output: &mut Vec<String>,
amount: u64,
token: &AssetType,
assets: &HashMap<AssetType, (Address, Epoch)>,
prefix: &str,
) {
// To facilitate lookups of human-readable token names
let tokens = tokens();

if let Some((token, _epoch)) = assets.get(token) {
// If the AssetType can be decoded, then at least display Addressees
if let Some(token) = tokens.get(&token) {
output
.push(format!("3 | {}Amount: {} {}", prefix, token, Amount::from(amount)));
} else {
output.extend(vec![
format!("3 | {}Token: {}", prefix, token),
format!("4 | {}Amount: {}", prefix, Amount::from(amount)),
]);
}
} else {
// Otherwise display the raw AssetTypes
output.extend(vec![
format!("3 | {}Token: {}", prefix, token),
format!("4 | {}Amount: {}", prefix, Amount::from(amount)),
]);
}
}

/// Converts the given transaction to the form that is displayed on the Ledger
/// device
fn to_ledger_vector(
Expand Down Expand Up @@ -684,10 +724,15 @@ fn to_ledger_vector(
let transfer = Transfer::try_from_slice(
&tx.data().ok_or_else(|| Error::from(ErrorKind::InvalidData))?,
)?;
// To facilitate lookups of MASP AssetTypes
let mut asset_types = HashMap::new();
let builder = if let Some(shielded_hash) = transfer.shielded {
tx.sections.iter().find_map(|x| {
match x {
Section::MaspBuilder(builder) if builder.target == shielded_hash => {
for (addr, epoch) in &builder.asset_types {
asset_types.insert(make_asset_type(*epoch, addr), (addr.clone(), *epoch));
}
Some(builder)
},
_ => None,
Expand All @@ -703,31 +748,29 @@ fn to_ledger_vector(
if transfer.source != masp() {
tv.output.push(format!("1 | Sender: {}", transfer.source));
if transfer.target == masp() {
make_ledger_amount(&mut tv.output, transfer.amount, &transfer.token, "Sending ");
make_ledger_amount_addr(&mut tv.output, transfer.amount, &transfer.token, "Sending ");
}
} else if let Some(builder) = builder {
for input in builder.builder.sapling_inputs() {
let vk = ExtendedViewingKey::from(input.key().clone());
tv.output.push(format!("1 | Sender: {}", vk));
tv.output
.push(format!("3 | Sending: {} {}", input.asset_type(), Amount::from(input.value())));
make_ledger_amount_asset(&mut tv.output, input.value(), &input.asset_type(), &asset_types, "Sending ");
}
}
if transfer.target != masp() {
tv.output.push(format!("2 | Destination: {}", transfer.target));
if transfer.source == masp() {
make_ledger_amount(&mut tv.output, transfer.amount, &transfer.token, "Receiving ");
make_ledger_amount_addr(&mut tv.output, transfer.amount, &transfer.token, "Receiving ");
}
} else if let Some(builder) = builder {
for output in builder.builder.sapling_outputs() {
let pa = PaymentAddress::from(output.address().clone());
tv.output.push(format!("1 | Destination: {}", pa));
tv.output
.push(format!("3 | Receiving: {} {}", output.asset_type(), Amount::from(output.value())));
make_ledger_amount_asset(&mut tv.output, output.value(), &output.asset_type(), &asset_types, "Receiving ");
}
}
if transfer.source != masp() && transfer.target != masp() {
make_ledger_amount(&mut tv.output, transfer.amount, &transfer.token, "");
make_ledger_amount_addr(&mut tv.output, transfer.amount, &transfer.token, "");
}

tv.output_expert.extend(vec![
Expand Down
69 changes: 68 additions & 1 deletion apps/src/lib/client/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ use masp_primitives::transaction::TransparentAddress;
use masp_primitives::merkle_tree::{
CommitmentTree, IncrementalWitness, MerklePath,
};
use masp_primitives::transaction::components::sapling::fees::InputView as SaplingInputView;
use masp_primitives::transaction::components::sapling::fees::OutputView as SaplingOutputView;
use masp_primitives::transaction::components::transparent::fees::InputView as TransparentInputView;
use masp_primitives::transaction::components::transparent::fees::OutputView as TransparentOutputView;
use masp_primitives::transaction::components::sapling::fees::ConvertView;
use masp_primitives::transaction::fees::fixed::FeeRule;
use masp_primitives::transaction::Authorization;
use masp_primitives::transaction::Authorized;
Expand Down Expand Up @@ -1311,7 +1316,7 @@ impl ShieldedContext {
}

/// Make asset type corresponding to given address and epoch
fn make_asset_type(epoch: Epoch, token: &Address) -> AssetType {
pub fn make_asset_type(epoch: Epoch, token: &Address) -> AssetType {
// Typestamp the chosen token with the current epoch
let token_bytes = (token, epoch.0)
.try_to_vec()
Expand Down Expand Up @@ -1514,6 +1519,60 @@ where
.map(|(tx, metadata)| Some((builder.map_builder(WalletMap), tx, metadata)))
}

/// Try to decode the given asset type and add its decoding to the supplied set.
/// Returns true only if a new decoding has been added to the given set.
async fn add_asset_type(
asset_types: &mut HashSet<(Address, Epoch)>,
ctx: &mut Context,
client: &HttpClient,
asset_type: AssetType,
) -> bool {
if let Some(asset_type) = ctx
.shielded
.decode_asset_type(client.clone(), asset_type)
.await
{
asset_types.insert(asset_type)
} else {
false
}
}

/// Collect the asset types used in the given Builder and decode them. This
/// function provides the data necessary for offline wallets to present asset
/// type information.
async fn used_asset_types<P, R, K, N>(
ctx: &mut Context,
ledger_address: &TendermintAddress,
builder: &Builder<P, R, K, N>,
) -> Result<HashSet<(Address, Epoch)>, RpcError> {
let client = HttpClient::new(ledger_address.clone())?;
let mut asset_types = HashSet::new();
// Collect all the asset types used in the Sapling inputs
for input in builder.sapling_inputs() {
add_asset_type(&mut asset_types, ctx, &client, input.asset_type()).await;
}
// Collect all the asset types used in the transparent inputs
for input in builder.transparent_inputs() {
add_asset_type(&mut asset_types, ctx, &client, input.coin().asset_type()).await;
}
// Collect all the asset types used in the Sapling outputs
for output in builder.sapling_outputs() {
add_asset_type(&mut asset_types, ctx, &client, output.asset_type()).await;
}
// Collect all the asset types used in the transparent outputs
for output in builder.transparent_outputs() {
add_asset_type(&mut asset_types, ctx, &client, output.asset_type()).await;
}
// Collect all the asset types used in the Sapling converts
for output in builder.sapling_converts() {
for (asset_type, _) in Amount::from(output.conversion().clone()).components() {
add_asset_type(&mut asset_types, ctx, &client, asset_type.clone()).await;
}
}
Ok(asset_types)
}

pub async fn submit_transfer(mut ctx: Context, args: args::TxTransfer) {
let parsed_args = args.parse_from_context(&mut ctx);
let source = parsed_args.source.effective_address();
Expand Down Expand Up @@ -1692,8 +1751,16 @@ pub async fn submit_transfer(mut ctx: Context, args: args::TxTransfer) {
let masp_tx = tx.add_section(Section::MaspTx(shielded.1));
// Get the hash of the MASP Transaction section
let masp_hash = Hash(masp_tx.hash(&mut Sha256::new()).finalize_reset().into());
// Get the decoded asset types used in the transaction to give offline
// wallet users more information
let asset_types = used_asset_types(
&mut ctx,
&args.tx.ledger_address,
&shielded.0,
).await.unwrap_or_default();
// Add the MASP Transaction's Builder to the Tx
tx.add_section(Section::MaspBuilder(MaspBuilder {
asset_types,
// Store how the Info objects map to Descriptors/Outputs
metadata: shielded.2,
// Store the data that was used to construct the Transaction
Expand Down
6 changes: 6 additions & 0 deletions core/src/proto/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
use prost::Message;
use serde::{Deserialize, Serialize};
use thiserror::Error;
use std::collections::HashSet;

use super::generated::types;
#[cfg(any(feature = "tendermint", feature = "tendermint-abcipp"))]
Expand All @@ -24,6 +25,8 @@ use crate::types::transaction::EllipticCurve;
#[cfg(feature = "ferveo-tpke")]
use crate::types::transaction::EncryptionKey;
use crate::types::transaction::TxType;
use crate::types::address::Address;
use crate::types::storage::Epoch;
use crate::types::transaction::WrapperTx;
use sha2::{Digest, Sha256};
use crate::types::transaction::WrapperTxErr;
Expand Down Expand Up @@ -409,6 +412,9 @@ impl Into<Vec<u8>> for SaplingMetadataSerde {
pub struct MaspBuilder {
/// The MASP transaction that this section witnesses
pub target: crate::types::hash::Hash,
/// The decoded set of asset types used by the transaction. Useful for
/// offline wallets trying to display AssetTypes.
pub asset_types: HashSet<(Address, Epoch)>,
/// Track how Info objects map to descriptors and outputs
#[serde(
serialize_with = "borsh_serde::<SaplingMetadataSerde, _>",
Expand Down
6 changes: 3 additions & 3 deletions wasm/Cargo.lock

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

36 changes: 18 additions & 18 deletions wasm/checksums.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
{
"tx_bond.wasm": "tx_bond.7481e8507941b2fcf24d82abb6e094bef4df2bdff36a5ea8b8573bcc78f08836.wasm",
"tx_change_validator_commission.wasm": "tx_change_validator_commission.8c67738bee78e9dece8d9c3e53a2c81b52ae2191cbc0ddaa6ebdb35c76c6bd99.wasm",
"tx_ibc.wasm": "tx_ibc.1a1dc311b8480676ee1ada5af20b0322c6373d5fc94501f32906e0b7d922ef60.wasm",
"tx_init_account.wasm": "tx_init_account.8933f9a4634df4e744e6d78a90a07d4b80115b7ecb3c41c3825f785bbadb3f1a.wasm",
"tx_init_proposal.wasm": "tx_init_proposal.a5e9a6a7e0254e62f8fb6652c093988b438b6c202f7c43a7b16d31beeb102211.wasm",
"tx_init_validator.wasm": "tx_init_validator.4154b594fb379e6d5bdec6a2b7fb8dd6a40c911c689aed957f6b39d282750f4c.wasm",
"tx_reveal_pk.wasm": "tx_reveal_pk.d0862cdb7e3b94bccdcd77ea475202380f3179b856cffcb922616dd555ab602b.wasm",
"tx_transfer.wasm": "tx_transfer.01c1c3435e6996222c63b3ddb66c6f20dc36149fa98b81bbbf2f31f1c0f8f9a8.wasm",
"tx_unbond.wasm": "tx_unbond.8a5c031688c0e6aeb1d7a3b9fd7f948bd021331617ba579e4e9316c10eae95da.wasm",
"tx_update_vp.wasm": "tx_update_vp.48f2bc1c8c3fce39b802919c0bae43b7b004f2ad56404d999f57f7ab2c709767.wasm",
"tx_vote_proposal.wasm": "tx_vote_proposal.05aecde612c18e0e9f9585942e85367159caececfac356c855c72b7f4258785e.wasm",
"tx_withdraw.wasm": "tx_withdraw.9ac4085379ffae07e1baa9f79ae39dcb515fe2a9510d5f6013f9615f993ae501.wasm",
"vp_implicit.wasm": "vp_implicit.9dfe2c522696c42b23cc89091f8abea75f4c7735e3ea4a7ee53f218d7ebdaa64.wasm",
"vp_masp.wasm": "vp_masp.8970934897fc330b563add228766fa261e9ca6db0016e31885e6bf2ba969bd33.wasm",
"vp_testnet_faucet.wasm": "vp_testnet_faucet.65074afddb052ec24c49f3ed10609eac1e374a1541c473e357a5ea618a47a44d.wasm",
"vp_token.wasm": "vp_token.b2840bd73c667b6c4ee3e1962912233728c69c06b5e88cac19eb3f9df867116a.wasm",
"vp_user.wasm": "vp_user.2a4a2efc2d2c5c67fda9232a4c1c24dd298c5765ade942e87ce793d08441428f.wasm",
"vp_validator.wasm": "vp_validator.43e94992e63bcf92fe395ef1f87b69bc21c4ca6e8ab11beb7d4c6059c0778168.wasm"
"tx_bond.wasm": "tx_bond.21c63b00f018639afaf0e320e1684bf00a54010a282bde66cf6423cb493d26b6.wasm",
"tx_change_validator_commission.wasm": "tx_change_validator_commission.cf82fc5c0ffdce7933c8eb86f1dab1c4ef19153488abe26fb519fe8efab8cfb1.wasm",
"tx_ibc.wasm": "tx_ibc.0f7b3e11f13be3ef99829d84a675bb97133c0f69b2cffe8d6b028c5a381b462e.wasm",
"tx_init_account.wasm": "tx_init_account.8b7389277b309099b3911b99708e6e555797688e20dd0d913b28947c55817689.wasm",
"tx_init_proposal.wasm": "tx_init_proposal.b543d9ba1f3700b474e48851442a4ea7d5abaf2fcfb14c2df4adc81b08d54492.wasm",
"tx_init_validator.wasm": "tx_init_validator.e95087d4cd16d6e5227527e815e4c600bc663a1acd6d32b33eefffc3ffee3d36.wasm",
"tx_reveal_pk.wasm": "tx_reveal_pk.2d7d190f5fc35af1fc1e282704293a2718af388a54727fbff8c9e78dae7de246.wasm",
"tx_transfer.wasm": "tx_transfer.c63868b8102713771bf4db94514b892308bda0744c691f55d6cbfda5f5698c09.wasm",
"tx_unbond.wasm": "tx_unbond.fc56a17b2b433d8a702d04e2a0577319fe544bf866c59845d28370ec5931c15e.wasm",
"tx_update_vp.wasm": "tx_update_vp.83787cfec2b8f3c732900b5bcd3a1a8a6629915db064d7450c0da801039a86e5.wasm",
"tx_vote_proposal.wasm": "tx_vote_proposal.b108fbfd06affdd75efe01c5952025f6ac3c50bc7dcccf9c1a7102e7241d4d05.wasm",
"tx_withdraw.wasm": "tx_withdraw.78701ea2441ef27ba7bf865ada8b7e66739d506def8d939326a032cc0fbc54ec.wasm",
"vp_implicit.wasm": "vp_implicit.b6d4346da8be8d75799192152a5d14a00150c83c7514d49de508029c9421be62.wasm",
"vp_masp.wasm": "vp_masp.3c515db40812e367f30eda11e0503e9045fc213f4e42d4659516762f300daee9.wasm",
"vp_testnet_faucet.wasm": "vp_testnet_faucet.3af30baff7486f2ad575e89bcc1386e9cce010be31fcd00614b4f2430f04f41e.wasm",
"vp_token.wasm": "vp_token.2c9d62ac70fd5962734d41840c532eca2bb5d9167ad96e57233d5ab59c1f32e9.wasm",
"vp_user.wasm": "vp_user.7422ae023f420d62915a892450437eda3c6058a8643507d92fa075fb11ce3795.wasm",
"vp_validator.wasm": "vp_validator.08ad0926ccf8256917757b55752b15aee7aca0103eea39151ba346ceaffe720e.wasm"
}
Binary file modified wasm_for_tests/tx_memory_limit.wasm
Binary file not shown.
Binary file modified wasm_for_tests/tx_mint_tokens.wasm
Binary file not shown.
Binary file modified wasm_for_tests/tx_no_op.wasm
Binary file not shown.
Binary file modified wasm_for_tests/tx_proposal_code.wasm
Binary file not shown.
Binary file modified wasm_for_tests/tx_read_storage_key.wasm
Binary file not shown.
Binary file modified wasm_for_tests/tx_write_storage_key.wasm
Binary file not shown.
Binary file modified wasm_for_tests/vp_always_false.wasm
Binary file not shown.
Binary file modified wasm_for_tests/vp_always_true.wasm
Binary file not shown.
Binary file modified wasm_for_tests/vp_eval.wasm
Binary file not shown.
Binary file modified wasm_for_tests/vp_memory_limit.wasm
Binary file not shown.
Binary file modified wasm_for_tests/vp_read_storage_key.wasm
Binary file not shown.
6 changes: 3 additions & 3 deletions wasm_for_tests/wasm_source/Cargo.lock

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

0 comments on commit 4b65a73

Please sign in to comment.