Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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());
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't address a Copy type?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nope, we are relying on the trait bounds from frame_system which do not impose Copy


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