Runtime APIs are declared using the decl_runtime_api! macro. This is typically in a primitives crate. For example:

decl_runtime_apis! {
    pub trait ExampleApi {
        fn get_info(param1: u32, param2: u32) -> bool;

Then they are implemented with the impl_runtime_api! macro. This is in the Runtime. Continuing the example:

impl_runtime_apis! {
    impl ExampleApi<Block> for Runtime {
        fn get_info(param1: u32, param2: u32) -> bool {
            param1 == param2

Finally, they can be called from client side. Here there are no macros used, but there is an additional parameter for the block at which the call should be made. Completing the example:

let block_to_call_at = BlockId::Hash(parent.hash());
client.runtime_api().get_info(&block_to_call_at, 5, 10)

Question: Where is the machinery that handles the block height parameter, and passes the remaining parameters into the wasm runtime? Is this handled in the macros? When writing a runtime in a non-Rust language, does one need to reproduce any logic from the macros?

1 Answer 1


The block hash is for client-side rather than the runtime itself - it tells the client to invoke the runtime API using the post-state of the given block hash. The way this manifests is in how the client, which hosts the runtime, answers host functions called by the runtime Wasm as it executes. Most notably, it affects the host functions pertaining to storage. The client also selects and executes the runtime Wasm code which was available as-of the post-state of the given block.

The actual generated Wasm ABI for the runtime API functions doesn't accept the block hash as a parameter. This means that if you write a runtime without using FRAME, it will still be compatible with the Substrate client's runtime API system as long as the ABI of the exposed functions is consistent.

The impl_runtime_apis macro also implements ProvideRuntimeApis for the Client, when the runtime is compiled for native and linked into the node binary itself. This internal implementation detail is likely to change when the native runtime is no longer required by Substrate. Currently, it generates a wrapper around anything which implements CallApiAt, which is a trait implemented for every Client.

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.