mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-09 05:57:59 +00:00
Enable mocking contracts (#1331)
# Description This PR introduces two changes: - the previous `Tracing` trait has been modified to accept contract address instead of code hash (seems to be way more convenient) - a new trait `CallInterceptor` that allows intercepting contract calls; in particular the default implementation for `()` will just proceed in a standard way (after compilation optimizations, there will be no footprint of that); however, implementing type might decide to mock invocation and return `ExecResult` instead Note: one might try merging `before_call` and `intercept_call`. However, IMHO this would be bad, since it would mix two completely different abstractions - tracing without any effects and actual intervention into execution process. This will unblock working on mocking contracts utility in drink and similar tools (https://github.com/Cardinal-Cryptography/drink/issues/33) # Checklist - [x] My PR includes a detailed description as outlined in the "Description" section above - [ ] My PR follows the [labeling requirements](https://github.com/paritytech/polkadot-sdk/blob/master/docs/CONTRIBUTING.md#process) of this project (at minimum one label for `T` required) - [x] I have made corresponding changes to the documentation (if applicable) - [x] I have added tests that prove my fix is effective or that my feature works (if applicable)
This commit is contained in:
committed by
GitHub
parent
ef3adf9a01
commit
d8d90a82a7
@@ -15,14 +15,14 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
pub use crate::exec::ExportedFunction;
|
||||
use crate::{CodeHash, Config, LOG_TARGET};
|
||||
use pallet_contracts_primitives::ExecReturnValue;
|
||||
pub use crate::exec::{ExecResult, ExportedFunction};
|
||||
use crate::{Config, LOG_TARGET};
|
||||
pub use pallet_contracts_primitives::ExecReturnValue;
|
||||
|
||||
/// Umbrella trait for all interfaces that serves for debugging.
|
||||
pub trait Debugger<T: Config>: Tracing<T> {}
|
||||
pub trait Debugger<T: Config>: Tracing<T> + CallInterceptor<T> {}
|
||||
|
||||
impl<T: Config, V> Debugger<T> for V where V: Tracing<T> {}
|
||||
impl<T: Config, V> Debugger<T> for V where V: Tracing<T> + CallInterceptor<T> {}
|
||||
|
||||
/// Defines methods to capture contract calls, enabling external observers to
|
||||
/// measure, trace, and react to contract interactions.
|
||||
@@ -37,11 +37,11 @@ pub trait Tracing<T: Config> {
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `code_hash` - The code hash of the contract being called.
|
||||
/// * `contract_address` - The address of the contract that is about to be executed.
|
||||
/// * `entry_point` - Describes whether the call is the constructor or a regular call.
|
||||
/// * `input_data` - The raw input data of the call.
|
||||
fn new_call_span(
|
||||
code_hash: &CodeHash<T>,
|
||||
contract_address: &T::AccountId,
|
||||
entry_point: ExportedFunction,
|
||||
input_data: &[u8],
|
||||
) -> Self::CallSpan;
|
||||
@@ -60,8 +60,12 @@ pub trait CallSpan {
|
||||
impl<T: Config> Tracing<T> for () {
|
||||
type CallSpan = ();
|
||||
|
||||
fn new_call_span(code_hash: &CodeHash<T>, entry_point: ExportedFunction, input_data: &[u8]) {
|
||||
log::trace!(target: LOG_TARGET, "call {entry_point:?} hash: {code_hash:?}, input_data: {input_data:?}")
|
||||
fn new_call_span(
|
||||
contract_address: &T::AccountId,
|
||||
entry_point: ExportedFunction,
|
||||
input_data: &[u8],
|
||||
) {
|
||||
log::trace!(target: LOG_TARGET, "call {entry_point:?} account: {contract_address:?}, input_data: {input_data:?}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,3 +74,37 @@ impl CallSpan for () {
|
||||
log::trace!(target: LOG_TARGET, "call result {output:?}")
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides an interface for intercepting contract calls.
|
||||
pub trait CallInterceptor<T: Config> {
|
||||
/// Allows to intercept contract calls and decide whether they should be executed or not.
|
||||
/// If the call is intercepted, the mocked result of the call is returned.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `contract_address` - The address of the contract that is about to be executed.
|
||||
/// * `entry_point` - Describes whether the call is the constructor or a regular call.
|
||||
/// * `input_data` - The raw input data of the call.
|
||||
///
|
||||
/// # Expected behavior
|
||||
///
|
||||
/// This method should return:
|
||||
/// * `Some(ExecResult)` - if the call should be intercepted and the mocked result of the call
|
||||
/// is returned.
|
||||
/// * `None` - otherwise, i.e. the call should be executed normally.
|
||||
fn intercept_call(
|
||||
contract_address: &T::AccountId,
|
||||
entry_point: &ExportedFunction,
|
||||
input_data: &[u8],
|
||||
) -> Option<ExecResult>;
|
||||
}
|
||||
|
||||
impl<T: Config> CallInterceptor<T> for () {
|
||||
fn intercept_call(
|
||||
_contract_address: &T::AccountId,
|
||||
_entry_point: &ExportedFunction,
|
||||
_input_data: &[u8],
|
||||
) -> Option<ExecResult> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user