Files
pezkuwi-subxt/substrate/bin/node/executor/tests/basic.rs
T
Alexander Theißen c3ca78fae3 contracts: Add salt argument to contract instantiation (#7482)
* pallet-contracts: Fix seal_restore_to to output proper module errors

Those errors where part of the decl_error for some time but where
never actually returned. This allows proper debugging of failed
restorations. Previously, any error did return the misleading
`ContractTrapped`.

* Bind UncheckedFrom<T::Hash> + AsRef<[u8]> everywhere

This allows us to make assumptions about the AccoutId
that are necessary for testing and in order to benchmark
the module properly.

This also groups free standing functions into inherent functions
in order to minimize the places where the new bounds need to
be specified.

* Rework contract address determination

* Do not allow override by runtime author
* Instantiate gained a new parameter "salt"

This change is done now in expecation of the upcoming code rent
which needs to change the instantiation dispatchable and
host function anyways.

The situation in where we have only something that is like CREATE2
makes it impossible for UIs to help the user to create an arbitrary
amount of instantiations from the same code.

With this change we have the same functionality as ethereum with
a CREATE and CREATE2 instantation semantic.

* Remove TrieIdGenerator

The new trait bounds allows us to remove this workaround
from the configuration trait.

* Remove default parameters for config trait

It should be solely the responsiblity to determine proper values for
these parameter. As a matter of fact most runtime weren't using these
values anyways.

* Fix tests for new account id type

Because of the new bounds on the trait tests can't get away by using
u64 as accound id. Replacing the 8 byte value by a 32 byte value
creates out quite a bit of code churn.

* Fix benchmarks

The benchmarks need adaption to the new instantiate semantics.

* Fix compile errors caused by adding new trait bounds
* Fix compile errors caused by renaming storage and rent functions
* Adapt host functions and dispatchables to the new salt
* Add tests for instantiate host functions (was not possible before)

* Add benchmark results

* Adapt to the new WeightInfo

The new benchmarks add a new parameter for salt "s" to the instantiate weights
that needs to be applied.

* Fix deploying_wasm_contract_should_work integration test

This test is adapted to use the new instantiate signature.

* Break overlong line

* Break more long lines

Co-authored-by: Parity Benchmarking Bot <admin@parity.io>
2020-11-24 10:42:20 +00:00

826 lines
22 KiB
Rust

// This file is part of Substrate.
// Copyright (C) 2018-2020 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use codec::{Encode, Decode, Joiner};
use frame_support::{
StorageValue, StorageMap,
traits::Currency,
weights::{GetDispatchInfo, DispatchInfo, DispatchClass},
};
use sp_core::{NeverNativeValue, traits::Externalities, storage::well_known_keys};
use sp_runtime::{
ApplyExtrinsicResult,
traits::Hash as HashT,
transaction_validity::InvalidTransaction,
};
use frame_system::{self, EventRecord, Phase};
use node_runtime::{
Header, Block, UncheckedExtrinsic, CheckedExtrinsic, Call, Runtime, Balances,
System, TransactionPayment, Event,
constants::currency::*,
};
use node_primitives::{Balance, Hash};
use wat;
use node_testing::keyring::*;
pub mod common;
use self::common::{*, sign};
/// The wasm runtime binary which hasn't undergone the compacting process.
///
/// The idea here is to pass it as the current runtime code to the executor so the executor will
/// have to execute provided wasm code instead of the native equivalent. This trick is used to
/// test code paths that differ between native and wasm versions.
pub fn bloaty_code_unwrap() -> &'static [u8] {
node_runtime::WASM_BINARY_BLOATY.expect("Development wasm binary is not available. \
Testing is only supported with the flag disabled.")
}
/// Default transfer fee. This will use the same logic that is implemented in transaction-payment module.
///
/// Note that reads the multiplier from storage directly, hence to get the fee of `extrinsic`
/// at block `n`, it must be called prior to executing block `n` to do the calculation with the
/// correct multiplier.
fn transfer_fee<E: Encode>(extrinsic: &E) -> Balance {
TransactionPayment::compute_fee(
extrinsic.encode().len() as u32,
&default_transfer_call().get_dispatch_info(),
0,
)
}
fn xt() -> UncheckedExtrinsic {
sign(CheckedExtrinsic {
signed: Some((alice(), signed_extra(0, 0))),
function: Call::Balances(default_transfer_call()),
})
}
fn set_heap_pages<E: Externalities>(ext: &mut E, heap_pages: u64) {
ext.place_storage(well_known_keys::HEAP_PAGES.to_vec(), Some(heap_pages.encode()));
}
fn changes_trie_block() -> (Vec<u8>, Hash) {
construct_block(
&mut new_test_ext(compact_code_unwrap(), true),
1,
GENESIS_HASH.into(),
vec![
CheckedExtrinsic {
signed: None,
function: Call::Timestamp(pallet_timestamp::Call::set(42 * 1000)),
},
CheckedExtrinsic {
signed: Some((alice(), signed_extra(0, 0))),
function: Call::Balances(pallet_balances::Call::transfer(bob().into(), 69 * DOLLARS)),
},
]
)
}
/// block 1 and 2 must be created together to ensure transactions are only signed once (since they
/// are not guaranteed to be deterministic) and to ensure that the correct state is propagated
/// from block1's execution to block2 to derive the correct storage_root.
fn blocks() -> ((Vec<u8>, Hash), (Vec<u8>, Hash)) {
let mut t = new_test_ext(compact_code_unwrap(), false);
let block1 = construct_block(
&mut t,
1,
GENESIS_HASH.into(),
vec![
CheckedExtrinsic {
signed: None,
function: Call::Timestamp(pallet_timestamp::Call::set(42 * 1000)),
},
CheckedExtrinsic {
signed: Some((alice(), signed_extra(0, 0))),
function: Call::Balances(pallet_balances::Call::transfer(bob().into(), 69 * DOLLARS)),
},
]
);
let block2 = construct_block(
&mut t,
2,
block1.1.clone(),
vec![
CheckedExtrinsic {
signed: None,
function: Call::Timestamp(pallet_timestamp::Call::set(52 * 1000)),
},
CheckedExtrinsic {
signed: Some((bob(), signed_extra(0, 0))),
function: Call::Balances(pallet_balances::Call::transfer(alice().into(), 5 * DOLLARS)),
},
CheckedExtrinsic {
signed: Some((alice(), signed_extra(1, 0))),
function: Call::Balances(pallet_balances::Call::transfer(bob().into(), 15 * DOLLARS)),
}
]
);
// session change => consensus authorities change => authorities change digest item appears
let digest = Header::decode(&mut &block2.0[..]).unwrap().digest;
assert_eq!(digest.logs().len(), 0);
(block1, block2)
}
fn block_with_size(time: u64, nonce: u32, size: usize) -> (Vec<u8>, Hash) {
construct_block(
&mut new_test_ext(compact_code_unwrap(), false),
1,
GENESIS_HASH.into(),
vec![
CheckedExtrinsic {
signed: None,
function: Call::Timestamp(pallet_timestamp::Call::set(time * 1000)),
},
CheckedExtrinsic {
signed: Some((alice(), signed_extra(nonce, 0))),
function: Call::System(frame_system::Call::remark(vec![0; size])),
}
]
)
}
#[test]
fn panic_execution_with_foreign_code_gives_error() {
let mut t = new_test_ext(bloaty_code_unwrap(), false);
t.insert(
<frame_system::Account<Runtime>>::hashed_key_for(alice()),
(69u128, 0u32, 0u128, 0u128, 0u128).encode()
);
t.insert(<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(), 69_u128.encode());
t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
let r = executor_call::<NeverNativeValue, fn() -> _>(
&mut t,
"Core_initialize_block",
&vec![].and(&from_block_number(1u32)),
true,
None,
).0;
assert!(r.is_ok());
let v = executor_call::<NeverNativeValue, fn() -> _>(
&mut t,
"BlockBuilder_apply_extrinsic",
&vec![].and(&xt()),
true,
None,
).0.unwrap();
let r = ApplyExtrinsicResult::decode(&mut &v.as_encoded()[..]).unwrap();
assert_eq!(r, Err(InvalidTransaction::Payment.into()));
}
#[test]
fn bad_extrinsic_with_native_equivalent_code_gives_error() {
let mut t = new_test_ext(compact_code_unwrap(), false);
t.insert(
<frame_system::Account<Runtime>>::hashed_key_for(alice()),
(0u32, 0u32, 69u128, 0u128, 0u128, 0u128).encode()
);
t.insert(<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(), 69_u128.encode());
t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
let r = executor_call::<NeverNativeValue, fn() -> _>(
&mut t,
"Core_initialize_block",
&vec![].and(&from_block_number(1u32)),
true,
None,
).0;
assert!(r.is_ok());
let v = executor_call::<NeverNativeValue, fn() -> _>(
&mut t,
"BlockBuilder_apply_extrinsic",
&vec![].and(&xt()),
true,
None,
).0.unwrap();
let r = ApplyExtrinsicResult::decode(&mut &v.as_encoded()[..]).unwrap();
assert_eq!(r, Err(InvalidTransaction::Payment.into()));
}
#[test]
fn successful_execution_with_native_equivalent_code_gives_ok() {
let mut t = new_test_ext(compact_code_unwrap(), false);
t.insert(
<frame_system::Account<Runtime>>::hashed_key_for(alice()),
(0u32, 0u32, 111 * DOLLARS, 0u128, 0u128, 0u128).encode()
);
t.insert(
<frame_system::Account<Runtime>>::hashed_key_for(bob()),
(0u32, 0u32, 0 * DOLLARS, 0u128, 0u128, 0u128).encode()
);
t.insert(
<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(),
(111 * DOLLARS).encode()
);
t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
let r = executor_call::<NeverNativeValue, fn() -> _>(
&mut t,
"Core_initialize_block",
&vec![].and(&from_block_number(1u32)),
true,
None,
).0;
assert!(r.is_ok());
let fees = t.execute_with(|| transfer_fee(&xt()));
let r = executor_call::<NeverNativeValue, fn() -> _>(
&mut t,
"BlockBuilder_apply_extrinsic",
&vec![].and(&xt()),
true,
None,
).0;
assert!(r.is_ok());
t.execute_with(|| {
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees);
assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS);
});
}
#[test]
fn successful_execution_with_foreign_code_gives_ok() {
let mut t = new_test_ext(bloaty_code_unwrap(), false);
t.insert(
<frame_system::Account<Runtime>>::hashed_key_for(alice()),
(0u32, 0u32, 111 * DOLLARS, 0u128, 0u128, 0u128).encode()
);
t.insert(
<frame_system::Account<Runtime>>::hashed_key_for(bob()),
(0u32, 0u32, 0 * DOLLARS, 0u128, 0u128, 0u128).encode()
);
t.insert(
<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(),
(111 * DOLLARS).encode()
);
t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
let r = executor_call::<NeverNativeValue, fn() -> _>(
&mut t,
"Core_initialize_block",
&vec![].and(&from_block_number(1u32)),
true,
None,
).0;
assert!(r.is_ok());
let fees = t.execute_with(|| transfer_fee(&xt()));
let r = executor_call::<NeverNativeValue, fn() -> _>(
&mut t,
"BlockBuilder_apply_extrinsic",
&vec![].and(&xt()),
true,
None,
).0;
assert!(r.is_ok());
t.execute_with(|| {
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees);
assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS);
});
}
#[test]
fn full_native_block_import_works() {
let mut t = new_test_ext(compact_code_unwrap(), false);
let (block1, block2) = blocks();
let mut alice_last_known_balance: Balance = Default::default();
let mut fees = t.execute_with(|| transfer_fee(&xt()));
let transfer_weight = default_transfer_call().get_dispatch_info().weight;
let timestamp_weight = pallet_timestamp::Call::set::<Runtime>(Default::default()).get_dispatch_info().weight;
executor_call::<NeverNativeValue, fn() -> _>(
&mut t,
"Core_execute_block",
&block1.0,
true,
None,
).0.unwrap();
t.execute_with(|| {
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees);
assert_eq!(Balances::total_balance(&bob()), 169 * DOLLARS);
alice_last_known_balance = Balances::total_balance(&alice());
let events = vec![
EventRecord {
phase: Phase::ApplyExtrinsic(0),
event: Event::frame_system(frame_system::RawEvent::ExtrinsicSuccess(
DispatchInfo { weight: timestamp_weight, class: DispatchClass::Mandatory, ..Default::default() }
)),
topics: vec![],
},
EventRecord {
phase: Phase::ApplyExtrinsic(1),
event: Event::pallet_balances(pallet_balances::RawEvent::Transfer(
alice().into(),
bob().into(),
69 * DOLLARS,
)),
topics: vec![],
},
EventRecord {
phase: Phase::ApplyExtrinsic(1),
event: Event::pallet_treasury(pallet_treasury::RawEvent::Deposit(fees * 8 / 10)),
topics: vec![],
},
EventRecord {
phase: Phase::ApplyExtrinsic(1),
event: Event::frame_system(frame_system::RawEvent::ExtrinsicSuccess(
DispatchInfo { weight: transfer_weight, ..Default::default() }
)),
topics: vec![],
},
];
assert_eq!(System::events(), events);
});
fees = t.execute_with(|| transfer_fee(&xt()));
executor_call::<NeverNativeValue, fn() -> _>(
&mut t,
"Core_execute_block",
&block2.0,
true,
None,
).0.unwrap();
t.execute_with(|| {
assert_eq!(
Balances::total_balance(&alice()),
alice_last_known_balance - 10 * DOLLARS - fees,
);
assert_eq!(
Balances::total_balance(&bob()),
179 * DOLLARS - fees,
);
let events = vec![
EventRecord {
phase: Phase::ApplyExtrinsic(0),
event: Event::frame_system(frame_system::RawEvent::ExtrinsicSuccess(
DispatchInfo { weight: timestamp_weight, class: DispatchClass::Mandatory, ..Default::default() }
)),
topics: vec![],
},
EventRecord {
phase: Phase::ApplyExtrinsic(1),
event: Event::pallet_balances(
pallet_balances::RawEvent::Transfer(
bob().into(),
alice().into(),
5 * DOLLARS,
)
),
topics: vec![],
},
EventRecord {
phase: Phase::ApplyExtrinsic(1),
event: Event::pallet_treasury(pallet_treasury::RawEvent::Deposit(fees * 8 / 10)),
topics: vec![],
},
EventRecord {
phase: Phase::ApplyExtrinsic(1),
event: Event::frame_system(frame_system::RawEvent::ExtrinsicSuccess(
DispatchInfo { weight: transfer_weight, ..Default::default() }
)),
topics: vec![],
},
EventRecord {
phase: Phase::ApplyExtrinsic(2),
event: Event::pallet_balances(
pallet_balances::RawEvent::Transfer(
alice().into(),
bob().into(),
15 * DOLLARS,
)
),
topics: vec![],
},
EventRecord {
phase: Phase::ApplyExtrinsic(2),
event: Event::pallet_treasury(pallet_treasury::RawEvent::Deposit(fees * 8 / 10)),
topics: vec![],
},
EventRecord {
phase: Phase::ApplyExtrinsic(2),
event: Event::frame_system(frame_system::RawEvent::ExtrinsicSuccess(
DispatchInfo { weight: transfer_weight, ..Default::default() }
)),
topics: vec![],
},
];
assert_eq!(System::events(), events);
});
}
#[test]
fn full_wasm_block_import_works() {
let mut t = new_test_ext(compact_code_unwrap(), false);
let (block1, block2) = blocks();
let mut alice_last_known_balance: Balance = Default::default();
let mut fees = t.execute_with(|| transfer_fee(&xt()));
executor_call::<NeverNativeValue, fn() -> _>(
&mut t,
"Core_execute_block",
&block1.0,
false,
None,
).0.unwrap();
t.execute_with(|| {
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees);
assert_eq!(Balances::total_balance(&bob()), 169 * DOLLARS);
alice_last_known_balance = Balances::total_balance(&alice());
});
fees = t.execute_with(|| transfer_fee(&xt()));
executor_call::<NeverNativeValue, fn() -> _>(
&mut t,
"Core_execute_block",
&block2.0,
false,
None,
).0.unwrap();
t.execute_with(|| {
assert_eq!(
Balances::total_balance(&alice()),
alice_last_known_balance - 10 * DOLLARS - fees,
);
assert_eq!(
Balances::total_balance(&bob()),
179 * DOLLARS - 1 * fees,
);
});
}
const CODE_TRANSFER: &str = r#"
(module
;; seal_call(
;; callee_ptr: u32,
;; callee_len: u32,
;; gas: u64,
;; value_ptr: u32,
;; value_len: u32,
;; input_data_ptr: u32,
;; input_data_len: u32,
;; output_ptr: u32,
;; output_len_ptr: u32
;; ) -> u32
(import "seal0" "seal_call" (func $seal_call (param i32 i32 i64 i32 i32 i32 i32 i32 i32) (result i32)))
(import "seal0" "seal_input" (func $seal_input (param i32 i32)))
(import "env" "memory" (memory 1 1))
(func (export "deploy")
)
(func (export "call")
(block $fail
;; Load input data to contract memory
(call $seal_input
(i32.const 0)
(i32.const 52)
)
;; fail if the input size is not != 4
(br_if $fail
(i32.ne
(i32.const 4)
(i32.load (i32.const 52))
)
)
(br_if $fail
(i32.ne
(i32.load8_u (i32.const 0))
(i32.const 0)
)
)
(br_if $fail
(i32.ne
(i32.load8_u (i32.const 1))
(i32.const 1)
)
)
(br_if $fail
(i32.ne
(i32.load8_u (i32.const 2))
(i32.const 2)
)
)
(br_if $fail
(i32.ne
(i32.load8_u (i32.const 3))
(i32.const 3)
)
)
(drop
(call $seal_call
(i32.const 4) ;; Pointer to "callee" address.
(i32.const 32) ;; Length of "callee" address.
(i64.const 0) ;; How much gas to devote for the execution. 0 = all.
(i32.const 36) ;; Pointer to the buffer with value to transfer
(i32.const 16) ;; Length of the buffer with value to transfer.
(i32.const 0) ;; Pointer to input data buffer address
(i32.const 0) ;; Length of input data buffer
(i32.const 4294967295) ;; u32 max value is the sentinel value: do not copy output
(i32.const 0) ;; Length is ignored in this case
)
)
(return)
)
unreachable
)
;; Destination AccountId to transfer the funds.
;; Represented by H256 (32 bytes long) in little endian.
(data (i32.const 4)
"\09\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00"
"\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00"
"\00\00\00\00"
)
;; Amount of value to transfer.
;; Represented by u128 (16 bytes long) in little endian.
(data (i32.const 36)
"\06\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00"
"\00\00"
)
;; Length of the input buffer
(data (i32.const 52) "\04")
)
"#;
#[test]
fn deploying_wasm_contract_should_work() {
let transfer_code = wat::parse_str(CODE_TRANSFER).unwrap();
let transfer_ch = <Runtime as frame_system::Trait>::Hashing::hash(&transfer_code);
let addr = pallet_contracts::Module::<Runtime>::contract_address(
&charlie(),
&transfer_ch,
&[],
);
let subsistence = pallet_contracts::Config::<Runtime>::subsistence_threshold_uncached();
let b = construct_block(
&mut new_test_ext(compact_code_unwrap(), false),
1,
GENESIS_HASH.into(),
vec![
CheckedExtrinsic {
signed: None,
function: Call::Timestamp(pallet_timestamp::Call::set(42 * 1000)),
},
CheckedExtrinsic {
signed: Some((charlie(), signed_extra(0, 0))),
function: Call::Contracts(
pallet_contracts::Call::put_code::<Runtime>(transfer_code)
),
},
CheckedExtrinsic {
signed: Some((charlie(), signed_extra(1, 0))),
function: Call::Contracts(
pallet_contracts::Call::instantiate::<Runtime>(
1 * DOLLARS + subsistence,
500_000_000,
transfer_ch,
Vec::new(),
Vec::new(),
)
),
},
CheckedExtrinsic {
signed: Some((charlie(), signed_extra(2, 0))),
function: Call::Contracts(
pallet_contracts::Call::call::<Runtime>(
sp_runtime::MultiAddress::Id(addr.clone()),
10,
500_000_000,
vec![0x00, 0x01, 0x02, 0x03]
)
),
},
]
);
let mut t = new_test_ext(compact_code_unwrap(), false);
executor_call::<NeverNativeValue, fn() -> _>(
&mut t,
"Core_execute_block",
&b.0,
false,
None,
).0.unwrap();
t.execute_with(|| {
// Verify that the contract constructor worked well and code of TRANSFER contract is actually deployed.
assert_eq!(
&pallet_contracts::ContractInfoOf::<Runtime>::get(addr)
.and_then(|c| c.get_alive())
.unwrap()
.code_hash,
&transfer_ch
);
});
}
#[test]
fn wasm_big_block_import_fails() {
let mut t = new_test_ext(compact_code_unwrap(), false);
set_heap_pages(&mut t.ext(), 4);
let result = executor_call::<NeverNativeValue, fn() -> _>(
&mut t,
"Core_execute_block",
&block_with_size(42, 0, 120_000).0,
false,
None,
).0;
assert!(result.is_err()); // Err(Wasmi(Trap(Trap { kind: Host(AllocatorOutOfSpace) })))
}
#[test]
fn native_big_block_import_succeeds() {
let mut t = new_test_ext(compact_code_unwrap(), false);
executor_call::<NeverNativeValue, fn() -> _>(
&mut t,
"Core_execute_block",
&block_with_size(42, 0, 120_000).0,
true,
None,
).0.unwrap();
}
#[test]
fn native_big_block_import_fails_on_fallback() {
let mut t = new_test_ext(compact_code_unwrap(), false);
assert!(
executor_call::<NeverNativeValue, fn() -> _>(
&mut t,
"Core_execute_block",
&block_with_size(42, 0, 120_000).0,
false,
None,
).0.is_err()
);
}
#[test]
fn panic_execution_gives_error() {
let mut t = new_test_ext(bloaty_code_unwrap(), false);
t.insert(
<frame_system::Account<Runtime>>::hashed_key_for(alice()),
(0u32, 0u32, 0 * DOLLARS, 0u128, 0u128, 0u128).encode()
);
t.insert(<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(), 0_u128.encode());
t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
let r = executor_call::<NeverNativeValue, fn() -> _>(
&mut t,
"Core_initialize_block",
&vec![].and(&from_block_number(1u32)),
false,
None,
).0;
assert!(r.is_ok());
let r = executor_call::<NeverNativeValue, fn() -> _>(
&mut t,
"BlockBuilder_apply_extrinsic",
&vec![].and(&xt()),
false,
None,
).0.unwrap().into_encoded();
let r = ApplyExtrinsicResult::decode(&mut &r[..]).unwrap();
assert_eq!(r, Err(InvalidTransaction::Payment.into()));
}
#[test]
fn successful_execution_gives_ok() {
let mut t = new_test_ext(compact_code_unwrap(), false);
t.insert(
<frame_system::Account<Runtime>>::hashed_key_for(alice()),
(0u32, 0u32, 111 * DOLLARS, 0u128, 0u128, 0u128).encode()
);
t.insert(
<frame_system::Account<Runtime>>::hashed_key_for(bob()),
(0u32, 0u32, 0 * DOLLARS, 0u128, 0u128, 0u128).encode()
);
t.insert(
<pallet_balances::TotalIssuance<Runtime>>::hashed_key().to_vec(),
(111 * DOLLARS).encode()
);
t.insert(<frame_system::BlockHash<Runtime>>::hashed_key_for(0), vec![0u8; 32]);
let r = executor_call::<NeverNativeValue, fn() -> _>(
&mut t,
"Core_initialize_block",
&vec![].and(&from_block_number(1u32)),
false,
None,
).0;
assert!(r.is_ok());
t.execute_with(|| {
assert_eq!(Balances::total_balance(&alice()), 111 * DOLLARS);
});
let fees = t.execute_with(|| transfer_fee(&xt()));
let r = executor_call::<NeverNativeValue, fn() -> _>(
&mut t,
"BlockBuilder_apply_extrinsic",
&vec![].and(&xt()),
false,
None,
).0.unwrap().into_encoded();
ApplyExtrinsicResult::decode(&mut &r[..])
.unwrap()
.expect("Extrinsic could not be applied")
.expect("Extrinsic failed");
t.execute_with(|| {
assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees);
assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS);
});
}
#[test]
fn full_native_block_import_works_with_changes_trie() {
let block1 = changes_trie_block();
let block_data = block1.0;
let block = Block::decode(&mut &block_data[..]).unwrap();
let mut t = new_test_ext(compact_code_unwrap(), true);
executor_call::<NeverNativeValue, fn() -> _>(
&mut t,
"Core_execute_block",
&block.encode(),
true,
None,
).0.unwrap();
assert!(t.ext().storage_changes_root(&GENESIS_HASH).unwrap().is_some());
}
#[test]
fn full_wasm_block_import_works_with_changes_trie() {
let block1 = changes_trie_block();
let mut t = new_test_ext(compact_code_unwrap(), true);
executor_call::<NeverNativeValue, fn() -> _>(
&mut t,
"Core_execute_block",
&block1.0,
false,
None,
).0.unwrap();
assert!(t.ext().storage_changes_root(&GENESIS_HASH).unwrap().is_some());
}
#[test]
fn should_import_block_with_test_client() {
use node_testing::client::{
ClientBlockImportExt, TestClientBuilderExt, TestClientBuilder,
sp_consensus::BlockOrigin,
};
let mut client = TestClientBuilder::new().build();
let block1 = changes_trie_block();
let block_data = block1.0;
let block = node_primitives::Block::decode(&mut &block_data[..]).unwrap();
client.import(BlockOrigin::Own, block).unwrap();
}