mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-01 12:27:56 +00:00
contracts: Allow indeterministic instructions off-chain (#12469)
* Allow indetermistic instructions off-chain * Apply suggestions from code review Co-authored-by: Sasha Gryaznov <hi@agryaznov.com> * fmt Co-authored-by: Sasha Gryaznov <hi@agryaznov.com>
This commit is contained in:
committed by
GitHub
parent
d0dcf008ec
commit
3ae4be8662
@@ -24,7 +24,7 @@ use crate::{
|
||||
exec::{FixSizedKey, Frame},
|
||||
storage::Storage,
|
||||
tests::test_utils::{get_contract, get_contract_checked},
|
||||
wasm::{PrefabWasmModule, ReturnCode as RuntimeReturnCode},
|
||||
wasm::{Determinism, PrefabWasmModule, ReturnCode as RuntimeReturnCode},
|
||||
weights::WeightInfo,
|
||||
BalanceOf, Code, CodeStorage, Config, ContractInfoOf, DefaultAddressGenerator, DeletionQueue,
|
||||
Error, Pallet, Schedule,
|
||||
@@ -340,6 +340,7 @@ parameter_types! {
|
||||
// We want stack height to be always enabled for tests so that this
|
||||
// instrumentation path is always tested implicitly.
|
||||
schedule.limits.stack_height = Some(512);
|
||||
schedule.instruction_weights.fallback = 1;
|
||||
schedule
|
||||
};
|
||||
pub static DepositPerByte: BalanceOf<Test> = 1;
|
||||
@@ -522,7 +523,12 @@ fn instantiate_and_call_and_deposit_event() {
|
||||
|
||||
// We determine the storage deposit limit after uploading because it depends on ALICEs free
|
||||
// balance which is changed by uploading a module.
|
||||
assert_ok!(Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm, None));
|
||||
assert_ok!(Contracts::upload_code(
|
||||
RuntimeOrigin::signed(ALICE),
|
||||
wasm,
|
||||
None,
|
||||
Determinism::Deterministic
|
||||
));
|
||||
|
||||
// Drop previous events
|
||||
initialize_block(2);
|
||||
@@ -690,7 +696,13 @@ fn instantiate_unique_trie_id() {
|
||||
|
||||
ExtBuilder::default().existential_deposit(500).build().execute_with(|| {
|
||||
let _ = Balances::deposit_creating(&ALICE, 1_000_000);
|
||||
Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm, None).unwrap();
|
||||
Contracts::upload_code(
|
||||
RuntimeOrigin::signed(ALICE),
|
||||
wasm,
|
||||
None,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.unwrap();
|
||||
let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);
|
||||
|
||||
// Instantiate the contract and store its trie id for later comparison.
|
||||
@@ -940,6 +952,7 @@ fn delegate_call() {
|
||||
RuntimeOrigin::signed(ALICE),
|
||||
callee_wasm,
|
||||
Some(codec::Compact(100_000)),
|
||||
Determinism::Deterministic,
|
||||
));
|
||||
|
||||
assert_ok!(Contracts::call(
|
||||
@@ -1376,10 +1389,18 @@ fn crypto_hashes() {
|
||||
// We offset data in the contract tables by 1.
|
||||
let mut params = vec![(n + 1) as u8];
|
||||
params.extend_from_slice(input);
|
||||
let result =
|
||||
<Pallet<Test>>::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, params, false)
|
||||
.result
|
||||
.unwrap();
|
||||
let result = <Pallet<Test>>::bare_call(
|
||||
ALICE,
|
||||
addr.clone(),
|
||||
0,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
params,
|
||||
false,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.result
|
||||
.unwrap();
|
||||
assert!(!result.did_revert());
|
||||
let expected = hash_fn(input.as_ref());
|
||||
assert_eq!(&result.data[..*expected_size], &*expected);
|
||||
@@ -1407,9 +1428,18 @@ fn transfer_return_code() {
|
||||
|
||||
// Contract has only the minimal balance so any transfer will fail.
|
||||
Balances::make_free_balance_be(&addr, min_balance);
|
||||
let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, vec![], false)
|
||||
.result
|
||||
.unwrap();
|
||||
let result = Contracts::bare_call(
|
||||
ALICE,
|
||||
addr.clone(),
|
||||
0,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
vec![],
|
||||
false,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.result
|
||||
.unwrap();
|
||||
assert_return_code!(result, RuntimeReturnCode::TransferFailed);
|
||||
|
||||
// Contract has enough total balance in order to not go below the min balance
|
||||
@@ -1417,9 +1447,18 @@ fn transfer_return_code() {
|
||||
// the transfer still fails.
|
||||
Balances::make_free_balance_be(&addr, min_balance + 100);
|
||||
Balances::reserve(&addr, min_balance + 100).unwrap();
|
||||
let result = Contracts::bare_call(ALICE, addr, 0, GAS_LIMIT, None, vec![], false)
|
||||
.result
|
||||
.unwrap();
|
||||
let result = Contracts::bare_call(
|
||||
ALICE,
|
||||
addr,
|
||||
0,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
vec![],
|
||||
false,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.result
|
||||
.unwrap();
|
||||
assert_return_code!(result, RuntimeReturnCode::TransferFailed);
|
||||
});
|
||||
}
|
||||
@@ -1454,6 +1493,7 @@ fn call_return_code() {
|
||||
None,
|
||||
AsRef::<[u8]>::as_ref(&DJANGO).to_vec(),
|
||||
false,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.result
|
||||
.unwrap();
|
||||
@@ -1484,6 +1524,7 @@ fn call_return_code() {
|
||||
.cloned()
|
||||
.collect(),
|
||||
false,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.result
|
||||
.unwrap();
|
||||
@@ -1506,6 +1547,7 @@ fn call_return_code() {
|
||||
.cloned()
|
||||
.collect(),
|
||||
false,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.result
|
||||
.unwrap();
|
||||
@@ -1525,6 +1567,7 @@ fn call_return_code() {
|
||||
.cloned()
|
||||
.collect(),
|
||||
false,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.result
|
||||
.unwrap();
|
||||
@@ -1543,6 +1586,7 @@ fn call_return_code() {
|
||||
.cloned()
|
||||
.collect(),
|
||||
false,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.result
|
||||
.unwrap();
|
||||
@@ -1591,6 +1635,7 @@ fn instantiate_return_code() {
|
||||
None,
|
||||
callee_hash.clone(),
|
||||
false,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.result
|
||||
.unwrap();
|
||||
@@ -1609,6 +1654,7 @@ fn instantiate_return_code() {
|
||||
None,
|
||||
callee_hash.clone(),
|
||||
false,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.result
|
||||
.unwrap();
|
||||
@@ -1616,10 +1662,18 @@ fn instantiate_return_code() {
|
||||
|
||||
// Contract has enough balance but the passed code hash is invalid
|
||||
Balances::make_free_balance_be(&addr, min_balance + 10_000);
|
||||
let result =
|
||||
Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, vec![0; 33], false)
|
||||
.result
|
||||
.unwrap();
|
||||
let result = Contracts::bare_call(
|
||||
ALICE,
|
||||
addr.clone(),
|
||||
0,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
vec![0; 33],
|
||||
false,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.result
|
||||
.unwrap();
|
||||
assert_return_code!(result, RuntimeReturnCode::CodeNotFound);
|
||||
|
||||
// Contract has enough balance but callee reverts because "1" is passed.
|
||||
@@ -1631,6 +1685,7 @@ fn instantiate_return_code() {
|
||||
None,
|
||||
callee_hash.iter().chain(&1u32.to_le_bytes()).cloned().collect(),
|
||||
false,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.result
|
||||
.unwrap();
|
||||
@@ -1645,6 +1700,7 @@ fn instantiate_return_code() {
|
||||
None,
|
||||
callee_hash.iter().chain(&2u32.to_le_bytes()).cloned().collect(),
|
||||
false,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.result
|
||||
.unwrap();
|
||||
@@ -1717,8 +1773,16 @@ fn chain_extension_works() {
|
||||
|
||||
// 0 = read input buffer and pass it through as output
|
||||
let input: Vec<u8> = ExtensionInput { extension_id: 0, func_id: 0, extra: &[99] }.into();
|
||||
let result =
|
||||
Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, input.clone(), false);
|
||||
let result = Contracts::bare_call(
|
||||
ALICE,
|
||||
addr.clone(),
|
||||
0,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
input.clone(),
|
||||
false,
|
||||
Determinism::Deterministic,
|
||||
);
|
||||
assert_eq!(TestExtension::last_seen_buffer(), input);
|
||||
assert_eq!(result.result.unwrap().data, input);
|
||||
|
||||
@@ -1731,6 +1795,7 @@ fn chain_extension_works() {
|
||||
None,
|
||||
ExtensionInput { extension_id: 0, func_id: 1, extra: &[] }.into(),
|
||||
false,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.result
|
||||
.unwrap();
|
||||
@@ -1746,6 +1811,7 @@ fn chain_extension_works() {
|
||||
None,
|
||||
ExtensionInput { extension_id: 0, func_id: 2, extra: &[0] }.into(),
|
||||
false,
|
||||
Determinism::Deterministic,
|
||||
);
|
||||
assert_ok!(result.result);
|
||||
let gas_consumed = result.gas_consumed;
|
||||
@@ -1757,6 +1823,7 @@ fn chain_extension_works() {
|
||||
None,
|
||||
ExtensionInput { extension_id: 0, func_id: 2, extra: &[42] }.into(),
|
||||
false,
|
||||
Determinism::Deterministic,
|
||||
);
|
||||
assert_ok!(result.result);
|
||||
assert_eq!(result.gas_consumed.ref_time(), gas_consumed.ref_time() + 42);
|
||||
@@ -1768,6 +1835,7 @@ fn chain_extension_works() {
|
||||
None,
|
||||
ExtensionInput { extension_id: 0, func_id: 2, extra: &[95] }.into(),
|
||||
false,
|
||||
Determinism::Deterministic,
|
||||
);
|
||||
assert_ok!(result.result);
|
||||
assert_eq!(result.gas_consumed.ref_time(), gas_consumed.ref_time() + 95);
|
||||
@@ -1781,6 +1849,7 @@ fn chain_extension_works() {
|
||||
None,
|
||||
ExtensionInput { extension_id: 0, func_id: 3, extra: &[] }.into(),
|
||||
false,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.result
|
||||
.unwrap();
|
||||
@@ -1798,6 +1867,7 @@ fn chain_extension_works() {
|
||||
None,
|
||||
ExtensionInput { extension_id: 1, func_id: 0, extra: &[] }.into(),
|
||||
false,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.result
|
||||
.unwrap();
|
||||
@@ -1847,8 +1917,17 @@ fn chain_extension_temp_storage_works() {
|
||||
);
|
||||
|
||||
assert_ok!(
|
||||
Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, input.clone(), false)
|
||||
.result
|
||||
Contracts::bare_call(
|
||||
ALICE,
|
||||
addr.clone(),
|
||||
0,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
input.clone(),
|
||||
false,
|
||||
Determinism::Deterministic
|
||||
)
|
||||
.result
|
||||
);
|
||||
})
|
||||
}
|
||||
@@ -2387,12 +2466,28 @@ fn reinstrument_does_charge() {
|
||||
|
||||
// Call the contract two times without reinstrument
|
||||
|
||||
let result0 =
|
||||
Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, zero.clone(), false);
|
||||
let result0 = Contracts::bare_call(
|
||||
ALICE,
|
||||
addr.clone(),
|
||||
0,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
zero.clone(),
|
||||
false,
|
||||
Determinism::Deterministic,
|
||||
);
|
||||
assert!(!result0.result.unwrap().did_revert());
|
||||
|
||||
let result1 =
|
||||
Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, zero.clone(), false);
|
||||
let result1 = Contracts::bare_call(
|
||||
ALICE,
|
||||
addr.clone(),
|
||||
0,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
zero.clone(),
|
||||
false,
|
||||
Determinism::Deterministic,
|
||||
);
|
||||
assert!(!result1.result.unwrap().did_revert());
|
||||
|
||||
// They should match because both where called with the same schedule.
|
||||
@@ -2405,8 +2500,16 @@ fn reinstrument_does_charge() {
|
||||
});
|
||||
|
||||
// This call should trigger reinstrumentation
|
||||
let result2 =
|
||||
Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, zero.clone(), false);
|
||||
let result2 = Contracts::bare_call(
|
||||
ALICE,
|
||||
addr.clone(),
|
||||
0,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
zero.clone(),
|
||||
false,
|
||||
Determinism::Deterministic,
|
||||
);
|
||||
assert!(!result2.result.unwrap().did_revert());
|
||||
assert!(result2.gas_consumed.ref_time() > result1.gas_consumed.ref_time());
|
||||
assert_eq!(
|
||||
@@ -2433,7 +2536,16 @@ fn debug_message_works() {
|
||||
vec![],
|
||||
),);
|
||||
let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);
|
||||
let result = Contracts::bare_call(ALICE, addr, 0, GAS_LIMIT, None, vec![], true);
|
||||
let result = Contracts::bare_call(
|
||||
ALICE,
|
||||
addr,
|
||||
0,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
vec![],
|
||||
true,
|
||||
Determinism::Deterministic,
|
||||
);
|
||||
|
||||
assert_matches!(result.result, Ok(_));
|
||||
assert_eq!(std::str::from_utf8(&result.debug_message).unwrap(), "Hello World!");
|
||||
@@ -2457,7 +2569,16 @@ fn debug_message_logging_disabled() {
|
||||
),);
|
||||
let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);
|
||||
// disable logging by passing `false`
|
||||
let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, vec![], false);
|
||||
let result = Contracts::bare_call(
|
||||
ALICE,
|
||||
addr.clone(),
|
||||
0,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
vec![],
|
||||
false,
|
||||
Determinism::Deterministic,
|
||||
);
|
||||
assert_matches!(result.result, Ok(_));
|
||||
// the dispatchables always run without debugging
|
||||
assert_ok!(Contracts::call(RuntimeOrigin::signed(ALICE), addr, 0, GAS_LIMIT, None, vec![]));
|
||||
@@ -2481,7 +2602,16 @@ fn debug_message_invalid_utf8() {
|
||||
vec![],
|
||||
),);
|
||||
let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);
|
||||
let result = Contracts::bare_call(ALICE, addr, 0, GAS_LIMIT, None, vec![], true);
|
||||
let result = Contracts::bare_call(
|
||||
ALICE,
|
||||
addr,
|
||||
0,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
vec![],
|
||||
true,
|
||||
Determinism::Deterministic,
|
||||
);
|
||||
assert_err!(result.result, <Error<Test>>::DebugMessageInvalidUTF8);
|
||||
});
|
||||
}
|
||||
@@ -2532,6 +2662,7 @@ fn gas_estimation_nested_call_fixed_limit() {
|
||||
None,
|
||||
input.clone(),
|
||||
false,
|
||||
Determinism::Deterministic,
|
||||
);
|
||||
assert_ok!(&result.result);
|
||||
|
||||
@@ -2548,6 +2679,7 @@ fn gas_estimation_nested_call_fixed_limit() {
|
||||
Some(result.storage_deposit.charge_or_zero()),
|
||||
input,
|
||||
false,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.result
|
||||
);
|
||||
@@ -2604,6 +2736,7 @@ fn gas_estimation_call_runtime() {
|
||||
None,
|
||||
call.encode(),
|
||||
false,
|
||||
Determinism::Deterministic,
|
||||
);
|
||||
// contract encodes the result of the dispatch runtime
|
||||
let outcome = u32::decode(&mut result.result.unwrap().data.as_ref()).unwrap();
|
||||
@@ -2620,6 +2753,7 @@ fn gas_estimation_call_runtime() {
|
||||
None,
|
||||
call.encode(),
|
||||
false,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.result
|
||||
);
|
||||
@@ -2668,10 +2802,18 @@ fn ecdsa_recover() {
|
||||
params.extend_from_slice(&signature);
|
||||
params.extend_from_slice(&message_hash);
|
||||
assert!(params.len() == 65 + 32);
|
||||
let result =
|
||||
<Pallet<Test>>::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, params, false)
|
||||
.result
|
||||
.unwrap();
|
||||
let result = <Pallet<Test>>::bare_call(
|
||||
ALICE,
|
||||
addr.clone(),
|
||||
0,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
params,
|
||||
false,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.result
|
||||
.unwrap();
|
||||
assert!(!result.did_revert());
|
||||
assert_eq!(result.data, EXPECTED_COMPRESSED_PUBLIC_KEY);
|
||||
})
|
||||
@@ -2691,7 +2833,8 @@ fn upload_code_works() {
|
||||
assert_ok!(Contracts::upload_code(
|
||||
RuntimeOrigin::signed(ALICE),
|
||||
wasm,
|
||||
Some(codec::Compact(1_000))
|
||||
Some(codec::Compact(1_000)),
|
||||
Determinism::Deterministic,
|
||||
));
|
||||
assert!(<CodeStorage<Test>>::contains_key(code_hash));
|
||||
|
||||
@@ -2702,7 +2845,7 @@ fn upload_code_works() {
|
||||
phase: Phase::Initialization,
|
||||
event: RuntimeEvent::Balances(pallet_balances::Event::Reserved {
|
||||
who: ALICE,
|
||||
amount: 240,
|
||||
amount: 241,
|
||||
}),
|
||||
topics: vec![],
|
||||
},
|
||||
@@ -2727,7 +2870,12 @@ fn upload_code_limit_too_low() {
|
||||
initialize_block(2);
|
||||
|
||||
assert_noop!(
|
||||
Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm, Some(codec::Compact(100))),
|
||||
Contracts::upload_code(
|
||||
RuntimeOrigin::signed(ALICE),
|
||||
wasm,
|
||||
Some(codec::Compact(100)),
|
||||
Determinism::Deterministic
|
||||
),
|
||||
<Error<Test>>::StorageDepositLimitExhausted,
|
||||
);
|
||||
|
||||
@@ -2746,7 +2894,12 @@ fn upload_code_not_enough_balance() {
|
||||
initialize_block(2);
|
||||
|
||||
assert_noop!(
|
||||
Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm, Some(codec::Compact(1_000))),
|
||||
Contracts::upload_code(
|
||||
RuntimeOrigin::signed(ALICE),
|
||||
wasm,
|
||||
Some(codec::Compact(1_000)),
|
||||
Determinism::Deterministic
|
||||
),
|
||||
<Error<Test>>::StorageDepositNotEnoughFunds,
|
||||
);
|
||||
|
||||
@@ -2767,7 +2920,8 @@ fn remove_code_works() {
|
||||
assert_ok!(Contracts::upload_code(
|
||||
RuntimeOrigin::signed(ALICE),
|
||||
wasm,
|
||||
Some(codec::Compact(1_000))
|
||||
Some(codec::Compact(1_000)),
|
||||
Determinism::Deterministic,
|
||||
));
|
||||
|
||||
assert!(<CodeStorage<Test>>::contains_key(code_hash));
|
||||
@@ -2781,7 +2935,7 @@ fn remove_code_works() {
|
||||
phase: Phase::Initialization,
|
||||
event: RuntimeEvent::Balances(pallet_balances::Event::Reserved {
|
||||
who: ALICE,
|
||||
amount: 240,
|
||||
amount: 241,
|
||||
}),
|
||||
topics: vec![],
|
||||
},
|
||||
@@ -2794,7 +2948,7 @@ fn remove_code_works() {
|
||||
phase: Phase::Initialization,
|
||||
event: RuntimeEvent::Balances(pallet_balances::Event::Unreserved {
|
||||
who: ALICE,
|
||||
amount: 240,
|
||||
amount: 241,
|
||||
}),
|
||||
topics: vec![],
|
||||
},
|
||||
@@ -2821,7 +2975,8 @@ fn remove_code_wrong_origin() {
|
||||
assert_ok!(Contracts::upload_code(
|
||||
RuntimeOrigin::signed(ALICE),
|
||||
wasm,
|
||||
Some(codec::Compact(1_000))
|
||||
Some(codec::Compact(1_000)),
|
||||
Determinism::Deterministic,
|
||||
));
|
||||
|
||||
assert_noop!(
|
||||
@@ -2836,7 +2991,7 @@ fn remove_code_wrong_origin() {
|
||||
phase: Phase::Initialization,
|
||||
event: RuntimeEvent::Balances(pallet_balances::Event::Reserved {
|
||||
who: ALICE,
|
||||
amount: 240,
|
||||
amount: 241,
|
||||
}),
|
||||
topics: vec![],
|
||||
},
|
||||
@@ -2969,7 +3124,7 @@ fn instantiate_with_zero_balance_works() {
|
||||
phase: Phase::Initialization,
|
||||
event: RuntimeEvent::Balances(pallet_balances::Event::Reserved {
|
||||
who: ALICE,
|
||||
amount: 240,
|
||||
amount: 241,
|
||||
}),
|
||||
topics: vec![],
|
||||
},
|
||||
@@ -3071,7 +3226,7 @@ fn instantiate_with_below_existential_deposit_works() {
|
||||
phase: Phase::Initialization,
|
||||
event: RuntimeEvent::Balances(pallet_balances::Event::Reserved {
|
||||
who: ALICE,
|
||||
amount: 240,
|
||||
amount: 241,
|
||||
}),
|
||||
topics: vec![],
|
||||
},
|
||||
@@ -3261,7 +3416,12 @@ fn set_code_extrinsic() {
|
||||
));
|
||||
let addr = Contracts::contract_address(&ALICE, &code_hash, &[]);
|
||||
|
||||
assert_ok!(Contracts::upload_code(RuntimeOrigin::signed(ALICE), new_wasm, None,));
|
||||
assert_ok!(Contracts::upload_code(
|
||||
RuntimeOrigin::signed(ALICE),
|
||||
new_wasm,
|
||||
None,
|
||||
Determinism::Deterministic
|
||||
));
|
||||
|
||||
// Drop previous events
|
||||
initialize_block(2);
|
||||
@@ -3457,7 +3617,12 @@ fn contract_reverted() {
|
||||
let input = (flags.bits(), buffer).encode();
|
||||
|
||||
// We just upload the code for later use
|
||||
assert_ok!(Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm.clone(), None));
|
||||
assert_ok!(Contracts::upload_code(
|
||||
RuntimeOrigin::signed(ALICE),
|
||||
wasm.clone(),
|
||||
None,
|
||||
Determinism::Deterministic
|
||||
));
|
||||
|
||||
// Calling extrinsic: revert leads to an error
|
||||
assert_err_ignore_postinfo!(
|
||||
@@ -3536,9 +3701,18 @@ fn contract_reverted() {
|
||||
);
|
||||
|
||||
// Calling directly: revert leads to success but the flags indicate the error
|
||||
let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, input, false)
|
||||
.result
|
||||
.unwrap();
|
||||
let result = Contracts::bare_call(
|
||||
ALICE,
|
||||
addr.clone(),
|
||||
0,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
input,
|
||||
false,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.result
|
||||
.unwrap();
|
||||
assert_eq!(result.flags, flags);
|
||||
assert_eq!(result.data, buffer);
|
||||
});
|
||||
@@ -3551,7 +3725,12 @@ fn code_rejected_error_works() {
|
||||
let _ = Balances::deposit_creating(&ALICE, 1_000_000);
|
||||
|
||||
assert_noop!(
|
||||
Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm.clone(), None),
|
||||
Contracts::upload_code(
|
||||
RuntimeOrigin::signed(ALICE),
|
||||
wasm.clone(),
|
||||
None,
|
||||
Determinism::Deterministic
|
||||
),
|
||||
<Error<Test>>::CodeRejected,
|
||||
);
|
||||
|
||||
@@ -3594,7 +3773,12 @@ fn set_code_hash() {
|
||||
vec![],
|
||||
));
|
||||
// upload new code
|
||||
assert_ok!(Contracts::upload_code(RuntimeOrigin::signed(ALICE), new_wasm.clone(), None));
|
||||
assert_ok!(Contracts::upload_code(
|
||||
RuntimeOrigin::signed(ALICE),
|
||||
new_wasm.clone(),
|
||||
None,
|
||||
Determinism::Deterministic
|
||||
));
|
||||
|
||||
System::reset_events();
|
||||
|
||||
@@ -3607,16 +3791,25 @@ fn set_code_hash() {
|
||||
None,
|
||||
new_code_hash.as_ref().to_vec(),
|
||||
true,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.result
|
||||
.unwrap();
|
||||
assert_return_code!(result, 1);
|
||||
|
||||
// Second calls new contract code that returns 2
|
||||
let result =
|
||||
Contracts::bare_call(ALICE, contract_addr.clone(), 0, GAS_LIMIT, None, vec![], true)
|
||||
.result
|
||||
.unwrap();
|
||||
let result = Contracts::bare_call(
|
||||
ALICE,
|
||||
contract_addr.clone(),
|
||||
0,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
vec![],
|
||||
true,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.result
|
||||
.unwrap();
|
||||
assert_return_code!(result, 2);
|
||||
|
||||
// Checking for the last event only
|
||||
@@ -3950,3 +4143,243 @@ fn deposit_limit_honors_min_leftover() {
|
||||
assert_eq!(Balances::free_balance(&BOB), 1_000);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cannot_instantiate_indeterministic_code() {
|
||||
let (wasm, code_hash) = compile_module::<Test>("float_instruction").unwrap();
|
||||
let (caller_wasm, _) = compile_module::<Test>("instantiate_return_code").unwrap();
|
||||
ExtBuilder::default().existential_deposit(200).build().execute_with(|| {
|
||||
let _ = Balances::deposit_creating(&ALICE, 1_000_000);
|
||||
|
||||
// Try to instantiate directly from code
|
||||
assert_err_ignore_postinfo!(
|
||||
Contracts::instantiate_with_code(
|
||||
RuntimeOrigin::signed(ALICE),
|
||||
0,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
wasm.clone(),
|
||||
vec![],
|
||||
vec![],
|
||||
),
|
||||
<Error<Test>>::CodeRejected,
|
||||
);
|
||||
assert_err!(
|
||||
Contracts::bare_instantiate(
|
||||
ALICE,
|
||||
0,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
Code::Upload(wasm.clone()),
|
||||
vec![],
|
||||
vec![],
|
||||
false,
|
||||
)
|
||||
.result,
|
||||
<Error<Test>>::CodeRejected,
|
||||
);
|
||||
|
||||
// Try to upload a non deterministic code as deterministic
|
||||
assert_err!(
|
||||
Contracts::upload_code(
|
||||
RuntimeOrigin::signed(ALICE),
|
||||
wasm.clone(),
|
||||
None,
|
||||
Determinism::Deterministic
|
||||
),
|
||||
<Error<Test>>::CodeRejected,
|
||||
);
|
||||
|
||||
// Try to instantiate from already stored indeterministic code hash
|
||||
assert_ok!(Contracts::upload_code(
|
||||
RuntimeOrigin::signed(ALICE),
|
||||
wasm,
|
||||
None,
|
||||
Determinism::AllowIndeterminism,
|
||||
));
|
||||
assert_err_ignore_postinfo!(
|
||||
Contracts::instantiate(
|
||||
RuntimeOrigin::signed(ALICE),
|
||||
0,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
code_hash,
|
||||
vec![],
|
||||
vec![],
|
||||
),
|
||||
<Error<Test>>::Indeterministic,
|
||||
);
|
||||
assert_err!(
|
||||
Contracts::bare_instantiate(
|
||||
ALICE,
|
||||
0,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
Code::Existing(code_hash),
|
||||
vec![],
|
||||
vec![],
|
||||
false,
|
||||
)
|
||||
.result,
|
||||
<Error<Test>>::Indeterministic,
|
||||
);
|
||||
|
||||
// Deploy contract which instantiates another contract
|
||||
let addr = Contracts::bare_instantiate(
|
||||
ALICE,
|
||||
0,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
Code::Upload(caller_wasm),
|
||||
vec![],
|
||||
vec![],
|
||||
false,
|
||||
)
|
||||
.result
|
||||
.unwrap()
|
||||
.account_id;
|
||||
|
||||
// Try to instantiate `code_hash` from another contract in deterministic mode
|
||||
assert_err!(
|
||||
<Pallet<Test>>::bare_call(
|
||||
ALICE,
|
||||
addr.clone(),
|
||||
0,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
code_hash.encode(),
|
||||
false,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.result,
|
||||
<Error<Test>>::Indeterministic,
|
||||
);
|
||||
|
||||
// Instantiations are not allowed even in non determinism mode
|
||||
assert_err!(
|
||||
<Pallet<Test>>::bare_call(
|
||||
ALICE,
|
||||
addr.clone(),
|
||||
0,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
code_hash.encode(),
|
||||
false,
|
||||
Determinism::AllowIndeterminism,
|
||||
)
|
||||
.result,
|
||||
<Error<Test>>::Indeterministic,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cannot_set_code_indeterministic_code() {
|
||||
let (wasm, code_hash) = compile_module::<Test>("float_instruction").unwrap();
|
||||
let (caller_wasm, _) = compile_module::<Test>("set_code_hash").unwrap();
|
||||
ExtBuilder::default().existential_deposit(200).build().execute_with(|| {
|
||||
let _ = Balances::deposit_creating(&ALICE, 1_000_000);
|
||||
|
||||
// Put the non deterministic contract on-chain
|
||||
assert_ok!(Contracts::upload_code(
|
||||
RuntimeOrigin::signed(ALICE),
|
||||
wasm,
|
||||
None,
|
||||
Determinism::AllowIndeterminism,
|
||||
));
|
||||
|
||||
// Create the contract that will call `seal_set_code_hash`
|
||||
let caller_addr = Contracts::bare_instantiate(
|
||||
ALICE,
|
||||
0,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
Code::Upload(caller_wasm),
|
||||
vec![],
|
||||
vec![],
|
||||
false,
|
||||
)
|
||||
.result
|
||||
.unwrap()
|
||||
.account_id;
|
||||
|
||||
// We do not allow to set the code hash to a non determinstic wasm
|
||||
assert_err!(
|
||||
<Pallet<Test>>::bare_call(
|
||||
ALICE,
|
||||
caller_addr.clone(),
|
||||
0,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
code_hash.encode(),
|
||||
false,
|
||||
Determinism::AllowIndeterminism,
|
||||
)
|
||||
.result,
|
||||
<Error<Test>>::Indeterministic,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn delegate_call_indeterministic_code() {
|
||||
let (wasm, code_hash) = compile_module::<Test>("float_instruction").unwrap();
|
||||
let (caller_wasm, _) = compile_module::<Test>("delegate_call_simple").unwrap();
|
||||
ExtBuilder::default().existential_deposit(200).build().execute_with(|| {
|
||||
let _ = Balances::deposit_creating(&ALICE, 1_000_000);
|
||||
|
||||
// Put the non deterministic contract on-chain
|
||||
assert_ok!(Contracts::upload_code(
|
||||
RuntimeOrigin::signed(ALICE),
|
||||
wasm,
|
||||
None,
|
||||
Determinism::AllowIndeterminism,
|
||||
));
|
||||
|
||||
// Create the contract that will call `seal_delegate_call`
|
||||
let caller_addr = Contracts::bare_instantiate(
|
||||
ALICE,
|
||||
0,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
Code::Upload(caller_wasm),
|
||||
vec![],
|
||||
vec![],
|
||||
false,
|
||||
)
|
||||
.result
|
||||
.unwrap()
|
||||
.account_id;
|
||||
|
||||
// The delegate call will fail in deterministic mode
|
||||
assert_err!(
|
||||
<Pallet<Test>>::bare_call(
|
||||
ALICE,
|
||||
caller_addr.clone(),
|
||||
0,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
code_hash.encode(),
|
||||
false,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.result,
|
||||
<Error<Test>>::Indeterministic,
|
||||
);
|
||||
|
||||
// The delegate call will work on non deterministic mode
|
||||
assert_ok!(
|
||||
<Pallet<Test>>::bare_call(
|
||||
ALICE,
|
||||
caller_addr.clone(),
|
||||
0,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
code_hash.encode(),
|
||||
false,
|
||||
Determinism::AllowIndeterminism,
|
||||
)
|
||||
.result
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user