5

I am struggling with #[runtime_interface] the whole day. here is the Runtime Interface Trait Defination, the expanded macro is too long to paste here, here is a expanded macro. I have lots of questions here.

This interface is callable from a native and a wasm runtime. The macro will generate the corresponding code for the native implementation and the code for calling from the wasm side to the native implementation.

What I understand here(If wrong, please correct me):

  1. This HostFunction will be registered in the executor, this belongs to the node side.
pub struct HostFunctions;
impl proc_macro_runtime_interface::sp_wasm_interface::HostFunctions for HostFunctions{...}
  1. I do not know what &mut dyn proc_macro_runtime_interface::Externalities is, but I guess this is for the runtime side. Can somebody explain how to understand the Externalities here?
#[cfg(feature = "std")]
impl DvmExt for &mut dyn proc_macro_runtime_interface::Externalities {...}
  1. Other generated code(part of it). I guess this is the code for calling from the wasm side to the native implementation. I noticed that this function uses proc_macro_runtime_interface::with_externalities(...) and I found Use sp_externalities::with_externalities. But, I am still don't know how this function call from wasm side to the native side.
#[cfg(feature = "std")]
/// An `Evm` event proxied by the runtime to this host function.
/// evm -> runtime -> host.
fn evm_event_version_1(event: Vec<u8>) {
   {
       use ::tracing::__macro_support::Callsite as _;
       static CALLSITE: ::tracing::__macro_support::MacroCallsite = {
           use ::tracing::__macro_support::MacroCallsite;
           static META: ::tracing::Metadata<'static> = {
               ::tracing_core::metadata::Metadata::new(
                   "evm_event_version_1",
                   "dp_evm_trace_ext::dvm_ext",
                   ::tracing::Level::TRACE,
                   Some("primitives/evm-trace/ext/src/lib.rs"),
                   Some(31u32),
                   Some("dp_evm_trace_ext::dvm_ext"),
                   ::tracing_core::field::FieldSet::new(
                       &[],
                       ::tracing_core::callsite::Identifier(&CALLSITE),
                   ),
                   ::tracing::metadata::Kind::SPAN,
               )
           };
           MacroCallsite::new(&META)
       };
       let mut interest = ::tracing::subscriber::Interest::never();
       if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
           && ::tracing::Level::TRACE <= ::tracing::level_filters::LevelFilter::current()
           && {
               interest = CALLSITE.interest();
               !interest.is_never()
           }
           && CALLSITE.is_enabled(interest)
       {
           let meta = CALLSITE.metadata();
           ::tracing::Span::new(meta, &{ meta.fields().value_set(&[]) })
       } else {
           let span = CALLSITE.disabled_span();
           {};
           span
       }
   }
   .in_scope(|| {
       proc_macro_runtime_interface::with_externalities(|mut __externalities__| {
           DvmExt::evm_event_version_1(&mut __externalities__, event)
       })
       .expect("`evm_event_version_1` called outside of an Externalities-provided environment.")
   })
}
  1. After all the above things are done. What is the common way to call from the wasm side to the native side or the native side to the wasm side? Is there any example for beginners to understand?

1 Answer 1

4

In general, it is not advised to look at the output of any macro at all, if you are not developing it ;) If there are questions that you want to know specifically or if the docs are missing information, I would encourage you to open an issue on github. Did you take a look at the docs of the macro? These docs explain what the macro is doing and also show code for the individual steps. Nevertheless, I will answer you your questions.

  1. This HostFunction will be registered in the executor, this belongs to the node side.

Yes that is correct.

  1. I do not know what &mut dyn proc_macro_runtime_interface::Externalities is, but I guess this is for the runtime side. Can somebody explain how to understand the Externalities here?

In general everything that is behind the #[cfg(feature = "std")] feature flag means that it is on the host side. As you are declaring the runtime interface as trait, this trait with some changes to the signatures is used to implement it for &mut dyn proc_macro_runtime_interface::Externalities. Externalities is again a trait that is provided by Substrate. This trait mainly provides functionality for interacting with the storage, e.g. it provides the functions to get/set storage. You can find the trait declaration here. The Externalities also provides access to extensions that are registered in the node. These extensions for example provide access to the key store etc.

  1. Other generated code(part of it). I guess this is the code for calling from the wasm side to the native implementation. I noticed that this function uses proc_macro_runtime_interface::with_externalities(...) and I found Use sp_externalities::with_externalities. But, I am still don't know how this function call from wasm side to the native side.

The code you have shown there again is the code that is being part of the host side. This specific code is the one that prepares the context to execute the actual implementation. The important part of this function is calling the with_externalities. The Externalities are being set in a thread local variable before we execute any runtime functionality and you get access to this thread local variable using with_externalities. When it comes to the wasm side, there is a extern "C" function declared for each trait method. There is a "decorator" function that uses the same function signature as the trait method and that will be the one you are calling. This function the internally calls the extern "C" function and this lands then on the host side. On the host side you convert the arguments given to the function back to the correct rust types and then call the host side implementation.

  1. After all the above things are done. What is the common way to call from the wasm side to the native side or the native side to the wasm side? Is there any example for beginners to understand?

You just need to call dvm_ext::evm_event(events).

In general calling from wasm to host side is done using the runtime interface. The other way around, host to wasm, uses the runtime api.

1
  • Maybe you can answer this. I'm looking at how offchain_indexing_enabeld is used specifically, when I see BasicExternalities, I see the set_offchain_storage function is unimplemented. So wondering where I can find the actual implementation of set_offchain_storage and how offchain_indexing_enabeld flag changes the behavior
    – vedhavyas
    Commented Jan 26 at 7:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.