Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Commit ce03f37

Browse files
authored
Fix semantics of ExistenceRequirement::KeepAlive. (#3796)
* Fix semantics of ExistenceRequirement::KeepAlive. * Bump runtime version
1 parent 7adfd83 commit ce03f37

File tree

4 files changed

+49
-3
lines changed

4 files changed

+49
-3
lines changed

node/runtime/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
8484
// and set impl_version to equal spec_version. If only runtime
8585
// implementation changes and behavior does not, then leave spec_version as
8686
// is and increment impl_version.
87-
spec_version: 174,
87+
spec_version: 175,
8888
impl_version: 175,
8989
apis: RUNTIME_API_VERSIONS,
9090
};

srml/balances/src/lib.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -947,8 +947,15 @@ where
947947
reason: WithdrawReason,
948948
liveness: ExistenceRequirement,
949949
) -> result::Result<Self::NegativeImbalance, &'static str> {
950-
if let Some(new_balance) = Self::free_balance(who).checked_sub(&value) {
951-
if liveness == ExistenceRequirement::KeepAlive && new_balance < T::ExistentialDeposit::get() {
950+
let old_balance = Self::free_balance(who);
951+
if let Some(new_balance) = old_balance.checked_sub(&value) {
952+
// if we need to keep the account alive...
953+
if liveness == ExistenceRequirement::KeepAlive
954+
// ...and it would be dead afterwards...
955+
&& new_balance < T::ExistentialDeposit::get()
956+
// ...yet is was alive before
957+
&& old_balance >= T::ExistentialDeposit::get()
958+
{
952959
return Err("payment would kill account")
953960
}
954961
Self::ensure_can_withdraw(who, value, reason, new_balance)?;

srml/balances/src/tests.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use support::{
2525
traits::{LockableCurrency, LockIdentifier, WithdrawReason, WithdrawReasons,
2626
Currency, ReservableCurrency}
2727
};
28+
use sr_primitives::weights::DispatchClass;
2829
use system::RawOrigin;
2930

3031
const ID_1: LockIdentifier = *b"1 ";
@@ -783,6 +784,41 @@ fn signed_extension_take_fees_is_bounded() {
783784
});
784785
}
785786

787+
#[test]
788+
fn signed_extension_allows_free_transactions() {
789+
ExtBuilder::default()
790+
.transaction_fees(100, 1, 1)
791+
.monied(false)
792+
.build()
793+
.execute_with(|| {
794+
// 1 ain't have a penny.
795+
assert_eq!(Balances::free_balance(&1), 0);
796+
797+
// like a FreeOperational
798+
let operational_transaction = DispatchInfo {
799+
weight: 0,
800+
class: DispatchClass::Operational
801+
};
802+
let len = 100;
803+
assert!(
804+
TakeFees::<Runtime>::from(0)
805+
.validate(&1, CALL, operational_transaction , len)
806+
.is_ok()
807+
);
808+
809+
// like a FreeNormal
810+
let free_transaction = DispatchInfo {
811+
weight: 0,
812+
class: DispatchClass::Normal
813+
};
814+
assert!(
815+
TakeFees::<Runtime>::from(0)
816+
.validate(&1, CALL, free_transaction , len)
817+
.is_err()
818+
);
819+
});
820+
}
821+
786822
#[test]
787823
fn burn_must_work() {
788824
ExtBuilder::default().monied(true).build().execute_with(|| {

srml/support/src/traits.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,9 @@ impl<Imbalance: Drop> OnUnbalanced<Imbalance> for () {
156156
#[derive(Copy, Clone, Eq, PartialEq)]
157157
pub enum ExistenceRequirement {
158158
/// Operation must not result in the account going out of existence.
159+
///
160+
/// Note this implies that if the account never existed in the first place, then the operation
161+
/// may legitimately leave the account unchanged and still non-existent.
159162
KeepAlive,
160163
/// Operation may result in account going out of existence.
161164
AllowDeath,

0 commit comments

Comments
 (0)