diff --git a/substrate/bin/node/executor/tests/basic.rs b/substrate/bin/node/executor/tests/basic.rs index 79160ebb9e..f6dc1c3e7e 100644 --- a/substrate/bin/node/executor/tests/basic.rs +++ b/substrate/bin/node/executor/tests/basic.rs @@ -591,6 +591,8 @@ fn deploying_wasm_contract_should_work() { &charlie(), ); + let subsistence = pallet_contracts::Config::::subsistence_threshold_uncached(); + let b = construct_block( &mut new_test_ext(compact_code_unwrap(), false), 1, @@ -610,7 +612,7 @@ fn deploying_wasm_contract_should_work() { signed: Some((charlie(), signed_extra(1, 0))), function: Call::Contracts( pallet_contracts::Call::instantiate::( - 1 * DOLLARS, + 1 * DOLLARS + subsistence, 500_000_000, transfer_ch, Vec::new() diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index f514e1819f..ad748c4574 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -105,7 +105,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to 0. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 256, + spec_version: 257, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, diff --git a/substrate/frame/contracts/src/exec.rs b/substrate/frame/contracts/src/exec.rs index f6327f7f2d..e8965692aa 100644 --- a/substrate/frame/contracts/src/exec.rs +++ b/substrate/frame/contracts/src/exec.rs @@ -426,7 +426,10 @@ where )?; // Error out if insufficient remaining balance. - if T::Currency::free_balance(&dest) < nested.config.existential_deposit { + // We need each contract that exists to be above the subsistence threshold + // in order to keep up the guarantuee that we always leave a tombstone behind + // with the exception of a contract that called `ext_terminate`. + if T::Currency::free_balance(&dest) < nested.config.subsistence_threshold() { Err("insufficient remaining balance")? } @@ -1016,7 +1019,7 @@ mod tests { let mut gas_meter = GasMeter::::new(GAS_LIMIT); - let result = ctx.instantiate(1, &mut gas_meter, &code, vec![]); + let result = ctx.instantiate(cfg.subsistence_threshold(), &mut gas_meter, &code, vec![]); assert_matches!(result, Ok(_)); let mut toks = gas_meter.tokens().iter(); @@ -1306,7 +1309,7 @@ mod tests { set_balance(&ALICE, 100); let result = ctx.instantiate( - 1, + cfg.subsistence_threshold(), &mut GasMeter::::new(GAS_LIMIT), &input_data_ch, vec![1, 2, 3, 4], @@ -1549,7 +1552,7 @@ mod tests { // Instantiate a contract and save it's address in `instantiated_contract_address`. let (address, output) = ctx.ext.instantiate( &dummy_ch, - 15u64, + Config::::subsistence_threshold_uncached(), ctx.gas_meter, vec![] ).unwrap(); @@ -1679,7 +1682,7 @@ mod tests { set_balance(&ALICE, 100); let result = ctx.instantiate( - 1, + cfg.subsistence_threshold(), &mut GasMeter::::new(GAS_LIMIT), &rent_allowance_ch, vec![], diff --git a/substrate/frame/contracts/src/lib.rs b/substrate/frame/contracts/src/lib.rs index 4b3a48119f..003853102d 100644 --- a/substrate/frame/contracts/src/lib.rs +++ b/substrate/frame/contracts/src/lib.rs @@ -743,7 +743,7 @@ impl Config { /// than the subsistence threshold in order to guarantee that a tombstone is created. /// /// The only way to completely kill a contract without a tombstone is calling `ext_terminate`. - fn subsistence_threshold(&self) -> BalanceOf { + pub fn subsistence_threshold(&self) -> BalanceOf { self.existential_deposit.saturating_add(self.tombstone_deposit) } @@ -751,7 +751,7 @@ impl Config { /// /// This is for cases where this value is needed in rent calculation rather than /// during contract execution. - fn subsistence_threshold_uncached() -> BalanceOf { + pub fn subsistence_threshold_uncached() -> BalanceOf { T::Currency::minimum_balance().saturating_add(T::TombstoneDeposit::get()) } } diff --git a/substrate/frame/contracts/src/tests.rs b/substrate/frame/contracts/src/tests.rs index 9051a81cc8..0d2a2f7a31 100644 --- a/substrate/frame/contracts/src/tests.rs +++ b/substrate/frame/contracts/src/tests.rs @@ -385,13 +385,14 @@ fn instantiate_and_call_and_deposit_event() { .build() .execute_with(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); + let subsistence = super::Config::::subsistence_threshold_uncached(); assert_ok!(Contracts::put_code(Origin::signed(ALICE), wasm)); // Check at the end to get hash on error easily let creation = Contracts::instantiate( Origin::signed(ALICE), - 100, + subsistence, GAS_LIMIT, code_hash.into(), vec![], @@ -421,14 +422,14 @@ fn instantiate_and_call_and_deposit_event() { EventRecord { phase: Phase::Initialization, event: MetaEvent::balances( - pallet_balances::RawEvent::Endowed(BOB, 100) + pallet_balances::RawEvent::Endowed(BOB, subsistence) ), topics: vec![], }, EventRecord { phase: Phase::Initialization, event: MetaEvent::balances( - pallet_balances::RawEvent::Transfer(ALICE, BOB, 100) + pallet_balances::RawEvent::Transfer(ALICE, BOB, subsistence) ), topics: vec![], }, diff --git a/substrate/frame/contracts/src/wasm/runtime.rs b/substrate/frame/contracts/src/wasm/runtime.rs index a221e3c7cf..0f07f2f427 100644 --- a/substrate/frame/contracts/src/wasm/runtime.rs +++ b/substrate/frame/contracts/src/wasm/runtime.rs @@ -617,10 +617,12 @@ define_env!(Env, , // This function creates an account and executes the constructor defined in the code specified // by the code hash. The address of this new account is copied to `address_ptr` and its length // to `address_len_ptr`. The constructors output buffer is copied to `output_ptr` and its - // length to `output_len_ptr`. + // length to `output_len_ptr`. The copy of the output buffer and address can be skipped by + // supplying the sentinel value of `u32::max_value()` to `output_ptr` or `address_ptr`. // - // The copy of the output buffer and address can be skipped by supplying the sentinel value - // of `u32::max_value()` to `output_ptr` or `address_ptr`. + // After running the constructor it is verfied that the contract account holds at + // least the subsistence threshold. If that is not the case the instantion fails and + // the contract is not created. // // # Parameters //