Skip to content

Commit 070dfa2

Browse files
juangirininathanwhit
authored andcommitted
contracts: add events to ContractResult (paritytech#13807)
* contracts: add events to ContractResult * contracts: add encoded events to ContractResult * contracts: add generic Event to ContractResult * contracts: test bare_call events * contracts: update bare_call test name * contracts: add better comments to dry run events * contracts: fix pallet contracts primitives implementation * contracts: add EventRecord generic to ContractInstantiateResult * contracts: make event collection optional * contracts: impreved notes on `collect_events` * contracts: update benchmarking calls * contracts: change bare_call and bare_instantiate to accept enums instead of bools * contracts: add partial eq to new enums * contracts: improve comments * contracts: improve comments * contracts: fix bare_call benchmarking * contracts: fix bare call and instantiate in impl_runtime_apis * contracts: add api versioning to new ContractsApi functions * contracts: modify api versioning to new ContractsApi functions * contracts: create new contracts api trait * contracts: clean up code * contracts: remove the contract results with events * contracts: undo contracts api v3 * contracts: remove commented out code * contracts: add new test bare call result does not return events * contracts: add code review improvements * contracts: remove type imports * contracts: minor code review improvements
1 parent 5ee0c54 commit 070dfa2

File tree

5 files changed

+487
-158
lines changed

5 files changed

+487
-158
lines changed

bin/node/runtime/src/lib.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1880,6 +1880,11 @@ type Migrations = (
18801880
pallet_contracts::Migration<Runtime>,
18811881
);
18821882

1883+
type EventRecord = frame_system::EventRecord<
1884+
<Runtime as frame_system::Config>::RuntimeEvent,
1885+
<Runtime as frame_system::Config>::Hash,
1886+
>;
1887+
18831888
/// MMR helper types.
18841889
mod mmr {
18851890
use super::Runtime;
@@ -2141,7 +2146,7 @@ impl_runtime_apis! {
21412146
}
21422147
}
21432148

2144-
impl pallet_contracts::ContractsApi<Block, AccountId, Balance, BlockNumber, Hash> for Runtime
2149+
impl pallet_contracts::ContractsApi<Block, AccountId, Balance, BlockNumber, Hash, EventRecord> for Runtime
21452150
{
21462151
fn call(
21472152
origin: AccountId,
@@ -2150,7 +2155,7 @@ impl_runtime_apis! {
21502155
gas_limit: Option<Weight>,
21512156
storage_deposit_limit: Option<Balance>,
21522157
input_data: Vec<u8>,
2153-
) -> pallet_contracts_primitives::ContractExecResult<Balance> {
2158+
) -> pallet_contracts_primitives::ContractExecResult<Balance, EventRecord> {
21542159
let gas_limit = gas_limit.unwrap_or(RuntimeBlockWeights::get().max_block);
21552160
Contracts::bare_call(
21562161
origin,
@@ -2159,7 +2164,8 @@ impl_runtime_apis! {
21592164
gas_limit,
21602165
storage_deposit_limit,
21612166
input_data,
2162-
true,
2167+
pallet_contracts::DebugInfo::UnsafeDebug,
2168+
pallet_contracts::CollectEvents::UnsafeCollect,
21632169
pallet_contracts::Determinism::Enforced,
21642170
)
21652171
}
@@ -2172,7 +2178,7 @@ impl_runtime_apis! {
21722178
code: pallet_contracts_primitives::Code<Hash>,
21732179
data: Vec<u8>,
21742180
salt: Vec<u8>,
2175-
) -> pallet_contracts_primitives::ContractInstantiateResult<AccountId, Balance>
2181+
) -> pallet_contracts_primitives::ContractInstantiateResult<AccountId, Balance, EventRecord>
21762182
{
21772183
let gas_limit = gas_limit.unwrap_or(RuntimeBlockWeights::get().max_block);
21782184
Contracts::bare_instantiate(
@@ -2183,7 +2189,8 @@ impl_runtime_apis! {
21832189
code,
21842190
data,
21852191
salt,
2186-
true
2192+
pallet_contracts::DebugInfo::UnsafeDebug,
2193+
pallet_contracts::CollectEvents::UnsafeCollect,
21872194
)
21882195
}
21892196

frame/contracts/primitives/src/lib.rs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,18 @@ use sp_runtime::{
2929
use sp_std::prelude::*;
3030
use sp_weights::Weight;
3131

32-
/// Result type of a `bare_call` or `bare_instantiate` call.
32+
/// Result type of a `bare_call` or `bare_instantiate` call as well as `ContractsApi::call` and
33+
/// `ContractsApi::instantiate`.
3334
///
3435
/// It contains the execution result together with some auxiliary information.
36+
///
37+
/// #Note
38+
///
39+
/// It has been extended to include `events` at the end of the struct while not bumping the
40+
/// `ContractsApi` version. Therefore when SCALE decoding a `ContractResult` its trailing data
41+
/// should be ignored to avoid any potential compatibility issues.
3542
#[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)]
36-
pub struct ContractResult<R, Balance> {
43+
pub struct ContractResult<R, Balance, EventRecord> {
3744
/// How much weight was consumed during execution.
3845
pub gas_consumed: Weight,
3946
/// How much weight is required as gas limit in order to execute this call.
@@ -71,15 +78,18 @@ pub struct ContractResult<R, Balance> {
7178
pub debug_message: Vec<u8>,
7279
/// The execution result of the wasm code.
7380
pub result: R,
81+
/// The events that were emitted during execution. It is an option as event collection is
82+
/// optional.
83+
pub events: Option<Vec<EventRecord>>,
7484
}
7585

76-
/// Result type of a `bare_call` call.
77-
pub type ContractExecResult<Balance> =
78-
ContractResult<Result<ExecReturnValue, DispatchError>, Balance>;
86+
/// Result type of a `bare_call` call as well as `ContractsApi::call`.
87+
pub type ContractExecResult<Balance, EventRecord> =
88+
ContractResult<Result<ExecReturnValue, DispatchError>, Balance, EventRecord>;
7989

80-
/// Result type of a `bare_instantiate` call.
81-
pub type ContractInstantiateResult<AccountId, Balance> =
82-
ContractResult<Result<InstantiateReturnValue<AccountId>, DispatchError>, Balance>;
90+
/// Result type of a `bare_instantiate` call as well as `ContractsApi::instantiate`.
91+
pub type ContractInstantiateResult<AccountId, Balance, EventRecord> =
92+
ContractResult<Result<InstantiateReturnValue<AccountId>, DispatchError>, Balance, EventRecord>;
8393

8494
/// Result type of a `bare_code_upload` call.
8595
pub type CodeUploadResult<CodeHash, Balance> =

frame/contracts/src/benchmarking/mod.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -951,7 +951,8 @@ benchmarks! {
951951
Weight::MAX,
952952
None,
953953
vec![],
954-
true,
954+
DebugInfo::UnsafeDebug,
955+
CollectEvents::Skip,
955956
Determinism::Enforced,
956957
)
957958
.result?;
@@ -1000,7 +1001,8 @@ benchmarks! {
10001001
Weight::MAX,
10011002
None,
10021003
vec![],
1003-
true,
1004+
DebugInfo::UnsafeDebug,
1005+
CollectEvents::Skip,
10041006
Determinism::Enforced,
10051007
)
10061008
.result?;
@@ -3192,7 +3194,8 @@ benchmarks! {
31923194
Weight::MAX,
31933195
None,
31943196
data,
3195-
false,
3197+
DebugInfo::Skip,
3198+
CollectEvents::Skip,
31963199
Determinism::Enforced,
31973200
)
31983201
.result?;
@@ -3241,7 +3244,8 @@ benchmarks! {
32413244
Weight::MAX,
32423245
None,
32433246
data,
3244-
false,
3247+
DebugInfo::Skip,
3248+
CollectEvents::Skip,
32453249
Determinism::Enforced,
32463250
)
32473251
.result?;

frame/contracts/src/lib.rs

Lines changed: 75 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ use frame_support::{
117117
weights::Weight,
118118
BoundedVec, RuntimeDebugNoBound, WeakBoundedVec,
119119
};
120-
use frame_system::{ensure_signed, pallet_prelude::OriginFor, Pallet as System};
120+
use frame_system::{ensure_signed, pallet_prelude::OriginFor, EventRecord, Pallet as System};
121121
use pallet_contracts_primitives::{
122122
Code, CodeUploadResult, CodeUploadReturnValue, ContractAccessError, ContractExecResult,
123123
ContractInstantiateResult, ExecReturnValue, GetStorageResult, InstantiateReturnValue,
@@ -148,6 +148,8 @@ type CodeVec<T> = BoundedVec<u8, <T as Config>::MaxCodeLen>;
148148
type RelaxedCodeVec<T> = WeakBoundedVec<u8, <T as Config>::MaxCodeLen>;
149149
type AccountIdLookupOf<T> = <<T as frame_system::Config>::Lookup as StaticLookup>::Source;
150150
type DebugBufferVec<T> = BoundedVec<u8, <T as Config>::MaxDebugBufferLen>;
151+
type EventRecordOf<T> =
152+
EventRecord<<T as frame_system::Config>::RuntimeEvent, <T as frame_system::Config>::Hash>;
151153

152154
/// The old weight type.
153155
///
@@ -971,6 +973,35 @@ struct InstantiateInput<T: Config> {
971973
salt: Vec<u8>,
972974
}
973975

976+
/// Determines whether events should be collected during execution.
977+
#[derive(PartialEq)]
978+
pub enum CollectEvents {
979+
/// Collect events.
980+
///
981+
/// # Note
982+
///
983+
/// Events should only be collected when called off-chain, as this would otherwise
984+
/// collect all the Events emitted in the block so far and put them into the PoV.
985+
///
986+
/// **Never** use this mode for on-chain execution.
987+
UnsafeCollect,
988+
/// Skip event collection.
989+
Skip,
990+
}
991+
992+
/// Determines whether debug messages will be collected.
993+
#[derive(PartialEq)]
994+
pub enum DebugInfo {
995+
/// Collect debug messages.
996+
/// # Note
997+
///
998+
/// This should only ever be set to `UnsafeDebug` when executing as an RPC because
999+
/// it adds allocations and could be abused to drive the runtime into an OOM panic.
1000+
UnsafeDebug,
1001+
/// Skip collection of debug messages.
1002+
Skip,
1003+
}
1004+
9741005
/// Return type of private helper functions.
9751006
struct InternalOutput<T: Config, O> {
9761007
/// The gas meter that was used to execute the call.
@@ -1187,22 +1218,27 @@ impl<T: Config> Pallet<T> {
11871218
///
11881219
/// # Note
11891220
///
1190-
/// `debug` should only ever be set to `true` when executing as an RPC because
1191-
/// it adds allocations and could be abused to drive the runtime into an OOM panic.
1192-
/// If set to `true` it returns additional human readable debugging information.
1221+
/// If `debug` is set to `DebugInfo::UnsafeDebug` it returns additional human readable debugging
1222+
/// information.
11931223
///
1194-
/// It returns the execution result and the amount of used weight.
1224+
/// If `collect_events` is set to `CollectEvents::UnsafeCollect` it collects all the Events
1225+
/// emitted in the block so far and the ones emitted during the execution of this contract.
11951226
pub fn bare_call(
11961227
origin: T::AccountId,
11971228
dest: T::AccountId,
11981229
value: BalanceOf<T>,
11991230
gas_limit: Weight,
12001231
storage_deposit_limit: Option<BalanceOf<T>>,
12011232
data: Vec<u8>,
1202-
debug: bool,
1233+
debug: DebugInfo,
1234+
collect_events: CollectEvents,
12031235
determinism: Determinism,
1204-
) -> ContractExecResult<BalanceOf<T>> {
1205-
let mut debug_message = if debug { Some(DebugBufferVec::<T>::default()) } else { None };
1236+
) -> ContractExecResult<BalanceOf<T>, EventRecordOf<T>> {
1237+
let mut debug_message = if matches!(debug, DebugInfo::UnsafeDebug) {
1238+
Some(DebugBufferVec::<T>::default())
1239+
} else {
1240+
None
1241+
};
12061242
let origin = Origin::from_account_id(origin);
12071243
let common = CommonInput {
12081244
origin,
@@ -1213,12 +1249,19 @@ impl<T: Config> Pallet<T> {
12131249
debug_message: debug_message.as_mut(),
12141250
};
12151251
let output = CallInput::<T> { dest, determinism }.run_guarded(common);
1252+
let events = if matches!(collect_events, CollectEvents::UnsafeCollect) {
1253+
Some(System::<T>::read_events_no_consensus().map(|e| *e).collect())
1254+
} else {
1255+
None
1256+
};
1257+
12161258
ContractExecResult {
12171259
result: output.result.map_err(|r| r.error),
12181260
gas_consumed: output.gas_meter.gas_consumed(),
12191261
gas_required: output.gas_meter.gas_required(),
12201262
storage_deposit: output.storage_deposit,
12211263
debug_message: debug_message.unwrap_or_default().to_vec(),
1264+
events,
12221265
}
12231266
}
12241267

@@ -1231,9 +1274,11 @@ impl<T: Config> Pallet<T> {
12311274
///
12321275
/// # Note
12331276
///
1234-
/// `debug` should only ever be set to `true` when executing as an RPC because
1235-
/// it adds allocations and could be abused to drive the runtime into an OOM panic.
1236-
/// If set to `true` it returns additional human readable debugging information.
1277+
/// If `debug` is set to `DebugInfo::UnsafeDebug` it returns additional human readable debugging
1278+
/// information.
1279+
///
1280+
/// If `collect_events` is set to `CollectEvents::UnsafeCollect` it collects all the Events
1281+
/// emitted in the block so far.
12371282
pub fn bare_instantiate(
12381283
origin: T::AccountId,
12391284
value: BalanceOf<T>,
@@ -1242,9 +1287,14 @@ impl<T: Config> Pallet<T> {
12421287
code: Code<CodeHash<T>>,
12431288
data: Vec<u8>,
12441289
salt: Vec<u8>,
1245-
debug: bool,
1246-
) -> ContractInstantiateResult<T::AccountId, BalanceOf<T>> {
1247-
let mut debug_message = if debug { Some(DebugBufferVec::<T>::default()) } else { None };
1290+
debug: DebugInfo,
1291+
collect_events: CollectEvents,
1292+
) -> ContractInstantiateResult<T::AccountId, BalanceOf<T>, EventRecordOf<T>> {
1293+
let mut debug_message = if debug == DebugInfo::UnsafeDebug {
1294+
Some(DebugBufferVec::<T>::default())
1295+
} else {
1296+
None
1297+
};
12481298
let common = CommonInput {
12491299
origin: Origin::from_account_id(origin),
12501300
value,
@@ -1254,6 +1304,12 @@ impl<T: Config> Pallet<T> {
12541304
debug_message: debug_message.as_mut(),
12551305
};
12561306
let output = InstantiateInput::<T> { code, salt }.run_guarded(common);
1307+
// collect events if CollectEvents is UnsafeCollect
1308+
let events = if collect_events == CollectEvents::UnsafeCollect {
1309+
Some(System::<T>::read_events_no_consensus().map(|e| *e).collect())
1310+
} else {
1311+
None
1312+
};
12571313
ContractInstantiateResult {
12581314
result: output
12591315
.result
@@ -1263,6 +1319,7 @@ impl<T: Config> Pallet<T> {
12631319
gas_required: output.gas_meter.gas_required(),
12641320
storage_deposit: output.storage_deposit,
12651321
debug_message: debug_message.unwrap_or_default().to_vec(),
1322+
events,
12661323
}
12671324
}
12681325

@@ -1370,11 +1427,12 @@ impl<T: Config> Pallet<T> {
13701427
sp_api::decl_runtime_apis! {
13711428
/// The API used to dry-run contract interactions.
13721429
#[api_version(2)]
1373-
pub trait ContractsApi<AccountId, Balance, BlockNumber, Hash> where
1430+
pub trait ContractsApi<AccountId, Balance, BlockNumber, Hash, EventRecord> where
13741431
AccountId: Codec,
13751432
Balance: Codec,
13761433
BlockNumber: Codec,
13771434
Hash: Codec,
1435+
EventRecord: Codec,
13781436
{
13791437
/// Perform a call from a specified account to a given contract.
13801438
///
@@ -1386,7 +1444,7 @@ sp_api::decl_runtime_apis! {
13861444
gas_limit: Option<Weight>,
13871445
storage_deposit_limit: Option<Balance>,
13881446
input_data: Vec<u8>,
1389-
) -> ContractExecResult<Balance>;
1447+
) -> ContractExecResult<Balance, EventRecord>;
13901448

13911449
/// Instantiate a new contract.
13921450
///
@@ -1399,8 +1457,7 @@ sp_api::decl_runtime_apis! {
13991457
code: Code<Hash>,
14001458
data: Vec<u8>,
14011459
salt: Vec<u8>,
1402-
) -> ContractInstantiateResult<AccountId, Balance>;
1403-
1460+
) -> ContractInstantiateResult<AccountId, Balance, EventRecord>;
14041461

14051462
/// Upload new code without instantiating a contract from it.
14061463
///

0 commit comments

Comments
 (0)