srml-contract: Fail calls to removed contracts instead of succeeding. (#2968)

* srml-contract: Refactor to reduce unnecessary storage lookups.

* srml-contract: Fail calls to removed contracts.

Previously, the calls would transfer funds and succeed without executing
any code on the target account, which is unintuitive behavior.

* Bump node runtime spec/impl versions.
This commit is contained in:
Jim Posen
2019-07-04 14:08:40 +02:00
committed by Sergei Pepyakin
parent 51e345c901
commit beea27b0f3
3 changed files with 94 additions and 35 deletions
+23 -21
View File
@@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
use crate::{BalanceOf, ContractInfo, ContractInfoOf, TombstoneContractInfo, Trait};
use crate::{BalanceOf, ContractInfo, ContractInfoOf, TombstoneContractInfo, Trait, AliveContractInfo};
use runtime_primitives::traits::{Bounded, CheckedDiv, CheckedMul, Saturating, Zero,
SaturatedConversion};
use srml_support::traits::{Currency, ExistenceRequirement, Get, WithdrawReason};
@@ -50,9 +50,10 @@ fn try_evict_or_and_pay_rent<T: Trait>(
account: &T::AccountId,
handicap: T::BlockNumber,
pay_rent: bool,
) -> RentOutcome {
let contract = match <ContractInfoOf<T>>::get(account) {
None | Some(ContractInfo::Tombstone(_)) => return RentOutcome::Exempted,
) -> (RentOutcome, Option<ContractInfo<T>>) {
let contract_info = <ContractInfoOf<T>>::get(account);
let contract = match contract_info {
None | Some(ContractInfo::Tombstone(_)) => return (RentOutcome::Exempted, contract_info),
Some(ContractInfo::Alive(contract)) => contract,
};
@@ -65,7 +66,7 @@ fn try_evict_or_and_pay_rent<T: Trait>(
let n = effective_block_number.saturating_sub(contract.deduct_block);
if n.is_zero() {
// Rent has already been paid
return RentOutcome::Exempted;
return (RentOutcome::Exempted, Some(ContractInfo::Alive(contract)));
}
n
};
@@ -89,7 +90,7 @@ fn try_evict_or_and_pay_rent<T: Trait>(
if fee_per_block.is_zero() {
// The rent deposit offset reduced the fee to 0. This means that the contract
// gets the rent for free.
return RentOutcome::Exempted;
return (RentOutcome::Exempted, Some(ContractInfo::Alive(contract)));
}
// The minimal amount of funds required for a contract not to be evicted.
@@ -99,7 +100,7 @@ fn try_evict_or_and_pay_rent<T: Trait>(
// The contract cannot afford to leave a tombstone, so remove the contract info altogether.
<ContractInfoOf<T>>::remove(account);
runtime_io::kill_child_storage(&contract.trie_id);
return RentOutcome::Evicted;
return (RentOutcome::Evicted, None);
}
let dues = fee_per_block
@@ -149,33 +150,34 @@ fn try_evict_or_and_pay_rent<T: Trait>(
&child_storage_root[..],
contract.code_hash,
);
<ContractInfoOf<T>>::insert(account, ContractInfo::Tombstone(tombstone));
let tombstone_info = ContractInfo::Tombstone(tombstone);
<ContractInfoOf<T>>::insert(account, &tombstone_info);
runtime_io::kill_child_storage(&contract.trie_id);
return RentOutcome::Evicted;
return (RentOutcome::Evicted, Some(tombstone_info));
}
if pay_rent {
<ContractInfoOf<T>>::mutate(account, |contract| {
let contract = contract
.as_mut()
.and_then(|c| c.as_alive_mut())
.expect("Dead or nonexistent account has been exempt above; qed");
let contract_info = ContractInfo::Alive(AliveContractInfo::<T> {
rent_allowance: contract.rent_allowance - dues, // rent_allowance is not exceeded
deduct_block: current_block_number,
..contract
});
contract.rent_allowance -= dues; // rent_allowance is not exceeded
contract.deduct_block = current_block_number;
})
<ContractInfoOf<T>>::insert(account, &contract_info);
return (RentOutcome::Ok, Some(contract_info));
}
RentOutcome::Ok
(RentOutcome::Ok, Some(ContractInfo::Alive(contract)))
}
/// Make account paying the rent for the current block number
///
/// NOTE: This function acts eagerly.
pub fn pay_rent<T: Trait>(account: &T::AccountId) {
let _ = try_evict_or_and_pay_rent::<T>(account, Zero::zero(), true);
pub fn pay_rent<T: Trait>(account: &T::AccountId) -> Option<ContractInfo<T>> {
try_evict_or_and_pay_rent::<T>(account, Zero::zero(), true).1
}
/// Evict the account if it should be evicted at the given block number.
@@ -186,5 +188,5 @@ pub fn pay_rent<T: Trait>(account: &T::AccountId) {
///
/// NOTE: This function acts eagerly.
pub fn try_evict<T: Trait>(account: &T::AccountId, handicap: T::BlockNumber) -> RentOutcome {
try_evict_or_and_pay_rent::<T>(account, handicap, false)
try_evict_or_and_pay_rent::<T>(account, handicap, false).0
}