diff --git a/.changelog/unreleased/testing/813-fix-pos-tx-test-input-lower-bound.md b/.changelog/unreleased/testing/813-fix-pos-tx-test-input-lower-bound.md new file mode 100644 index 0000000000..d33ceccc68 --- /dev/null +++ b/.changelog/unreleased/testing/813-fix-pos-tx-test-input-lower-bound.md @@ -0,0 +1,2 @@ +- Allow size zero bonds in PoS for testing. + ([#813](https://github.com/anoma/namada/pull/813)) \ No newline at end of file diff --git a/core/src/types/token.rs b/core/src/types/token.rs index 10c690bb06..2bf95735ed 100644 --- a/core/src/types/token.rs +++ b/core/src/types/token.rs @@ -502,4 +502,12 @@ pub mod testing { pub fn arb_amount_ceiled(max: u64) -> impl Strategy { (0..=max).prop_map(Amount::from) } + + /// Generate an arbitrary non-zero token amount up to and including given + /// `max` value + pub fn arb_amount_non_zero_ceiled( + max: u64, + ) -> impl Strategy { + (1..=max).prop_map(Amount::from) + } } diff --git a/proof_of_stake/src/lib.rs b/proof_of_stake/src/lib.rs index 68734aa30f..64c7ffdff8 100644 --- a/proof_of_stake/src/lib.rs +++ b/proof_of_stake/src/lib.rs @@ -968,8 +968,6 @@ pub enum BondError { InactiveValidator(Address), #[error("Voting power overflow: {0}")] VotingPowerOverflow(TryFromIntError), - #[error("Given zero amount to bond")] - ZeroAmount, } #[allow(missing_docs)] @@ -987,8 +985,6 @@ pub enum UnbondError { ValidatorHasNoVotingPower(Address), #[error("Voting power overflow: {0}")] VotingPowerOverflow(TryFromIntError), - #[error("Given zero amount to unbond")] - ZeroAmount, } #[allow(missing_docs)] @@ -1291,9 +1287,6 @@ fn bond_tokens( validator_set: &mut ValidatorSets, current_epoch: Epoch, ) -> Result { - if amount == token::Amount::default() { - return Err(BondError::ZeroAmount); - } // Check the validator state match validator_state { None => { @@ -1400,9 +1393,6 @@ fn unbond_tokens( validator_set: &mut ValidatorSets, current_epoch: Epoch, ) -> Result { - if amount == token::Amount::default() { - return Err(UnbondError::ZeroAmount); - } // We can unbond tokens that are bonded for a future epoch (not yet // active), hence we check the total at the pipeline offset let unbondable_amount = bond diff --git a/wasm/wasm_source/proptest-regressions/tx_unbond.txt b/wasm/wasm_source/proptest-regressions/tx_unbond.txt new file mode 100644 index 0000000000..8c589d1abd --- /dev/null +++ b/wasm/wasm_source/proptest-regressions/tx_unbond.txt @@ -0,0 +1 @@ +cc f22e874350910b197cb02a4a07ec5bef18e16c0d1a39eaabaee43d1fc05ce11d diff --git a/wasm/wasm_source/src/tx_bond.rs b/wasm/wasm_source/src/tx_bond.rs index 5e5eeb474a..219a612630 100644 --- a/wasm/wasm_source/src/tx_bond.rs +++ b/wasm/wasm_source/src/tx_bond.rs @@ -291,7 +291,7 @@ mod tests { ( arb_established_address(), prop::option::of(arb_non_internal_address()), - token::testing::arb_amount_ceiled(max_amount), + token::testing::arb_amount_non_zero_ceiled(max_amount), ) .prop_map(|(validator, source, amount)| { transaction::pos::Bond { diff --git a/wasm/wasm_source/src/tx_unbond.rs b/wasm/wasm_source/src/tx_unbond.rs index d7a6431243..70033286bf 100644 --- a/wasm/wasm_source/src/tx_unbond.rs +++ b/wasm/wasm_source/src/tx_unbond.rs @@ -258,21 +258,20 @@ mod tests { epoch {epoch}" ); } - // Check that the unbond is as expected - let start_epoch = match &unbond.source { - Some(_) => { - // This bond was a delegation - Epoch::from(pos_params.pipeline_len) - } - None => { - // This bond was a genesis validator self-bond - Epoch::default() - } + let start_epoch = if is_delegation { + // This bond was a delegation + Epoch::from(pos_params.pipeline_len) + } else { + // This bond was a genesis validator self-bond + Epoch::default() }; let end_epoch = Epoch::from(pos_params.unbonding_len - 1); - let expected_unbond = - HashMap::from_iter([((start_epoch, end_epoch), unbond.amount)]); + let expected_unbond = if unbond.amount == token::Amount::default() { + HashMap::new() + } else { + HashMap::from_iter([((start_epoch, end_epoch), unbond.amount)]) + }; let actual_unbond: Unbond = unbonds_post.get(pos_params.unbonding_len).unwrap(); assert_eq!( @@ -342,7 +341,7 @@ mod tests { ( address::testing::arb_established_address(), prop::option::of(address::testing::arb_non_internal_address()), - token::testing::arb_amount_ceiled(max_amount), + token::testing::arb_amount_non_zero_ceiled(max_amount), ) .prop_map(|(validator, source, amount)| { let validator = Address::Established(validator); diff --git a/wasm/wasm_source/src/tx_withdraw.rs b/wasm/wasm_source/src/tx_withdraw.rs index 8819063a0c..e29415f800 100644 --- a/wasm/wasm_source/src/tx_withdraw.rs +++ b/wasm/wasm_source/src/tx_withdraw.rs @@ -201,16 +201,17 @@ mod tests { fn arb_initial_stake_and_unbonded_amount() -> impl Strategy { // Generate initial stake - token::testing::arb_amount_ceiled((i64::MAX / 8) as u64).prop_flat_map( - |initial_stake| { + token::testing::arb_amount_non_zero_ceiled((i64::MAX / 8) as u64) + .prop_flat_map(|initial_stake| { // Use the initial stake to limit the unbonded amount from the // stake let unbonded_amount = - token::testing::arb_amount_ceiled(initial_stake.into()); + token::testing::arb_amount_non_zero_ceiled( + initial_stake.into(), + ); // Use the generated initial stake too too (Just(initial_stake), unbonded_amount) - }, - ) + }) } fn arb_withdraw() -> impl Strategy {