mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-27 18:37:59 +00:00
Contract accounting removal (#2230)
* first partial implementation * update rent allowance * fmt Co-Authored-By: thiolliere <gui.thiolliere@gmail.com> * remove comments * reward surcharge claims * remove rent allowance in param + code_hash changed * Fix bug * fix tests * fmt * impl getter setter rent allowance * fmt Co-Authored-By: thiolliere <gui.thiolliere@gmail.com> * comments * doc + be->le * doc * doc * fix improve fast return * renamings * rename + COMPLEXITY * COMPLEXITY * add test * etrinsic claim surcharge delay configurable * comment addressed * move and rewrite of pay_rent * remove child trie * fmt * use derive * arithmetic operation * fix * fix storage root + checked_mul + test * WIP: test * WIP * add tests and fix * fmt * typo and doc suggestions Co-Authored-By: thiolliere <gui.thiolliere@gmail.com> * WIP * address some comments divide tests + some docs * use br_table * remove unused function * Bump the runtime version * insert_with * Add some comments. * Refactor * Shuffle and fix comments * More comment fixes. * dues limited * Add comment * Handicap * Docs. * Apply suggestions from code review Co-Authored-By: pepyakin <s.pepyakin@gmail.com> * Coalesce block_passed in a block * Fix build * Paid → Ok * match → if * Imrpove handicap description
This commit is contained in:
committed by
Sergei Pepyakin
parent
f14580535e
commit
c7d9ca379d
@@ -19,27 +19,28 @@
|
||||
|
||||
#![allow(unused)]
|
||||
|
||||
use runtime_io::with_externalities;
|
||||
use runtime_primitives::testing::{Digest, DigestItem, H256, Header, UintAuthorityId};
|
||||
use runtime_primitives::traits::{BlakeTwo256, IdentityLookup};
|
||||
use runtime_primitives::BuildStorage;
|
||||
use runtime_io;
|
||||
use srml_support::{storage::child, StorageMap, assert_ok, impl_outer_event, impl_outer_dispatch,
|
||||
impl_outer_origin, traits::Currency};
|
||||
use substrate_primitives::Blake2Hasher;
|
||||
use system::{self, Phase, EventRecord};
|
||||
use {wabt, balances, consensus};
|
||||
use hex_literal::hex;
|
||||
use assert_matches::assert_matches;
|
||||
use crate::account_db::{AccountDb, DirectAccountDb, OverlayAccountDb};
|
||||
use crate::{
|
||||
ContractAddressFor, GenesisConfig, Module, RawEvent,
|
||||
Trait, ComputeDispatchFee, TrieIdGenerator, TrieId,
|
||||
AccountInfo, AccountInfoOf, TrieIdFromParentCounter
|
||||
ComputeDispatchFee, ContractAddressFor, ContractInfo, ContractInfoOf, GenesisConfig, Module,
|
||||
RawAliveContractInfo, RawEvent, Trait, TrieId, TrieIdFromParentCounter, TrieIdGenerator,
|
||||
};
|
||||
use assert_matches::assert_matches;
|
||||
use hex_literal::*;
|
||||
use parity_codec::{Decode, Encode, KeyedVec};
|
||||
use runtime_io;
|
||||
use runtime_io::with_externalities;
|
||||
use runtime_primitives::testing::{Digest, DigestItem, Header, UintAuthorityId, H256};
|
||||
use runtime_primitives::traits::{As, BlakeTwo256, IdentityLookup};
|
||||
use runtime_primitives::BuildStorage;
|
||||
use srml_support::{
|
||||
assert_ok, impl_outer_dispatch, impl_outer_event, impl_outer_origin, storage::child,
|
||||
traits::Currency, StorageMap,
|
||||
};
|
||||
use substrate_primitives::storage::well_known_keys;
|
||||
use parity_codec::{Encode, Decode, KeyedVec};
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use crate::account_db::{DirectAccountDb, OverlayAccountDb, AccountDb};
|
||||
use substrate_primitives::storage::well_known_keys;
|
||||
use substrate_primitives::Blake2Hasher;
|
||||
use system::{self, EventRecord, Phase};
|
||||
use {balances, consensus, wabt};
|
||||
|
||||
mod contract {
|
||||
// Re-export contents of the root. This basically
|
||||
@@ -206,8 +207,14 @@ impl ExtBuilder {
|
||||
);
|
||||
t.extend(
|
||||
GenesisConfig::<Test> {
|
||||
transaction_base_fee: 0,
|
||||
transaction_byte_fee: 0,
|
||||
signed_claim_handicap: 2,
|
||||
rent_byte_price: 4,
|
||||
rent_deposit_offset: 10_000,
|
||||
storage_size_offset: 8,
|
||||
surcharge_reward: 150,
|
||||
tombstone_deposit: 16,
|
||||
transaction_base_fee: 2,
|
||||
transaction_byte_fee: 6,
|
||||
transfer_fee: self.transfer_fee,
|
||||
creation_fee: self.creation_fee,
|
||||
contract_fee: 21,
|
||||
@@ -231,13 +238,7 @@ fn refunds_unused_gas() {
|
||||
with_externalities(&mut ExtBuilder::default().build(), || {
|
||||
Balances::deposit_creating(&0, 100_000_000);
|
||||
|
||||
assert_ok!(Contract::call(
|
||||
Origin::signed(0),
|
||||
1,
|
||||
0,
|
||||
100_000,
|
||||
Vec::new()
|
||||
));
|
||||
assert_ok!(Contract::call(Origin::signed(0), 1, 0, 100_000, Vec::new()));
|
||||
|
||||
assert_eq!(Balances::free_balance(&0), 100_000_000 - (2 * 135));
|
||||
});
|
||||
@@ -256,10 +257,13 @@ fn account_removal_removes_storage() {
|
||||
// Set up two accounts with free balance above the existential threshold.
|
||||
{
|
||||
Balances::deposit_creating(&1, 110);
|
||||
AccountInfoOf::<Test>::insert(1, &AccountInfo {
|
||||
ContractInfoOf::<Test>::insert(1, &ContractInfo::Alive(RawAliveContractInfo {
|
||||
trie_id: trie_id1.clone(),
|
||||
storage_size: 0,
|
||||
});
|
||||
storage_size: Contract::storage_size_offset(),
|
||||
deduct_block: System::block_number(),
|
||||
code_hash: H256::repeat_byte(1),
|
||||
rent_allowance: 40,
|
||||
}));
|
||||
|
||||
let mut overlay = OverlayAccountDb::<Test>::new(&DirectAccountDb);
|
||||
overlay.set_storage(&1, key1.clone(), Some(b"1".to_vec()));
|
||||
@@ -267,10 +271,13 @@ fn account_removal_removes_storage() {
|
||||
DirectAccountDb.commit(overlay.into_change_set());
|
||||
|
||||
Balances::deposit_creating(&2, 110);
|
||||
AccountInfoOf::<Test>::insert(2, &AccountInfo {
|
||||
ContractInfoOf::<Test>::insert(2, &ContractInfo::Alive(RawAliveContractInfo {
|
||||
trie_id: trie_id2.clone(),
|
||||
storage_size: 0,
|
||||
});
|
||||
storage_size: Contract::storage_size_offset(),
|
||||
deduct_block: System::block_number(),
|
||||
code_hash: H256::repeat_byte(2),
|
||||
rent_allowance: 40,
|
||||
}));
|
||||
|
||||
let mut overlay = OverlayAccountDb::<Test>::new(&DirectAccountDb);
|
||||
overlay.set_storage(&2, key1.clone(), Some(b"3".to_vec()));
|
||||
@@ -287,7 +294,6 @@ fn account_removal_removes_storage() {
|
||||
// Verify that all entries from account 1 is removed, while
|
||||
// entries from account 2 is in place.
|
||||
{
|
||||
// let a: <Test as system::Trait>::AccountId = 1;
|
||||
assert!(<AccountDb<Test>>::get_storage(&DirectAccountDb, &1, Some(&trie_id1), key1).is_none());
|
||||
assert!(<AccountDb<Test>>::get_storage(&DirectAccountDb, &1, Some(&trie_id1), key2).is_none());
|
||||
|
||||
@@ -342,11 +348,7 @@ fn instantiate_and_call_and_deposit_event() {
|
||||
|| {
|
||||
Balances::deposit_creating(&ALICE, 1_000_000);
|
||||
|
||||
assert_ok!(Contract::put_code(
|
||||
Origin::signed(ALICE),
|
||||
100_000,
|
||||
wasm,
|
||||
));
|
||||
assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm));
|
||||
|
||||
// Check at the end to get hash on error easily
|
||||
let creation = Contract::create(
|
||||
@@ -387,7 +389,7 @@ fn instantiate_and_call_and_deposit_event() {
|
||||
]);
|
||||
|
||||
assert_ok!(creation);
|
||||
assert!(AccountInfoOf::<Test>::exists(BOB));
|
||||
assert!(ContractInfoOf::<Test>::exists(BOB));
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -424,11 +426,7 @@ fn dispatch_call() {
|
||||
|| {
|
||||
Balances::deposit_creating(&ALICE, 1_000_000);
|
||||
|
||||
assert_ok!(Contract::put_code(
|
||||
Origin::signed(ALICE),
|
||||
100_000,
|
||||
wasm,
|
||||
));
|
||||
assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm));
|
||||
|
||||
// Let's keep this assert even though it's redundant. If you ever need to update the
|
||||
// wasm source this test will fail and will show you the actual hash.
|
||||
@@ -506,3 +504,399 @@ fn dispatch_call() {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
const CODE_SET_RENT: &str = r#"
|
||||
(module
|
||||
(import "env" "ext_dispatch_call" (func $ext_dispatch_call (param i32 i32)))
|
||||
(import "env" "ext_set_storage" (func $ext_set_storage (param i32 i32 i32 i32)))
|
||||
(import "env" "ext_set_rent_allowance" (func $ext_set_rent_allowance (param i32 i32)))
|
||||
(import "env" "ext_input_size" (func $ext_input_size (result i32)))
|
||||
(import "env" "ext_input_copy" (func $ext_input_copy (param i32 i32 i32)))
|
||||
(import "env" "memory" (memory 1 1))
|
||||
|
||||
;; insert a value of 4 bytes into storage
|
||||
(func $call_0
|
||||
(call $ext_set_storage
|
||||
(i32.const 1)
|
||||
(i32.const 1)
|
||||
(i32.const 0)
|
||||
(i32.const 4)
|
||||
)
|
||||
)
|
||||
|
||||
;; remove the value inserted by call_1
|
||||
(func $call_1
|
||||
(call $ext_set_storage
|
||||
(i32.const 1)
|
||||
(i32.const 0)
|
||||
(i32.const 0)
|
||||
(i32.const 0)
|
||||
)
|
||||
)
|
||||
|
||||
;; transfer 50 to ALICE
|
||||
(func $call_2
|
||||
(call $ext_dispatch_call
|
||||
(i32.const 8)
|
||||
(i32.const 11)
|
||||
)
|
||||
)
|
||||
|
||||
;; do nothing
|
||||
(func $call_else)
|
||||
|
||||
(func $assert (param i32)
|
||||
(block $ok
|
||||
(br_if $ok
|
||||
(get_local 0)
|
||||
)
|
||||
(unreachable)
|
||||
)
|
||||
)
|
||||
|
||||
;; Dispatch the call according to input size
|
||||
(func (export "call")
|
||||
(local $input_size i32)
|
||||
(set_local $input_size
|
||||
(call $ext_input_size)
|
||||
)
|
||||
(block $IF_ELSE
|
||||
(block $IF_2
|
||||
(block $IF_1
|
||||
(block $IF_0
|
||||
(br_table $IF_0 $IF_1 $IF_2 $IF_ELSE
|
||||
(get_local $input_size)
|
||||
)
|
||||
(unreachable)
|
||||
)
|
||||
(call $call_0)
|
||||
return
|
||||
)
|
||||
(call $call_1)
|
||||
return
|
||||
)
|
||||
(call $call_2)
|
||||
return
|
||||
)
|
||||
(call $call_else)
|
||||
)
|
||||
|
||||
;; Set into storage a 4 bytes value
|
||||
;; Set call set_rent_allowance with input
|
||||
(func (export "deploy")
|
||||
(local $input_size i32)
|
||||
(call $ext_set_storage
|
||||
(i32.const 0)
|
||||
(i32.const 1)
|
||||
(i32.const 0)
|
||||
(i32.const 4)
|
||||
)
|
||||
(set_local $input_size
|
||||
(call $ext_input_size)
|
||||
)
|
||||
(call $ext_input_copy
|
||||
(i32.const 0)
|
||||
(i32.const 0)
|
||||
(get_local $input_size)
|
||||
)
|
||||
(call $ext_set_rent_allowance
|
||||
(i32.const 0)
|
||||
(get_local $input_size)
|
||||
)
|
||||
)
|
||||
|
||||
;; Encoding of 10 in balance
|
||||
(data (i32.const 0) "\28")
|
||||
|
||||
;; Encoding of call transfer 50 to CHARLIE
|
||||
(data (i32.const 8) "\00\00\03\00\00\00\00\00\00\00\C8")
|
||||
)
|
||||
"#;
|
||||
const HASH_SET_RENT: [u8; 32] = hex!("a51c2a6f3f68936d4ae9abdb93b28eedcbd0f6f39770e168f9025f0c1e7094ef");
|
||||
|
||||
|
||||
/// Input data for each call in set_rent code
|
||||
mod call {
|
||||
pub fn set_storage_4_byte() -> Vec<u8> { vec![] }
|
||||
pub fn remove_storage_4_byte() -> Vec<u8> { vec![0] }
|
||||
pub fn transfer() -> Vec<u8> { vec![0, 0] }
|
||||
pub fn null() -> Vec<u8> { vec![0, 0, 0] }
|
||||
}
|
||||
|
||||
/// Test correspondance of set_rent code and its hash.
|
||||
/// Also test that encoded extrinsic in code correspond to the correct transfer
|
||||
#[test]
|
||||
fn set_rent_hash_and_code() {
|
||||
// This test can fail due to the encoding changes. In case it becomes too annoying
|
||||
// let's rewrite so as we use this module controlled call or we serialize it in runtime.
|
||||
let encoded = parity_codec::Encode::encode(&Call::Balances(balances::Call::transfer(CHARLIE, 50)));
|
||||
assert_eq!(&encoded[..], &hex!("00000300000000000000C8")[..]);
|
||||
|
||||
let wasm = wabt::wat2wasm(CODE_SET_RENT).unwrap();
|
||||
|
||||
with_externalities(
|
||||
&mut ExtBuilder::default().existential_deposit(50).build(),
|
||||
|| {
|
||||
Balances::deposit_creating(&ALICE, 1_000_000);
|
||||
assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm));
|
||||
|
||||
// If you ever need to update the wasm source this test will fail and will show you the actual hash.
|
||||
assert_eq!(System::events(), vec![
|
||||
EventRecord {
|
||||
phase: Phase::ApplyExtrinsic(0),
|
||||
event: MetaEvent::balances(balances::RawEvent::NewAccount(1, 1_000_000)),
|
||||
},
|
||||
EventRecord {
|
||||
phase: Phase::ApplyExtrinsic(0),
|
||||
event: MetaEvent::contract(RawEvent::CodeStored(HASH_SET_RENT.into())),
|
||||
},
|
||||
]);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn storage_size() {
|
||||
let wasm = wabt::wat2wasm(CODE_SET_RENT).unwrap();
|
||||
|
||||
// Storage size
|
||||
with_externalities(
|
||||
&mut ExtBuilder::default().existential_deposit(50).build(),
|
||||
|| {
|
||||
// Create
|
||||
Balances::deposit_creating(&ALICE, 1_000_000);
|
||||
assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm));
|
||||
assert_ok!(Contract::create(
|
||||
Origin::signed(ALICE),
|
||||
30_000,
|
||||
100_000, HASH_SET_RENT.into(),
|
||||
<Test as balances::Trait>::Balance::sa(1_000u64).encode() // rent allowance
|
||||
));
|
||||
let bob_contract = super::ContractInfoOf::<Test>::get(BOB).unwrap().get_alive().unwrap();
|
||||
assert_eq!(bob_contract.storage_size, Contract::storage_size_offset() + 4);
|
||||
|
||||
assert_ok!(Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::set_storage_4_byte()));
|
||||
let bob_contract = super::ContractInfoOf::<Test>::get(BOB).unwrap().get_alive().unwrap();
|
||||
assert_eq!(bob_contract.storage_size, Contract::storage_size_offset() + 4 + 4);
|
||||
|
||||
assert_ok!(Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::remove_storage_4_byte()));
|
||||
let bob_contract = super::ContractInfoOf::<Test>::get(BOB).unwrap().get_alive().unwrap();
|
||||
assert_eq!(bob_contract.storage_size, Contract::storage_size_offset() + 4);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deduct_blocks() {
|
||||
let wasm = wabt::wat2wasm(CODE_SET_RENT).unwrap();
|
||||
|
||||
with_externalities(
|
||||
&mut ExtBuilder::default().existential_deposit(50).build(),
|
||||
|| {
|
||||
// Create
|
||||
Balances::deposit_creating(&ALICE, 1_000_000);
|
||||
assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm));
|
||||
assert_ok!(Contract::create(
|
||||
Origin::signed(ALICE),
|
||||
30_000,
|
||||
100_000, HASH_SET_RENT.into(),
|
||||
<Test as balances::Trait>::Balance::sa(1_000u64).encode() // rent allowance
|
||||
));
|
||||
|
||||
// Check creation
|
||||
let bob_contract = super::ContractInfoOf::<Test>::get(BOB).unwrap().get_alive().unwrap();
|
||||
assert_eq!(bob_contract.rent_allowance, 1_000);
|
||||
|
||||
// Advance 4 blocks
|
||||
System::initialize(&5, &[0u8; 32].into(), &[0u8; 32].into());
|
||||
|
||||
// Trigger rent through call
|
||||
assert_ok!(Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::null()));
|
||||
|
||||
// Check result
|
||||
let rent = (8 + 4 - 3) // storage size = size_offset + deploy_set_storage - deposit_offset
|
||||
* 4 // rent byte price
|
||||
* 4; // blocks to rent
|
||||
let bob_contract = super::ContractInfoOf::<Test>::get(BOB).unwrap().get_alive().unwrap();
|
||||
assert_eq!(bob_contract.rent_allowance, 1_000 - rent);
|
||||
assert_eq!(Balances::free_balance(BOB), 30_000 - rent);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn call_contract_removals() {
|
||||
removals(|| Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::null()).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inherent_claim_surcharge_contract_removals() {
|
||||
removals(|| Contract::claim_surcharge(Origin::INHERENT, BOB, Some(ALICE)).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn signed_claim_surcharge_contract_removals() {
|
||||
removals(|| Contract::claim_surcharge(Origin::signed(ALICE), BOB, None).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn claim_surcharge_malus() {
|
||||
// Test surcharge malus for inherent
|
||||
claim_surcharge(4, || Contract::claim_surcharge(Origin::INHERENT, BOB, Some(ALICE)).is_ok(), true);
|
||||
claim_surcharge(3, || Contract::claim_surcharge(Origin::INHERENT, BOB, Some(ALICE)).is_ok(), true);
|
||||
claim_surcharge(2, || Contract::claim_surcharge(Origin::INHERENT, BOB, Some(ALICE)).is_ok(), true);
|
||||
claim_surcharge(1, || Contract::claim_surcharge(Origin::INHERENT, BOB, Some(ALICE)).is_ok(), false);
|
||||
|
||||
// Test surcharge malus for signed
|
||||
claim_surcharge(4, || Contract::claim_surcharge(Origin::signed(ALICE), BOB, None).is_ok(), true);
|
||||
claim_surcharge(3, || Contract::claim_surcharge(Origin::signed(ALICE), BOB, None).is_ok(), false);
|
||||
claim_surcharge(2, || Contract::claim_surcharge(Origin::signed(ALICE), BOB, None).is_ok(), false);
|
||||
claim_surcharge(1, || Contract::claim_surcharge(Origin::signed(ALICE), BOB, None).is_ok(), false);
|
||||
}
|
||||
|
||||
/// Claim surcharge with the given trigger_call at the given blocks.
|
||||
/// if removes is true then assert that the contract is a tombstonedead
|
||||
fn claim_surcharge(blocks: u64, trigger_call: impl Fn() -> bool, removes: bool) {
|
||||
let wasm = wabt::wat2wasm(CODE_SET_RENT).unwrap();
|
||||
|
||||
with_externalities(
|
||||
&mut ExtBuilder::default().existential_deposit(50).build(),
|
||||
|| {
|
||||
// Create
|
||||
Balances::deposit_creating(&ALICE, 1_000_000);
|
||||
assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm));
|
||||
assert_ok!(Contract::create(
|
||||
Origin::signed(ALICE),
|
||||
100,
|
||||
100_000, HASH_SET_RENT.into(),
|
||||
<Test as balances::Trait>::Balance::sa(1_000u64).encode() // rent allowance
|
||||
));
|
||||
|
||||
// Advance blocks
|
||||
System::initialize(&blocks, &[0u8; 32].into(), &[0u8; 32].into());
|
||||
|
||||
// Trigger rent through call
|
||||
assert!(trigger_call());
|
||||
|
||||
if removes {
|
||||
assert!(super::ContractInfoOf::<Test>::get(BOB).unwrap().get_tombstone().is_some());
|
||||
} else {
|
||||
assert!(super::ContractInfoOf::<Test>::get(BOB).unwrap().get_alive().is_some());
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/// Test for all kind of removals for the given trigger:
|
||||
/// * if balance is reached and balance > subsistence threshold
|
||||
/// * if allowance is exceeded
|
||||
/// * if balance is reached and balance < subsistence threshold
|
||||
fn removals(trigger_call: impl Fn() -> bool) {
|
||||
let wasm = wabt::wat2wasm(CODE_SET_RENT).unwrap();
|
||||
|
||||
// Balance reached and superior to subsistence threshold
|
||||
with_externalities(
|
||||
&mut ExtBuilder::default().existential_deposit(50).build(),
|
||||
|| {
|
||||
// Create
|
||||
Balances::deposit_creating(&ALICE, 1_000_000);
|
||||
assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm.clone()));
|
||||
assert_ok!(Contract::create(
|
||||
Origin::signed(ALICE),
|
||||
100,
|
||||
100_000, HASH_SET_RENT.into(),
|
||||
<Test as balances::Trait>::Balance::sa(1_000u64).encode() // rent allowance
|
||||
));
|
||||
|
||||
// Trigger rent must have no effect
|
||||
assert!(trigger_call());
|
||||
assert_eq!(super::ContractInfoOf::<Test>::get(BOB).unwrap().get_alive().unwrap().rent_allowance, 1_000);
|
||||
|
||||
// Advance blocks
|
||||
System::initialize(&10, &[0u8; 32].into(), &[0u8; 32].into());
|
||||
|
||||
// Trigger rent through call
|
||||
assert!(trigger_call());
|
||||
assert!(super::ContractInfoOf::<Test>::get(BOB).unwrap().get_tombstone().is_some());
|
||||
|
||||
// Advance blocks
|
||||
System::initialize(&20, &[0u8; 32].into(), &[0u8; 32].into());
|
||||
|
||||
// Trigger rent must have no effect
|
||||
assert!(trigger_call());
|
||||
assert!(super::ContractInfoOf::<Test>::get(BOB).unwrap().get_tombstone().is_some());
|
||||
}
|
||||
);
|
||||
|
||||
// Allowance exceeded
|
||||
with_externalities(
|
||||
&mut ExtBuilder::default().existential_deposit(50).build(),
|
||||
|| {
|
||||
// Create
|
||||
Balances::deposit_creating(&ALICE, 1_000_000);
|
||||
assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm.clone()));
|
||||
assert_ok!(Contract::create(
|
||||
Origin::signed(ALICE),
|
||||
1_000,
|
||||
100_000, HASH_SET_RENT.into(),
|
||||
<Test as balances::Trait>::Balance::sa(100u64).encode() // rent allowance
|
||||
));
|
||||
|
||||
// Trigger rent must have no effect
|
||||
assert!(trigger_call());
|
||||
assert_eq!(super::ContractInfoOf::<Test>::get(BOB).unwrap().get_alive().unwrap().rent_allowance, 100);
|
||||
|
||||
// Advance blocks
|
||||
System::initialize(&10, &[0u8; 32].into(), &[0u8; 32].into());
|
||||
|
||||
// Trigger rent through call
|
||||
assert!(trigger_call());
|
||||
assert!(super::ContractInfoOf::<Test>::get(BOB).unwrap().get_tombstone().is_some());
|
||||
|
||||
// Advance blocks
|
||||
System::initialize(&20, &[0u8; 32].into(), &[0u8; 32].into());
|
||||
|
||||
// Trigger rent must have no effect
|
||||
assert!(trigger_call());
|
||||
assert!(super::ContractInfoOf::<Test>::get(BOB).unwrap().get_tombstone().is_some());
|
||||
}
|
||||
);
|
||||
|
||||
// Balance reached and inferior to subsistence threshold
|
||||
with_externalities(
|
||||
&mut ExtBuilder::default().existential_deposit(50).build(),
|
||||
|| {
|
||||
// Create
|
||||
Balances::deposit_creating(&ALICE, 1_000_000);
|
||||
assert_ok!(Contract::put_code(Origin::signed(ALICE), 100_000, wasm.clone()));
|
||||
assert_ok!(Contract::create(
|
||||
Origin::signed(ALICE),
|
||||
50+Balances::minimum_balance(),
|
||||
100_000, HASH_SET_RENT.into(),
|
||||
<Test as balances::Trait>::Balance::sa(1_000u64).encode() // rent allowance
|
||||
));
|
||||
|
||||
// Trigger rent must have no effect
|
||||
assert!(trigger_call());
|
||||
assert_eq!(super::ContractInfoOf::<Test>::get(BOB).unwrap().get_alive().unwrap().rent_allowance, 1_000);
|
||||
|
||||
// Transfer funds
|
||||
assert_ok!(Contract::call(Origin::signed(ALICE), BOB, 0, 100_000, call::transfer()));
|
||||
assert_eq!(super::ContractInfoOf::<Test>::get(BOB).unwrap().get_alive().unwrap().rent_allowance, 1_000);
|
||||
|
||||
// Advance blocks
|
||||
System::initialize(&10, &[0u8; 32].into(), &[0u8; 32].into());
|
||||
|
||||
// Trigger rent through call
|
||||
assert!(trigger_call());
|
||||
assert!(super::ContractInfoOf::<Test>::get(BOB).is_none());
|
||||
|
||||
// Advance blocks
|
||||
System::initialize(&20, &[0u8; 32].into(), &[0u8; 32].into());
|
||||
|
||||
// Trigger rent must have no effect
|
||||
assert!(trigger_call());
|
||||
assert!(super::ContractInfoOf::<Test>::get(BOB).is_none());
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user