-
* fix process_refund_queue weight * add weight limit tests * benchmark process_refund_queue overhead * add pallet-quota benchmarks
* fix process_refund_queue weight * add weight limit tests * benchmark process_refund_queue overhead * add pallet-quota benchmarks
tests.rs 12.92 KiB
// Copyright 2021 Axiom-Team
//
// This file is part of Duniter-v2S.
//
// Duniter-v2S is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, version 3 of the License.
//
// Duniter-v2S is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>.
use crate::mock::*;
use crate::Weight;
use frame_support::traits::Currency;
use sp_core::Get;
// Note: values for reload rate and max quota defined in mock file
// parameter_types! {
// pub const ReloadRate: u64 = 10;
// pub const MaxQuota: u64 = 1000;
// }
// pub const ExistentialDeposit: Balance = 1000;
/// test that quota are well initialized for genesis identities
#[test]
fn test_initial_quota() {
new_test_ext(QuotaConfig {
identities: vec![1, 2, 3],
})
.execute_with(|| {
run_to_block(1);
// quota initialized to 0,0 for a given identity
assert_eq!(
Quota::quota(1),
Some(pallet_quota::Quota {
last_use: 0,
amount: 0
})
);
// no initialized quota for standard account
assert_eq!(Quota::quota(4), None);
})
}
/// test that quota are updated according to the reload rate and max quota values
#[test]
fn test_update_quota() {
new_test_ext(QuotaConfig {
identities: vec![1, 2, 3],
})
.execute_with(|| {
// Block 1
run_to_block(1);
assert_eq!(
Quota::quota(1),
Some(pallet_quota::Quota {
last_use: 0,
amount: 0
})
);
// (spending 0 quota will lead to only update)
// assert zero quota spent
assert_eq!(Quota::spend_quota(1, 0), 0);
assert_eq!(
Quota::quota(1),
Some(pallet_quota::Quota {
last_use: 1, // used at block 1
// max quota × (current block - last use) / reload rate
amount: 100 // 1000 × 1 / 10 = 100
})
);
// Block 2
run_to_block(2);
assert_eq!(Quota::spend_quota(2, 0), 0);
assert_eq!(
Quota::quota(2),
Some(pallet_quota::Quota {
last_use: 2, // used at block 2
// max quota × (current block - last use) / reload rate
amount: 200 // 1000 × 2 / 10 = 200
})
);
// Block 20
run_to_block(20);
assert_eq!(Quota::spend_quota(2, 0), 0);
assert_eq!(
Quota::quota(2),
Some(pallet_quota::Quota {
last_use: 20, // used at block 20
// maximum quota is reached
// 1000 × (20 - 2) / 10 = 1800
amount: 1000 // min(1000, 1800)
})
);
})
}
/// test that right amount of quota is spent
#[test]
fn test_spend_quota() {
new_test_ext(QuotaConfig {
identities: vec![1, 2, 3],
})
.execute_with(|| {
// at block 5, quota are half loaded (500)
run_to_block(5);
// spending less than available
assert_eq!(Quota::spend_quota(1, 200), 200);
assert_eq!(
Quota::quota(1),
Some(pallet_quota::Quota {
last_use: 5,
amount: 300 // 500 - 200
})
);
// spending all available
assert_eq!(Quota::spend_quota(2, 500), 500);
assert_eq!(
Quota::quota(2),
Some(pallet_quota::Quota {
last_use: 5,
amount: 0 // 500 - 500
})
);
// spending more than available
assert_eq!(Quota::spend_quota(3, 1000), 500);
assert_eq!(
Quota::quota(3),
Some(pallet_quota::Quota {
last_use: 5,
amount: 0 // 500 - 500
})
);
})
}
/// test complete scenario with queue and process refund queue
#[test]
fn test_process_refund_queue() {
new_test_ext(QuotaConfig {
identities: vec![1, 2],
})
.execute_with(|| {
run_to_block(5);
// give enough currency to accounts and treasury and double check
Balances::make_free_balance_be(&account(1), 1000);
Balances::make_free_balance_be(&account(2), 1000);
Balances::make_free_balance_be(&account(3), 1000);
Balances::make_free_balance_be(
&<Test as pallet_quota::Config>::RefundAccount::get(),
10_000,
);
assert_eq!(
Balances::free_balance(<Test as pallet_quota::Config>::RefundAccount::get()),
10_000
);
// fill in the refund queue
Quota::queue_refund(pallet_quota::Refund {
account: account(1),
identity: 1,
amount: 10,
});
Quota::queue_refund(pallet_quota::Refund {
account: account(2),
identity: 2,
amount: 1000,
});
Quota::queue_refund(pallet_quota::Refund {
account: account(3),
identity: 3,
amount: 666,
});
// process it
Quota::process_refund_queue(Weight::from(10));
// after processing, it should be empty
assert!(pallet_quota::RefundQueue::<Test>::get().is_empty());
// and we should observe the effects of refund
assert_eq!(Balances::free_balance(account(1)), 1010); // 1000 initial + 10 refunded
assert_eq!(Balances::free_balance(account(2)), 1500); // 1000 initial + 500 refunded
assert_eq!(Balances::free_balance(account(3)), 1000); // only initial because no available quota
assert_eq!(
Balances::free_balance(<Test as pallet_quota::Config>::RefundAccount::get()),
// initial minus refunds
10_000 - 500 - 10
);
// events
System::assert_has_event(RuntimeEvent::Quota(pallet_quota::Event::Refunded {
who: account(1),
identity: 1,
amount: 10,
}));
System::assert_has_event(RuntimeEvent::Quota(pallet_quota::Event::NoQuotaForIdty(3)));
})
}
/// test not enough currency in treasury
#[test]
fn test_not_enough_treasury() {
new_test_ext(QuotaConfig {
identities: vec![1],
})
.execute_with(|| {
run_to_block(5);
Balances::make_free_balance_be(&account(1), 1000);
Balances::make_free_balance_be(&<Test as pallet_quota::Config>::RefundAccount::get(), 1200);
Quota::queue_refund(pallet_quota::Refund {
account: account(1),
identity: 1,
amount: 500,
});
Quota::process_refund_queue(Weight::from(10));
// refund was not possible, would kill treasury
assert_eq!(Balances::free_balance(account(1)), 1000);
assert_eq!(
Balances::free_balance(<Test as pallet_quota::Config>::RefundAccount::get()),
1200
);
// event
System::assert_has_event(RuntimeEvent::Quota(
pallet_quota::Event::NoMoreCurrencyForRefund,
));
// quotas were spent anyway, there is no refund for quotas when refund account is empty
assert_eq!(
Quota::quota(1),
Some(pallet_quota::Quota {
last_use: 5,
amount: 0
})
);
})
}
/// test complete scenario with queue and process refund queue weight with available quotas
#[test]
fn test_process_refund_queue_weight_with_quotas() {
new_test_ext(QuotaConfig {
identities: vec![1, 2, 3],
})
.execute_with(|| {
run_to_block(15);
// give enough currency to accounts and treasury and double check
Balances::make_free_balance_be(&account(1), 1000);
Balances::make_free_balance_be(&account(2), 1000);
Balances::make_free_balance_be(&account(3), 1000);
Balances::make_free_balance_be(
&<Test as pallet_quota::Config>::RefundAccount::get(),
10_000,
);
assert_eq!(
Balances::free_balance(<Test as pallet_quota::Config>::RefundAccount::get()),
10_000
);
// fill in the refund queue
Quota::queue_refund(pallet_quota::Refund {
account: account(1),
identity: 10,
amount: 10,
});
Quota::queue_refund(pallet_quota::Refund {
account: account(2),
identity: 2,
amount: 500,
});
Quota::queue_refund(pallet_quota::Refund {
account: account(3),
identity: 3,
amount: 666,
});
// process it with only no weight
Quota::process_refund_queue(Weight::from(0));
// after processing, it should be of the same size
assert_eq!(pallet_quota::RefundQueue::<Test>::get().len(), 3);
// process it with only 200 allowed weight
Quota::process_refund_queue(Weight::from_parts(200u64, 0));
// after processing, it should be of size 1 because total_weight += 25*2 by iteration and
// limit is total_weight < 200-100 so 2 elements can be processed
assert_eq!(pallet_quota::RefundQueue::<Test>::get().len(), 1);
// and we should observe the effects of refund
assert_eq!(Balances::free_balance(account(3)), 1666); // 1000 initial + 666 refunded
assert_eq!(Balances::free_balance(account(2)), 1500); // 1000 initial + 1500 refunded
assert_eq!(Balances::free_balance(account(1)), 1000); // only initial because no available weight to process
assert_eq!(
Balances::free_balance(<Test as pallet_quota::Config>::RefundAccount::get()),
// initial minus refunds
10_000 - 666 - 500
);
// events
System::assert_has_event(RuntimeEvent::Quota(pallet_quota::Event::Refunded {
who: account(3),
identity: 3,
amount: 666,
}));
System::assert_has_event(RuntimeEvent::Quota(pallet_quota::Event::Refunded {
who: account(2),
identity: 2,
amount: 500,
}));
})
}
/// test complete scenario with queue and process refund queue weight with limited quotas
#[test]
fn test_process_refund_queue_weight_no_quotas() {
new_test_ext(QuotaConfig {
identities: vec![1, 2],
})
.execute_with(|| {
run_to_block(15);
// give enough currency to accounts and treasury and double check
Balances::make_free_balance_be(&account(1), 1000);
Balances::make_free_balance_be(&account(2), 1000);
Balances::make_free_balance_be(&account(3), 1000);
Balances::make_free_balance_be(
&<Test as pallet_quota::Config>::RefundAccount::get(),
10_000,
);
assert_eq!(
Balances::free_balance(<Test as pallet_quota::Config>::RefundAccount::get()),
10_000
);
// fill in the refund queue
Quota::queue_refund(pallet_quota::Refund {
account: account(1),
identity: 10,
amount: 10,
});
Quota::queue_refund(pallet_quota::Refund {
account: account(2),
identity: 2,
amount: 500,
});
Quota::queue_refund(pallet_quota::Refund {
account: account(3),
identity: 3,
amount: 666,
});
// process it with only no weight
Quota::process_refund_queue(Weight::from(0));
// after processing, it should be of the same size
assert_eq!(pallet_quota::RefundQueue::<Test>::get().len(), 3);
// process it with only 150 allowed weight
Quota::process_refund_queue(Weight::from_parts(150u64, 0));
// after processing, it should be of size 2 because try_refund weight is 25 (first in the queue with no quota) then 25*2 for the 2 other elements
// limit is total_weight < 150-100 so 2 elements can be processed
assert_eq!(pallet_quota::RefundQueue::<Test>::get().len(), 1);
// and we should observe the effects of refund
assert_eq!(Balances::free_balance(account(3)), 1000); // 1000 initial only because no quota available
assert_eq!(Balances::free_balance(account(2)), 1500); // 1000 initial + 500 refunded
assert_eq!(Balances::free_balance(account(1)), 1000); // only initial because no available weight to process
assert_eq!(
Balances::free_balance(<Test as pallet_quota::Config>::RefundAccount::get()),
// initial minus refunds
10_000 - 500
);
// events
System::assert_has_event(RuntimeEvent::Quota(pallet_quota::Event::Refunded {
who: account(2),
identity: 2,
amount: 500,
}));
})
}