From 9b8a9de2ae2a937a22bc11843b8db074d8c67253 Mon Sep 17 00:00:00 2001 From: Murisi Tarusenga Date: Mon, 22 Jan 2024 08:34:25 +0200 Subject: [PATCH] Constrained the range of MASP test vectors generated for correctness. --- sdk/src/lib.rs | 55 ++++++++++++++++++++++---- sdk/src/masp.rs | 96 +++++++++++++++++++++++++++++++++++----------- sdk/src/signing.rs | 10 +++-- 3 files changed, 128 insertions(+), 33 deletions(-) diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index 497f7dd674..035c2ff3e2 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -795,6 +795,7 @@ pub mod testing { use sha2::Digest; use super::*; + use crate::core::types::address::MASP; use crate::core::types::chain::ChainId; use crate::core::types::eth_bridge_pool::testing::arb_pending_transfer; use crate::core::types::key::testing::arb_common_pk; @@ -814,7 +815,9 @@ pub mod testing { use crate::core::types::transaction::{ DecryptedTx, Fee, TxType, WrapperTx, }; - use crate::masp::testing::arb_masp_transfer; + use crate::masp::testing::{ + arb_deshielding_transfer, arb_shielded_transfer, arb_shielding_transfer, + }; use crate::proto::{Code, Commitment, Header, MaspBuilder, Section}; #[derive(Debug)] @@ -992,26 +995,62 @@ pub mod testing { TransparentAddress(hash.into()) } + // Maximum number of notes to include in a transaction + const MAX_ASSETS: usize = 10; + + // Type of MASP transaction + #[derive(Debug, Clone)] + enum MaspTxType { + // Shielded transaction + Shielded, + // Shielding transaction + Shielding, + // Deshielding transaction + Deshielding, + } + prop_compose! { // Generate an arbitrary transfer transaction pub fn arb_masp_transfer_tx()(transfer in arb_transfer())( mut header in arb_header(), wrapper in arb_wrapper_tx(), code_hash in arb_hash(), - (shielded_transfer, asset_types) in arb_masp_transfer( - encode_address(&transfer.source), - encode_address(&transfer.target), - ), + (masp_tx_type, (shielded_transfer, asset_types)) in prop_oneof![ + (Just(MaspTxType::Shielded), arb_shielded_transfer(0..MAX_ASSETS)), + (Just(MaspTxType::Shielding), arb_shielding_transfer(encode_address(&transfer.source), 1)), + (Just(MaspTxType::Deshielding), arb_deshielding_transfer(encode_address(&transfer.target), 1)), + ], mut transfer in Just(transfer), ) -> (Tx, TxData) { header.tx_type = TxType::Wrapper(Box::new(wrapper)); let mut tx = Tx { header, sections: vec![] }; - tx.add_data(transfer.clone()); - tx.add_code_from_hash(code_hash, Some(TX_TRANSFER_WASM.to_owned())); + match masp_tx_type { + MaspTxType::Shielded => { + transfer.source = MASP; + transfer.target = MASP; + transfer.amount = token::Amount::zero().into(); + }, + MaspTxType::Shielding => { + transfer.target = MASP; + // Set the transparent amount and token + let ((addr, denom, _epoch), value) = asset_types.iter().next().unwrap(); + transfer.amount = DenominatedAmount::native(token::Amount::from_masp_denominated(*value, *denom)); + transfer.token = addr.clone(); + }, + MaspTxType::Deshielding => { + transfer.source = MASP; + // Set the transparent amount and token + let ((addr, denom, _epoch), value) = asset_types.iter().next().unwrap(); + transfer.amount = DenominatedAmount::native(token::Amount::from_masp_denominated(*value, *denom)); + transfer.token = addr.clone(); + }, + } let masp_tx_hash = tx.add_masp_tx_section(shielded_transfer.masp_tx).1; transfer.shielded = Some(masp_tx_hash); + tx.add_data(transfer.clone()); + tx.add_code_from_hash(code_hash, Some(TX_TRANSFER_WASM.to_owned())); tx.add_masp_builder(MaspBuilder { - asset_types, + asset_types: asset_types.into_keys().collect(), // Store how the Info objects map to Descriptors/Outputs metadata: shielded_transfer.metadata, // Store the data that was used to construct the Transaction diff --git a/sdk/src/masp.rs b/sdk/src/masp.rs index 68e9d72913..24a2eb4ad3 100644 --- a/sdk/src/masp.rs +++ b/sdk/src/masp.rs @@ -2231,6 +2231,7 @@ pub mod testing { Diversifier, Node, PaymentAddress, ProofGenerationKey, Rseed, }; use masp_primitives::transaction::components::{I128Sum, GROTH_PROOF_SIZE}; + use proptest::collection::SizeRange; use proptest::prelude::*; use proptest::test_runner::TestRng; use proptest::{collection, option, prop_compose}; @@ -2606,8 +2607,6 @@ pub mod testing { const MAX_MONEY: u64 = 100; // Maximum number of partitions for a note const MAX_SPLITS: usize = 10; - // Maximum number of notes to include in a transaction - const MAX_ASSETS: usize = 10; prop_compose! { // Arbitrarily partition the given vector of integers into sets and sum @@ -2695,11 +2694,11 @@ pub mod testing { prop_compose! { // Generate an arbitrary shielded MASP transaction builder - pub fn arb_shielded_builder()( + pub fn arb_shielded_builder(asset_range: impl Into)( assets in collection::hash_map( (arb_address(), arb_masp_denom(), option::of(arb_epoch())), collection::vec(..MAX_MONEY, ..MAX_SPLITS), - ..MAX_ASSETS, + asset_range, ), )( expiration_height in arb_height(BranchId::MASP, &TestNetwork), @@ -2715,7 +2714,7 @@ pub mod testing { assets in Just(assets), ) -> ( Builder::>, - HashSet<(Address, MaspDenom, Option)>, + HashMap<(Address, MaspDenom, Option), u64>, ) { let mut builder = Builder::::new_with_rng( NETWORK, @@ -2738,17 +2737,20 @@ pub mod testing { for (ovk, payment_addr, asset_type, value, memo) in output_descriptions.into_iter().flatten() { builder.add_sapling_output(ovk, payment_addr, asset_type, value, memo).unwrap(); } - (builder, assets.into_keys().collect()) + (builder, assets.into_iter().map(|(k, v)| (k, v.iter().sum())).collect()) } } prop_compose! { // Generate an arbitrary shielding MASP transaction builder - pub fn arb_shielding_builder(source: TransparentAddress)( + pub fn arb_shielding_builder( + source: TransparentAddress, + asset_range: impl Into, + )( assets in collection::hash_map( (arb_address(), arb_masp_denom(), option::of(arb_epoch())), collection::vec(..MAX_MONEY, ..MAX_SPLITS), - ..MAX_ASSETS, + asset_range, ), )( expiration_height in arb_height(BranchId::MASP, &TestNetwork), @@ -2764,7 +2766,7 @@ pub mod testing { assets in Just(assets), ) -> ( Builder::>, - HashSet<(Address, MaspDenom, Option)>, + HashMap<(Address, MaspDenom, Option), u64>, ) { let mut builder = Builder::::new_with_rng( NETWORK, @@ -2780,17 +2782,20 @@ pub mod testing { for (ovk, payment_addr, asset_type, value, memo) in output_descriptions.into_iter().flatten() { builder.add_sapling_output(ovk, payment_addr, asset_type, value, memo).unwrap(); } - (builder, assets.into_keys().collect()) + (builder, assets.into_iter().map(|(k, v)| (k, v.iter().sum())).collect()) } } prop_compose! { // Generate an arbitrary deshielding MASP transaction builder - pub fn arb_deshielding_builder(target: TransparentAddress)( + pub fn arb_deshielding_builder( + target: TransparentAddress, + asset_range: impl Into, + )( assets in collection::hash_map( (arb_address(), arb_masp_denom(), option::of(arb_epoch())), collection::vec(..MAX_MONEY, ..MAX_SPLITS), - ..MAX_ASSETS, + asset_range, ), )( expiration_height in arb_height(BranchId::MASP, &TestNetwork), @@ -2806,7 +2811,7 @@ pub mod testing { assets in Just(assets), ) -> ( Builder::>, - HashSet<(Address, MaspDenom, Option)>, + HashMap<(Address, MaspDenom, Option), u64>, ) { let mut builder = Builder::::new_with_rng( NETWORK, @@ -2829,24 +2834,71 @@ pub mod testing { for txout in txouts.into_iter().flatten() { builder.add_transparent_output(&txout.address, txout.asset_type, txout.value).unwrap(); } - (builder, assets.into_keys().collect()) + (builder, assets.into_iter().map(|(k, v)| (k, v.iter().sum())).collect()) + } + } + + prop_compose! { + // Generate an arbitrary MASP shielded transfer + pub fn arb_shielded_transfer( + asset_range: impl Into, + )(asset_range in Just(asset_range.into()))( + (builder, asset_types) in arb_shielded_builder(asset_range), + epoch in arb_epoch(), + rng in arb_rng().prop_map(TestCsprng), + ) -> (ShieldedTransfer, HashMap<(Address, MaspDenom, Option), u64>) { + let (masp_tx, metadata) = builder.clone().build( + &MockTxProver(Mutex::new(rng)), + &FeeRule::non_standard(U64Sum::zero()), + ).unwrap(); + (ShieldedTransfer { + builder: builder.map_builder(WalletMap), + metadata, + masp_tx, + epoch, + }, asset_types) } } prop_compose! { // Generate an arbitrary MASP shielded transfer - pub fn arb_masp_transfer( + pub fn arb_shielding_transfer( source: TransparentAddress, + asset_range: impl Into, + )(asset_range in Just(asset_range.into()))( + (builder, asset_types) in arb_shielding_builder( + source, + asset_range, + ), + epoch in arb_epoch(), + rng in arb_rng().prop_map(TestCsprng), + ) -> (ShieldedTransfer, HashMap<(Address, MaspDenom, Option), u64>) { + let (masp_tx, metadata) = builder.clone().build( + &MockTxProver(Mutex::new(rng)), + &FeeRule::non_standard(U64Sum::zero()), + ).unwrap(); + (ShieldedTransfer { + builder: builder.map_builder(WalletMap), + metadata, + masp_tx, + epoch, + }, asset_types) + } + } + + prop_compose! { + // Generate an arbitrary MASP shielded transfer + pub fn arb_deshielding_transfer( target: TransparentAddress, - )( - (builder, asset_types) in prop_oneof![ - arb_shielded_builder(), - arb_shielding_builder(source), - arb_deshielding_builder(target), - ], + asset_range: impl Into, + )(asset_range in Just(asset_range.into()))( + (builder, asset_types) in arb_deshielding_builder( + target, + asset_range, + ), epoch in arb_epoch(), rng in arb_rng().prop_map(TestCsprng), - ) -> (ShieldedTransfer, HashSet<(Address, MaspDenom, Option)>) { + ) -> (ShieldedTransfer, HashMap<(Address, MaspDenom, Option), u64>) { let (masp_tx, metadata) = builder.clone().build( &MockTxProver(Mutex::new(rng)), &FeeRule::non_standard(U64Sum::zero()), diff --git a/sdk/src/signing.rs b/sdk/src/signing.rs index ef17ee7c29..db7b780549 100644 --- a/sdk/src/signing.rs +++ b/sdk/src/signing.rs @@ -729,19 +729,23 @@ async fn make_ledger_amount_asset( assets: &HashMap)>, prefix: &str, ) { - if let Some((token, _, _epoch)) = assets.get(token) { + if let Some((token, denom, _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!( "{}Amount : {} {}", prefix, token.to_uppercase(), - amount, + token::Amount::from_masp_denominated(amount, *denom), )); } else { output.extend(vec![ format!("{}Token : {}", prefix, token), - format!("{}Amount : {}", prefix, amount,), + format!( + "{}Amount : {}", + prefix, + token::Amount::from_masp_denominated(amount, *denom) + ), ]); } } else {