Emit ContractReverted error when revert flag is set (#10481)

* Emit `ContractReverted` error when revert flag is set

* `is_success()` -> `did_revert()`
This commit is contained in:
Alexander Theißen
2021-12-15 08:35:05 +01:00
committed by GitHub
parent 7ee25416c2
commit 1939567a79
5 changed files with 136 additions and 19 deletions
+97 -6
View File
@@ -24,7 +24,7 @@ use crate::{
storage::Storage,
wasm::{PrefabWasmModule, ReturnCode as RuntimeReturnCode},
weights::WeightInfo,
BalanceOf, CodeStorage, Config, ContractInfoOf, Error, Pallet, Schedule,
BalanceOf, Code, CodeStorage, Config, ContractInfoOf, Error, Pallet, Schedule,
};
use assert_matches::assert_matches;
use codec::Encode;
@@ -1096,7 +1096,7 @@ fn crypto_hashes() {
<Pallet<Test>>::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, params, false)
.result
.unwrap();
assert!(result.is_success());
assert!(!result.did_revert());
let expected = hash_fn(input.as_ref());
assert_eq!(&result.data[..*expected_size], &*expected);
}
@@ -1881,11 +1881,11 @@ fn reinstrument_does_charge() {
let result0 =
Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, zero.clone(), false);
assert!(result0.result.unwrap().is_success());
assert!(!result0.result.unwrap().did_revert());
let result1 =
Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, zero.clone(), false);
assert!(result1.result.unwrap().is_success());
assert!(!result1.result.unwrap().did_revert());
// They should match because both where called with the same schedule.
assert_eq!(result0.gas_consumed, result1.gas_consumed);
@@ -1899,7 +1899,7 @@ fn reinstrument_does_charge() {
// This call should trigger reinstrumentation
let result2 =
Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, zero.clone(), false);
assert!(result2.result.unwrap().is_success());
assert!(!result2.result.unwrap().did_revert());
assert!(result2.gas_consumed > result1.gas_consumed);
assert_eq!(
result2.gas_consumed,
@@ -2162,7 +2162,7 @@ fn ecdsa_recover() {
<Pallet<Test>>::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, params, false)
.result
.unwrap();
assert!(result.is_success());
assert!(!result.did_revert());
assert_eq!(result.data.as_ref(), &EXPECTED_COMPRESSED_PUBLIC_KEY);
})
}
@@ -2808,3 +2808,94 @@ fn call_after_killed_account_needs_funding() {
);
});
}
#[test]
fn contract_reverted() {
let (wasm, code_hash) = compile_module::<Test>("return_with_data").unwrap();
ExtBuilder::default().existential_deposit(100).build().execute_with(|| {
let _ = Balances::deposit_creating(&ALICE, 1_000_000);
let flags = ReturnFlags::REVERT;
let buffer = [4u8, 8, 15, 16, 23, 42];
let input = (flags.bits(), buffer).encode();
// We just upload the code for later use
assert_ok!(Contracts::upload_code(Origin::signed(ALICE), wasm.clone(), None));
// Calling extrinsic: revert leads to an error
assert_err_ignore_postinfo!(
Contracts::instantiate(
Origin::signed(ALICE),
0,
GAS_LIMIT,
None,
code_hash,
input.clone(),
vec![],
),
<Error<Test>>::ContractReverted,
);
// Calling extrinsic: revert leads to an error
assert_err_ignore_postinfo!(
Contracts::instantiate_with_code(
Origin::signed(ALICE),
0,
GAS_LIMIT,
None,
wasm,
input.clone(),
vec![],
),
<Error<Test>>::ContractReverted,
);
// Calling directly: revert leads to success but the flags indicate the error
// This is just a different way of transporting the error that allows the read out
// the `data` which is only there on success. Obviously, the contract isn't
// instantiated.
let result = Contracts::bare_instantiate(
ALICE,
0,
GAS_LIMIT,
None,
Code::Existing(code_hash),
input.clone(),
vec![],
false,
)
.result
.unwrap();
assert_eq!(result.result.flags, flags);
assert_eq!(result.result.data.0, buffer);
assert!(!<ContractInfoOf<Test>>::contains_key(result.account_id));
// Pass empty flags and therefore successfully instantiate the contract for later use.
let addr = Contracts::bare_instantiate(
ALICE,
0,
GAS_LIMIT,
None,
Code::Existing(code_hash),
ReturnFlags::empty().bits().encode(),
vec![],
false,
)
.result
.unwrap()
.account_id;
// Calling extrinsic: revert leads to an error
assert_err_ignore_postinfo!(
Contracts::call(Origin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, None, input.clone()),
<Error<Test>>::ContractReverted,
);
// 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();
assert_eq!(result.flags, flags);
assert_eq!(result.data.0, buffer);
});
}