Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions chain-impl-mockchain/src/testing/arbitrary/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pub mod config_builder;
pub mod kind_type;
pub mod ledger_builder;
pub mod output;
pub mod random;
pub mod transaction;
pub mod update_proposal;
pub mod utils;
Expand All @@ -17,6 +18,7 @@ use quickcheck::{Arbitrary, Gen};
pub use address::*;
pub use kind_type::*;
pub use output::*;
pub use random::*;
use std::cmp;
pub use transaction::*;
pub use update_proposal::*;
Expand Down
10 changes: 10 additions & 0 deletions chain-impl-mockchain/src/testing/arbitrary/random.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use quickcheck::{Arbitrary, Gen};

#[derive(Clone, Debug)]
pub struct Random1to10(pub u64);

impl Arbitrary for Random1to10 {
fn arbitrary<G: Gen>(g: &mut G) -> Self {
Self(u64::arbitrary(g) % 10 + 1)
}
}
109 changes: 108 additions & 1 deletion chain-impl-mockchain/src/testing/e2e/fees.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
use crate::testing::VoteTestGen;
use crate::tokens::name::{TokenName, TOKEN_NAME_MAX_SIZE};
use crate::{
fee::{LinearFee, PerCertificateFee},
header::BlockDate,
testing::{
builders::StakePoolBuilder,
ledger::ConfigBuilder,
scenario::{prepare_scenario, wallet},
scenario::{prepare_scenario, proposal, vote_plan, wallet},
verifiers::LedgerStateVerifier,
},
value::Value,
vote::Choice,
};
use chain_addr::Discrimination;
use quickcheck_macros::quickcheck;
Expand All @@ -16,6 +20,10 @@ use std::num::NonZeroU64;
const ALICE: &str = "Alice";
const BOB: &str = "Bob";
const STAKE_POOL: &str = "stake_pool";
const VOTE_PLAN: &str = "fund1";
const BASIC_REWARD: u64 = 500;
const BASIC_VOTING_TOKEN_VALUE: u64 = 1000;
const BASIC_BALANCE: u64 = 1500;

#[test]
pub fn per_certificate_fees() {
Expand Down Expand Up @@ -239,3 +247,102 @@ fn verify_total_funds_after_transaction_with_fee(fee: u64) {
.pots()
.has_fee_equals_to(&Value(fee));
}

#[quickcheck]
pub fn vote_cast_fees(linear_fee: LinearFee) {
let expected_fees = linear_fee.constant + linear_fee.coefficient + linear_fee.certificate;
let favorable = Choice::new(1);
let voting_token = TokenName::try_from(vec![0u8; TOKEN_NAME_MAX_SIZE]).unwrap();
Copy link
Contributor

Choose a reason for hiding this comment

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

i think we got TestGen::token_name() static method for this purpose

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not working for this purpose as TestGen::token_name() returns an incompatible type of token.
As discussed I created a ticket to track this desiderata: https://input-output.atlassian.net/browse/NPG-1217


let (mut ledger, controller) = prepare_scenario()
.with_config(
ConfigBuilder::new()
.with_fee(linear_fee)
.with_rewards(Value(BASIC_REWARD)),
)
.with_initials(vec![wallet(ALICE)
.with(BASIC_BALANCE)
.with_token(voting_token, BASIC_VOTING_TOKEN_VALUE)
.owns(STAKE_POOL)
.committee_member()])
.with_vote_plans(vec![vote_plan(VOTE_PLAN)
.owner(ALICE)
.consecutive_epoch_dates()
.with_proposal(
proposal(VoteTestGen::external_proposal_id())
.options(3)
.action_off_chain(),
)])
.build()
.unwrap();

let mut alice = controller.wallet(ALICE).unwrap();

let vote_plan = controller.vote_plan(VOTE_PLAN).unwrap();

let proposal = vote_plan.proposal(0);

controller
.cast_vote_public(&alice, &vote_plan, &proposal.id(), favorable, &mut ledger)
.unwrap();

alice.confirm_transaction();

LedgerStateVerifier::new(ledger.clone().into())
.info("fee pot is filled with expected fees amount")
.pots()
.has_fee_equals_to(&Value(expected_fees));

LedgerStateVerifier::new(ledger.into())
.info("account balance is correct")
.address_has_expected_balance(
alice.as_account_data(),
Value(BASIC_BALANCE - expected_fees),
);
}

#[quickcheck]
pub fn vote_tally_fees(linear_fee: LinearFee) {
let expected_fees = linear_fee.constant + linear_fee.coefficient + linear_fee.certificate;

let (mut ledger, controller) = prepare_scenario()
.with_config(
ConfigBuilder::new()
.with_fee(linear_fee)
.with_rewards(Value(BASIC_REWARD)),
)
.with_initials(vec![wallet(ALICE)
.with(BASIC_BALANCE)
.owns(STAKE_POOL)
.committee_member()])
.with_vote_plans(vec![vote_plan(VOTE_PLAN)
.owner(ALICE)
.consecutive_epoch_dates()])
.build()
.unwrap();

let mut alice = controller.wallet(ALICE).unwrap();
let vote_plan = controller.vote_plan(VOTE_PLAN).unwrap();

ledger.fast_forward_to(BlockDate {
epoch: 1,
slot_id: 1,
});

controller
.tally_vote_public(&alice, &vote_plan, &mut ledger)
.unwrap();
alice.confirm_transaction();

LedgerStateVerifier::new(ledger.clone().into())
.info("fee pot is filled with expected fees amount")
.pots()
.has_fee_equals_to(&Value(expected_fees));

LedgerStateVerifier::new(ledger.into())
.info("account balance is correct")
.address_has_expected_balance(
alice.as_account_data(),
Value(BASIC_BALANCE - expected_fees),
);
}
1 change: 1 addition & 0 deletions chain-impl-mockchain/src/testing/e2e/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub mod pool_update;
pub mod rewards;
pub mod spending_counter_lanes;
pub mod stake_distribution;
pub mod transactions;
pub mod update_proposal;
pub mod vote_private;
pub mod vote_public;
95 changes: 95 additions & 0 deletions chain-impl-mockchain/src/testing/e2e/transactions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
use crate::{
fee::{FeeAlgorithm, LinearFee},
testing::{
arbitrary::Random1to10,
ledger::ConfigBuilder,
scenario::{prepare_scenario, wallet},
verifiers::LedgerStateVerifier,
},
value::Value,
};

use quickcheck_macros::quickcheck;

const BASIC_BALANCE: u64 = 1000;

#[quickcheck]
pub fn validate_ledger_state_after_transaction(amount: Random1to10, linear_fee: LinearFee) {
let total_fees = linear_fee.calculate(None, 1, 1);
let valid_transaction_amount = total_fees.0 + amount.0;
let alice_initial_balance = BASIC_BALANCE + valid_transaction_amount + total_fees.0;
let bob_initial_balance = BASIC_BALANCE;

let (mut ledger, controller) = prepare_scenario()
.with_config(ConfigBuilder::new().with_fee(linear_fee))
.with_initials(vec![
wallet("Alice").with(alice_initial_balance),
wallet("Bob").with(bob_initial_balance),
])
.build()
.unwrap();

let mut alice = controller.wallet("Alice").unwrap();
let bob = controller.wallet("Bob").unwrap();

controller
.transfer_funds(
&alice,
&bob,
&mut ledger,
valid_transaction_amount + total_fees.0,
)
.unwrap();
alice.confirm_transaction();

LedgerStateVerifier::new(ledger.into()).address_has_expected_balance(
bob.as_account_data(),
Value(bob_initial_balance + valid_transaction_amount),
);
}

#[quickcheck]
pub fn validate_ledger_state_after_invalid_transaction(amount: Random1to10, linear_fee: LinearFee) {
let total_fees = linear_fee.calculate(None, 1, 1);
let valid_transaction_amount = total_fees.0 + amount.0;
let alice_initial_balance = amount.0 + valid_transaction_amount + total_fees.0;
let bob_initial_balance = BASIC_BALANCE;

let (mut ledger, controller) = prepare_scenario()
.with_config(ConfigBuilder::new().with_fee(linear_fee))
.with_initials(vec![
wallet("Alice").with(alice_initial_balance),
wallet("Bob").with(bob_initial_balance),
])
.build()
.unwrap();

let mut alice = controller.wallet("Alice").unwrap();
let bob = controller.wallet("Bob").unwrap();

controller
.transfer_funds(
&alice,
&bob,
&mut ledger,
valid_transaction_amount + total_fees.0,
)
.unwrap();

alice.confirm_transaction();

// this second transaction should fail as alice does not have the balance to cover for it
let _ = controller.transfer_funds(
&alice,
&bob,
&mut ledger,
valid_transaction_amount + total_fees.0,
);

alice.confirm_transaction();

LedgerStateVerifier::new(ledger.into()).address_has_expected_balance(
alice.as_account_data(),
Value(alice_initial_balance - (valid_transaction_amount + total_fees.0)),
);
}