Skip to content

Commit

Permalink
Accessing emitted events (#92)
Browse files Browse the repository at this point in the history
  • Loading branch information
pmikolajczyk41 committed Dec 11, 2023
1 parent e59baf9 commit fab9dc7
Show file tree
Hide file tree
Showing 9 changed files with 405 additions and 77 deletions.
4 changes: 2 additions & 2 deletions drink-cli/src/executor/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ pub fn deploy(app_state: &mut AppState, constructor: String, args: Vec<String>,
Err(err) => app_state.print_error(&format!("Failed to deploy contract\n{err}")),
}

if let Some(info) = app_state.session.last_deploy_result() {
if let Some(info) = app_state.session.record().deploy_results().last() {
app_state.print(&format_contract_action(info));
}
}
Expand All @@ -113,7 +113,7 @@ pub fn call(app_state: &mut AppState, message: String, args: Vec<String>) {
Err(err) => app_state.print_error(&format!("Failed to call contract\n{err}")),
};

if let Some(info) = app_state.session.last_call_result() {
if let Some(info) = app_state.session.record().call_results().last() {
app_state.print(&format_contract_action(info))
}
}
Expand Down
85 changes: 23 additions & 62 deletions drink/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,21 @@ pub use contract_transcode;
use contract_transcode::ContractMessageTranscoder;
use frame_support::{traits::fungible::Inspect, weights::Weight};
use pallet_contracts::Determinism;
use pallet_contracts_primitives::{ContractExecResult, ContractInstantiateResult};
use parity_scale_codec::Decode;
pub use record::Record;

use crate::{
mock::MockRegistry,
runtime::{
pallet_contracts_debugging::{InterceptingExt, TracingExt},
AccountIdFor, HashFor, RuntimeWithContracts,
},
EventRecordOf, MockingExtension, Sandbox, DEFAULT_GAS_LIMIT,
MockingExtension, Sandbox, DEFAULT_GAS_LIMIT,
};

pub mod error;
pub mod mocking_api;
mod record;
mod transcoding;

use error::SessionError;
Expand Down Expand Up @@ -121,12 +122,12 @@ pub const NO_ENDOWMENT: Option<BalanceOf<MinimalRuntime>> = None;
/// # fn main() -> Result<(), drink::session::error::SessionError> {
/// // Simplest way, loading a bundle from the project's directory:
/// Session::<MinimalRuntime>::new()?
/// .deploy_bundle_and(local_contract_file!(), "new", NO_ARGS, NO_SALT, NO_ENDOWMENT); /* ... */
/// .deploy_bundle_and(local_contract_file!(), "new", NO_ARGS, NO_SALT, NO_ENDOWMENT)?; /* ... */
///
/// // Or choosing the file explicitly:
/// let contract = ContractBundle::load("path/to/your.contract")?;
/// Session::<MinimalRuntime>::new()?
/// .deploy_bundle_and(contract, "new", NO_ARGS, NO_SALT, NO_ENDOWMENT); /* ... */
/// .deploy_bundle_and(contract, "new", NO_ARGS, NO_SALT, NO_ENDOWMENT)?; /* ... */
/// # Ok(()) }
/// ```
pub struct Session<R: RuntimeWithContracts> {
Expand All @@ -137,11 +138,7 @@ pub struct Session<R: RuntimeWithContracts> {
determinism: Determinism,

transcoders: TranscoderRegistry<AccountIdFor<R>>,

deploy_results: Vec<ContractInstantiateResult<AccountIdFor<R>, BalanceOf<R>, EventRecordOf<R>>>,
deploy_returns: Vec<AccountIdFor<R>>,
call_results: Vec<ContractExecResult<BalanceOf<R>, EventRecordOf<R>>>,
call_returns: Vec<Vec<u8>>,
record: Record<R>,
mocks: Arc<Mutex<MockRegistry<AccountIdFor<R>>>>,
}

Expand All @@ -161,10 +158,7 @@ impl<R: RuntimeWithContracts> Session<R> {
gas_limit: DEFAULT_GAS_LIMIT,
determinism: Determinism::Enforced,
transcoders: TranscoderRegistry::new(),
deploy_results: vec![],
deploy_returns: vec![],
call_results: vec![],
call_returns: vec![],
record: Default::default(),
})
}

Expand Down Expand Up @@ -235,6 +229,11 @@ impl<R: RuntimeWithContracts> Session<R> {
&mut self.sandbox
}

/// Returns a reference to the record of the session.
pub fn record(&self) -> &Record<R> {
&self.record
}

/// Returns a reference for mocking API.
pub fn mocking_api(&mut self) -> &mut impl MockingApi<R> {
self
Expand Down Expand Up @@ -277,6 +276,7 @@ impl<R: RuntimeWithContracts> Session<R> {
.encode(constructor, args)
.map_err(|err| SessionError::Encoding(err.to_string()))?;

self.record.start_recording_events(&mut self.sandbox);
let result = self.sandbox.deploy_contract(
contract_bytes,
endowment.unwrap_or_default(),
Expand All @@ -286,14 +286,15 @@ impl<R: RuntimeWithContracts> Session<R> {
self.gas_limit,
None,
);
self.record.stop_recording_events(&mut self.sandbox);

let ret = match &result.result {
Ok(exec_result) if exec_result.result.did_revert() => {
Err(SessionError::DeploymentReverted)
}
Ok(exec_result) => {
let address = exec_result.account_id.clone();
self.deploy_returns.push(address.clone());
self.record.push_deploy_return(address.clone());

self.transcoders.register(address.clone(), transcoder);

Expand All @@ -302,7 +303,7 @@ impl<R: RuntimeWithContracts> Session<R> {
Err(err) => Err(SessionError::DeploymentFailed(*err)),
};

self.deploy_results.push(result);
self.record.push_deploy_result(result);
ret
}

Expand Down Expand Up @@ -437,7 +438,8 @@ impl<R: RuntimeWithContracts> Session<R> {
let address = match address {
Some(address) => address,
None => self
.deploy_returns
.record
.deploy_returns()
.last()
.ok_or(SessionError::NoContract)?
.clone(),
Expand All @@ -451,6 +453,7 @@ impl<R: RuntimeWithContracts> Session<R> {
.encode(message, args)
.map_err(|err| SessionError::Encoding(err.to_string()))?;

self.record.start_recording_events(&mut self.sandbox);
let result = self.sandbox.call_contract(
address,
endowment.unwrap_or_default(),
Expand All @@ -460,63 +463,21 @@ impl<R: RuntimeWithContracts> Session<R> {
None,
self.determinism,
);
self.record.stop_recording_events(&mut self.sandbox);

let ret = match &result.result {
Ok(exec_result) if exec_result.did_revert() => Err(SessionError::CallReverted),
Ok(exec_result) => {
let encoded = exec_result.data.clone();
self.call_returns.push(encoded.clone());

MessageResult::<T>::decode(&mut encoded.as_slice()).map_err(|err| {
SessionError::Decoding(format!(
"Failed to decode the result of calling a contract: {err:?}",
))
})
self.record.push_call_return(exec_result.data.clone());
self.record.last_call_return_decoded::<T>()
}
Err(err) => Err(SessionError::CallFailed(*err)),
};

self.call_results.push(result);
self.record.push_call_result(result);
ret
}

/// Returns the last result of deploying a contract.
pub fn last_deploy_result(
&self,
) -> Option<&ContractInstantiateResult<AccountIdFor<R>, BalanceOf<R>, EventRecordOf<R>>> {
self.deploy_results.last()
}

/// Returns the address of the last deployed contract.
pub fn last_deploy_return(&self) -> Option<AccountIdFor<R>> {
self.deploy_returns.last().cloned()
}

/// Returns the addresses of all deployed contracts in the order of deploying.
pub fn deployed_contracts(&self) -> Vec<AccountIdFor<R>> {
self.deploy_returns.clone()
}

/// Returns the last result of calling a contract.
pub fn last_call_result(&self) -> Option<&ContractExecResult<BalanceOf<R>, EventRecordOf<R>>> {
self.call_results.last()
}

/// Returns the last value (in the encoded form) returned from calling a contract.
///
/// Returns `None` if there has been no call yet.
pub fn last_call_raw_return(&self) -> Option<Vec<u8>> {
self.call_returns.last().cloned()
}

/// Returns the last value (in the decoded form) returned from calling a contract.
///
/// Returns `None` if there has been no call yet, or if decoding failed.
pub fn last_call_return<T: Decode>(&self) -> Option<MessageResult<T>> {
let raw = self.last_call_raw_return()?;
MessageResult::decode(&mut raw.as_slice()).ok()
}

/// Set the tracing extension
pub fn set_tracing_extension(&mut self, d: TracingExt) {
self.sandbox.register_extension(d);
Expand Down
Loading

0 comments on commit fab9dc7

Please sign in to comment.