From fc7936fc960471654f9015e8d6f49799e8588289 Mon Sep 17 00:00:00 2001 From: Eugen Rata Date: Wed, 1 Jun 2022 08:44:24 -0500 Subject: [PATCH] =?UTF-8?q?added=20proper=20testing=20for=20sorted=20outpu?= =?UTF-8?q?ts=20for=20BlockVersion=20version=203=20an=E2=80=A6=20(#2062)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * added proper testing for sorted outputs for BlockVersion version 3 and higher * linting fix * linting fix #2 * linting fix #3 * linting fix #4 * linting fix #5 * removed mod crate Co-authored-by: Eugene Rata --- transaction/core/test-utils/src/lib.rs | 59 ++++++++++++++++++++++++-- transaction/core/tests/util/mod.rs | 35 ++++++++++++++- transaction/core/tests/validation.rs | 30 +++++++++---- 3 files changed, 111 insertions(+), 13 deletions(-) diff --git a/transaction/core/test-utils/src/lib.rs b/transaction/core/test-utils/src/lib.rs index eb2d1653b0..30b41e7f83 100644 --- a/transaction/core/test-utils/src/lib.rs +++ b/transaction/core/test-utils/src/lib.rs @@ -146,6 +146,44 @@ pub fn create_transaction_with_amount_and_comparer< fee: u64, tombstone_block: BlockIndex, rng: &mut R, +) -> Tx { + create_transaction_with_amount_and_comparer_and_recipients::( + block_version, + ledger, + tx_out, + sender, + &[recipient], + value, + fee, + tombstone_block, + rng, + ) +} + +/// Creates a transaction that sends an arbitrary amount to a single recipient. +/// +/// # Arguments: +/// * `ledger` - A ledger containing `tx_out`. +/// * `tx_out` - The TxOut that will be spent. +/// * `sender` - The owner of `tx_out`. +/// * `recipient` - The recipient of the new transaction. +/// * `amount` - Amount to send. +/// * `tombstone_block` - The tombstone block for the new transaction. +/// * `rng` - The randomness used by this function +pub fn create_transaction_with_amount_and_comparer_and_recipients< + L: Ledger, + R: RngCore + CryptoRng, + O: TxOutputsOrdering, +>( + block_version: BlockVersion, + ledger: &mut L, + tx_out: &TxOut, + sender: &AccountKey, + recipients: &[&PublicAddress], + value: u64, + fee: u64, + tombstone_block: BlockIndex, + rng: &mut R, ) -> Tx { let (sender_amount, _) = tx_out.view_key_match(sender.view_private_key()).unwrap(); @@ -195,14 +233,27 @@ pub fn create_transaction_with_amount_and_comparer< transaction_builder.add_input(input_credentials); let amount = Amount { - value, + value: value / recipients.len() as u64, token_id: sender_amount.token_id, }; + let rest = value % recipients.len() as u64; + // Output - transaction_builder - .add_output(amount, recipient, rng) - .unwrap(); + for (idx, recipient) in recipients.iter().enumerate() { + if idx == 0 && rest != 0 { + let mut dup_amount = amount; + dup_amount.value += rest; + transaction_builder + .add_output(dup_amount, recipient, rng) + .unwrap(); + continue; + } + + transaction_builder + .add_output(amount, recipient, rng) + .unwrap(); + } // Tombstone block transaction_builder.set_tombstone_block(tombstone_block); diff --git a/transaction/core/tests/util/mod.rs b/transaction/core/tests/util/mod.rs index 5216b847a8..a645ef73d4 100644 --- a/transaction/core/tests/util/mod.rs +++ b/transaction/core/tests/util/mod.rs @@ -1,10 +1,11 @@ // Copyright (c) 2018-2022 The MobileCoin Foundation +use mc_account_keys::PublicAddress; use mc_ledger_db::{Ledger, LedgerDB}; use mc_transaction_core::{tx::Tx, BlockVersion}; use mc_transaction_core_test_utils::{ create_ledger, create_transaction, create_transaction_with_amount_and_comparer, - initialize_ledger, AccountKey, + create_transaction_with_amount_and_comparer_and_recipients, initialize_ledger, AccountKey, }; use mc_transaction_std::{DefaultTxOutputsOrdering, TxOutputsOrdering}; use mc_util_test_helper::{RngType, SeedableRng}; @@ -74,3 +75,35 @@ pub fn create_test_tx_with_amount_and_comparer( (tx, ledger) } + +#[allow(unused)] +pub fn create_test_tx_with_amount_and_comparer_and_recipients( + block_version: BlockVersion, + amount: u64, + fee: u64, + recipients: &[&PublicAddress], +) -> (Tx, LedgerDB) { + let mut rng: RngType = SeedableRng::from_seed([1u8; 32]); + let sender = AccountKey::random(&mut rng); + let mut ledger = create_ledger(); + let n_blocks = 1; + initialize_ledger(block_version, &mut ledger, n_blocks, &sender, &mut rng); + + // Spend an output from the last block. + let block_contents = ledger.get_block_contents(n_blocks - 1).unwrap(); + let tx_out = block_contents.outputs[0].clone(); + + let tx = create_transaction_with_amount_and_comparer_and_recipients::<_, _, O>( + block_version, + &mut ledger, + &tx_out, + &sender, + recipients, + amount, + fee, + n_blocks + 1, + &mut rng, + ); + + (tx, ledger) +} diff --git a/transaction/core/tests/validation.rs b/transaction/core/tests/validation.rs index 484c3fab41..a879b92097 100644 --- a/transaction/core/tests/validation.rs +++ b/transaction/core/tests/validation.rs @@ -7,7 +7,12 @@ extern crate alloc; mod util; +use crate::util::{ + create_test_tx, create_test_tx_with_amount, + create_test_tx_with_amount_and_comparer_and_recipients, +}; use alloc::vec::Vec; +use mc_account_keys::AccountKey; use mc_crypto_keys::{CompressedRistrettoPublic, ReprBytes}; use mc_ledger_db::Ledger; use mc_transaction_core::{ @@ -20,7 +25,6 @@ use mc_transaction_core::{ }; use mc_transaction_core_test_utils::{InverseTxOutputsOrdering, INITIALIZE_LEDGER_AMOUNT}; use mc_util_test_helper::get_seeded_rng; -use util::*; #[test] // Should return MissingMemo when memos are missing in an output @@ -747,21 +751,31 @@ fn test_validate_tombstone_tombstone_block_too_far() { } } -// FIXME: This test needs to involve a Tx with more than one output to make // sense #[test] -#[ignore] fn test_global_validate_for_blocks_with_sorted_outputs() { let mut rng = get_seeded_rng(); let fee = Mob::MINIMUM_FEE + 1; + + let recipients = vec![ + AccountKey::random(&mut rng).default_subaddress(), + AccountKey::random(&mut rng).default_subaddress(), + AccountKey::random(&mut rng).default_subaddress(), + AccountKey::random(&mut rng).default_subaddress(), + AccountKey::random(&mut rng).default_subaddress(), + ]; + let recipients_refs = recipients.iter().collect::>(); + for block_version in BlockVersion::iterator() { // for block version < 3 it doesn't matter // for >= 3 it shall return an error about unsorted outputs - let (tx, ledger) = create_test_tx_with_amount_and_comparer::( - block_version, - INITIALIZE_LEDGER_AMOUNT - fee, - fee, - ); + let (tx, ledger) = + create_test_tx_with_amount_and_comparer_and_recipients::( + block_version, + INITIALIZE_LEDGER_AMOUNT - fee, + fee, + &recipients_refs, + ); let highest_indices = tx.get_membership_proof_highest_indices(); let root_proofs: Vec = ledger