mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 09:51:10 +00:00
contracts: Add host function tracing (#13648)
This commit is contained in:
@@ -135,6 +135,18 @@ to `error` in order to prevent them from spamming the console.
|
||||
`--dev`: Use a dev chain spec
|
||||
`--tmp`: Use temporary storage for chain data (the chain state is deleted on exit)
|
||||
|
||||
## Host function tracing
|
||||
|
||||
For contract authors, it can be a helpful debugging tool to see which host functions are called, with which arguments, and what the result was.
|
||||
|
||||
In order to see these messages on the node console, the log level for the `runtime::contracts::strace` target needs to be raised to the `trace` level.
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
cargo run --release -- --dev -lerror,runtime::contracts::strace=trace,runtime::contracts=debug
|
||||
```
|
||||
|
||||
## Unstable Interfaces
|
||||
|
||||
Driven by the desire to have an iterative approach in developing new contract interfaces
|
||||
|
||||
@@ -596,6 +596,7 @@ fn expand_functions(def: &EnvDef, expand_blocks: bool, host_state: TokenStream2)
|
||||
let impls = def.host_funcs.iter().map(|f| {
|
||||
// skip the context and memory argument
|
||||
let params = f.item.sig.inputs.iter().skip(2);
|
||||
|
||||
let (module, name, body, wasm_output, output) = (
|
||||
f.module(),
|
||||
&f.name,
|
||||
@@ -606,6 +607,39 @@ fn expand_functions(def: &EnvDef, expand_blocks: bool, host_state: TokenStream2)
|
||||
let is_stable = f.is_stable;
|
||||
let not_deprecated = f.not_deprecated;
|
||||
|
||||
// wrapped host function body call with host function traces
|
||||
// see https://github.com/paritytech/substrate/tree/master/frame/contracts#host-function-tracing
|
||||
let wrapped_body_with_trace = {
|
||||
let trace_fmt_args = params.clone().filter_map(|arg| match arg {
|
||||
syn::FnArg::Receiver(_) => None,
|
||||
syn::FnArg::Typed(p) => {
|
||||
match *p.pat.clone() {
|
||||
syn::Pat::Ident(ref pat_ident) => Some(pat_ident.ident.clone()),
|
||||
_ => None,
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
let params_fmt_str = trace_fmt_args.clone().map(|s| format!("{s}: {{:?}}")).collect::<Vec<_>>().join(", ");
|
||||
let trace_fmt_str = format!("{}::{}({}) = {{:?}}\n", module, name, params_fmt_str);
|
||||
|
||||
quote! {
|
||||
if ::log::log_enabled!(target: "runtime::contracts::strace", ::log::Level::Trace) {
|
||||
let result = #body;
|
||||
{
|
||||
use sp_std::fmt::Write;
|
||||
let mut w = sp_std::Writer::default();
|
||||
let _ = core::write!(&mut w, #trace_fmt_str, #( #trace_fmt_args, )* result);
|
||||
let msg = core::str::from_utf8(&w.inner()).unwrap_or_default();
|
||||
ctx.ext().append_debug_buffer(msg);
|
||||
}
|
||||
result
|
||||
} else {
|
||||
#body
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// If we don't expand blocks (implementing for `()`) we change a few things:
|
||||
// - We replace any code by unreachable!
|
||||
// - Allow unused variables as the code that uses is not expanded
|
||||
@@ -617,7 +651,7 @@ fn expand_functions(def: &EnvDef, expand_blocks: bool, host_state: TokenStream2)
|
||||
.memory()
|
||||
.expect("Memory must be set when setting up host data; qed")
|
||||
.data_and_store_mut(&mut __caller__);
|
||||
#body
|
||||
#wrapped_body_with_trace
|
||||
} }
|
||||
} else {
|
||||
quote! { || -> #wasm_output {
|
||||
|
||||
@@ -84,6 +84,7 @@ enum KeyType {
|
||||
/// will not be changed or removed. This means that any contract **must not** exhaustively
|
||||
/// match return codes. Instead, contracts should prepare for unknown variants and deal with
|
||||
/// those errors gracefully in order to be forward compatible.
|
||||
#[derive(Debug)]
|
||||
#[repr(u32)]
|
||||
pub enum ReturnCode {
|
||||
/// API call successful.
|
||||
|
||||
Generated
+911
-907
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user