use crate::{mock::*, *};
use pezframe_support::{assert_noop, assert_ok};
use pezsp_runtime::{testing::UintAuthorityId, transaction_validity::InvalidTransaction};
#[test]
fn non_restricted_origin_is_not_charged() {
new_test_ext().execute_with(|| {
advance_by(1);
assert_ok!(exec_signed_tx(NON_RESTRICTED_ORIGIN, MockPalletCall::do_something {}));
assert!(
Usages::<Test>::iter().next().is_none(),
"Non-restricted origin should have no tracked usage."
);
});
}
#[test]
fn restricted_origin_works() {
new_test_ext().execute_with(|| {
let len = {
let tx_ext = (RestrictOrigin::<Test>::new(true),);
let tx = UncheckedExtrinsic::new_signed(
MockPalletCall::do_something {}.into(),
RESTRICTED_ORIGIN_1,
UintAuthorityId(RESTRICTED_ORIGIN_1),
tx_ext,
);
tx.encoded_size() as u64
};
let mut previous_used = 0;
assert_eq!(ALLOWANCE_RECOVERY_PER_BLOCK, 5);
assert_eq!(CALL_WEIGHT, 15);
assert_eq!(MAX_ALLOWANCE, 100);
advance_by(1);
assert_ok!(exec_signed_tx(RESTRICTED_ORIGIN_1, MockPalletCall::do_something {}));
let usage = Usages::<Test>::get(RuntimeRestrictedEntity::A).unwrap();
assert_eq!(usage.used, previous_used + CALL_WEIGHT + len);
assert_eq!(usage.at_block, 1);
previous_used = Usages::<Test>::get(RuntimeRestrictedEntity::A).unwrap().used;
assert_ok!(exec_signed_tx(RESTRICTED_ORIGIN_1, MockPalletCall::do_something_refunded {}));
let usage_after = Usages::<Test>::get(RuntimeRestrictedEntity::A).unwrap();
assert_eq!(usage_after.used, previous_used);
assert_ok!(exec_signed_tx(RESTRICTED_ORIGIN_1, MockPalletCall::do_something {}));
let usage = Usages::<Test>::get(RuntimeRestrictedEntity::A).unwrap();
assert_eq!(usage.used, previous_used + CALL_WEIGHT + len);
assert_noop!(
exec_signed_tx(RESTRICTED_ORIGIN_1, MockPalletCall::do_something {}),
InvalidTransaction::Payment
);
advance_by(1);
assert_noop!(
exec_signed_tx(RESTRICTED_ORIGIN_1, MockPalletCall::do_something {}),
InvalidTransaction::Payment
);
advance_by(1);
previous_used = Usages::<Test>::get(RuntimeRestrictedEntity::A).unwrap().used;
assert_ok!(exec_signed_tx(RESTRICTED_ORIGIN_1, MockPalletCall::do_something {}));
let current_usage = Usages::<Test>::get(RuntimeRestrictedEntity::A).unwrap();
let recovered_amount = 2 * ALLOWANCE_RECOVERY_PER_BLOCK;
assert_eq!(current_usage.used, previous_used + CALL_WEIGHT + len - recovered_amount);
assert_eq!(current_usage.at_block, 3);
});
}
#[test]
fn one_time_excess_works_and_works_only_one_time() {
new_test_ext().execute_with(|| {
advance_by(1);
assert_ok!(exec_signed_tx(
RESTRICTED_ORIGIN_1,
MockPalletCall::do_something_allowed_excess {}
));
let current_usage = Usages::<Test>::get(RuntimeRestrictedEntity::A).unwrap();
assert!(current_usage.used > MAX_ALLOWANCE);
assert_noop!(
exec_signed_tx(RESTRICTED_ORIGIN_1, MockPalletCall::do_something_allowed_excess {}),
InvalidTransaction::Payment
);
});
}
#[test]
fn one_time_excess_is_origin_specific() {
new_test_ext().execute_with(|| {
advance_by(1);
assert_noop!(
exec_signed_tx(RESTRICTED_ORIGIN_2, MockPalletCall::do_something_allowed_excess {}),
InvalidTransaction::Payment
);
assert_ok!(exec_signed_tx(
RESTRICTED_ORIGIN_1,
MockPalletCall::do_something_allowed_excess {}
));
let current_usage = Usages::<Test>::get(RuntimeRestrictedEntity::A).unwrap();
assert!(current_usage.used > MAX_ALLOWANCE);
});
}
#[test]
fn one_time_excess_requires_usage_zero() {
new_test_ext().execute_with(|| {
advance_by(1);
assert_ok!(exec_signed_tx(RESTRICTED_ORIGIN_1, MockPalletCall::do_something {}));
let usage = Usages::<Test>::get(RuntimeRestrictedEntity::A).unwrap();
assert!(usage.used < MAX_ALLOWANCE);
assert!(usage.used > 0);
assert_noop!(
exec_signed_tx(RESTRICTED_ORIGIN_1, MockPalletCall::do_something_allowed_excess {}),
InvalidTransaction::Payment
);
});
}
#[test]
fn clean_usage_works() {
new_test_ext().execute_with(|| {
advance_by(1);
assert_noop!(
OriginsRestriction::clean_usage(
pezframe_system::RawOrigin::Root.into(),
RuntimeRestrictedEntity::A
),
Error::<Test>::NoUsage
);
assert_ok!(exec_signed_tx(RESTRICTED_ORIGIN_1, MockPalletCall::do_something {}));
let usage = Usages::<Test>::get(RuntimeRestrictedEntity::A).expect("Usage must be present");
assert!(usage.used > 0, "Usage should have increased after the call");
assert_noop!(
OriginsRestriction::clean_usage(
pezframe_system::RawOrigin::Root.into(),
RuntimeRestrictedEntity::A
),
Error::<Test>::NotZero
);
let used_amount = usage.used;
let blocks_needed = used_amount.div_ceil(ALLOWANCE_RECOVERY_PER_BLOCK);
advance_by(blocks_needed);
assert_ok!(OriginsRestriction::clean_usage(
pezframe_system::RawOrigin::Root.into(),
RuntimeRestrictedEntity::A
));
assert!(Usages::<Test>::get(RuntimeRestrictedEntity::A).is_none());
System::assert_last_event(RuntimeEvent::OriginsRestriction(Event::UsageCleaned {
entity: RuntimeRestrictedEntity::A,
}));
assert_noop!(
OriginsRestriction::clean_usage(
pezframe_system::RawOrigin::Root.into(),
RuntimeRestrictedEntity::A
),
Error::<Test>::NoUsage
);
});
}
#[test]
fn restrict_origin_extension_disabled_behavior() {
new_test_ext().execute_with(|| {
advance_by(1);
assert_noop!(
exec_signed_tx_disabled(RESTRICTED_ORIGIN_1, MockPalletCall::do_something {}),
pezsp_runtime::transaction_validity::InvalidTransaction::Call
);
assert_ok!(exec_signed_tx_disabled(NON_RESTRICTED_ORIGIN, MockPalletCall::do_something {}));
assert!(
Usages::<Test>::iter().next().is_none(),
"Extension is disabled, so no usage should be tracked for non-restricted origins."
);
});
}