Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Metadata V15: Add Runtime API metadata #13302

Merged
merged 84 commits into from
Apr 11, 2023

Conversation

lexnv
Copy link
Contributor

@lexnv lexnv commented Feb 2, 2023

This PR collects the runtime API information for the metadata V15 and
exposes the metadata under metadata_at_version(u32::MAX).

Considering both sp-api and frame-support crates need access to the
metadata_ir (an intermediate representation of the metadata that can be converted
into multiple metadata versions), and frame-support depends on sp-api, the
metadata_ir has been moved to sp-api.

Implementation Details

decl_runtime_apis

Collects the runtime metadata of each declared trait using the metadata IR
and exposes the runtime_metadata. The collection of the metadata happens
at this stage because it preserves trait and method documentation, as well as
method parameter names.

mod runtime_decl_for_core {
	// Metadata collected for the `Core` trait. 
	pub fn runtime_metadata<Block, ...>() -> RuntimeApiMetadataIR {
		...
	}
}

impl_runtime_apis

This is the stage at which we definitely know which runtime traits are implemented for
the given Runtime. The macro collects all the RuntimeApiMetadataIR by calling
runtime_metadata of each trait.
The runtime_metadata function is exposed using the InternalImplRuntimeApis trait.

trait InternalImplRuntimeApis {
	fn runtime_metadata(&self) -> vec<RuntimeApiMetadataIR> {
		...
	}
}
impl InternalImplRuntimeApis for Runtime {}

InternalImplRuntimeApis and InternalConstructRuntime

There are many tests that use independently just the impl_runtime_apis or just construct_runtime.
However, only the impl_runtime_apis has access to the runtime metadata API.

To avoid a breaking change, the following behavior is desired:

  • when only construct_runtime is used a runtime_metadata method should return an empty runtime metadata API
  • when construct_runtime and impl_runtime_apis are used together, the runtime_metadata method should be deduced from the impl_runtime_apis macro

This is indeed the behavior exposed by rust unstable specialization: rust-lang/rust#31844 feature.

One way of circumventing this is by introducing 2 traits

trait InternalImplRuntimeApis {
	fn runtime_metadata(&self) -> vec<RuntimeApiMetadataIR> {
                actual_metadata 
	}
}

trait InternalConstructRuntime {
	fn runtime_metadata(&self) -> vec<RuntimeApiMetadataIR> {
                vec![ ]
	}
}

impl_runtime_apis implements InternalImplRuntimeApis on the Runtime itself (strongest pick by the compiler for runtime_metadata() fn). While construct_runtime implements InternalConstructRuntime on the & Runtime.

Using the Deref guarantees, if we are only using construct_runtime: the runtime will return an empty runtime metadata (avoid breaking change). Otherwise, when implementing both traits the runtime_metadata is deduced to be part of the InternalImplRuntimeApis that contains the complete runtime metadata API.

construct_runtime

This macro puts together the metadata IR and implements the InternalConstructRuntime for avoiding breaking changes.

trait InternalConstructRuntime {
	#[inline(always)]
	fn runtime_metadata(&self) ->vec<TraitMetadata> {
		...
	}
}

// Implemented for &Runtime - lower priority than InternalImplRuntimeApis
impl InternalConstructRuntime for & Runtime {}
let rt = Runtime;
let runtime_md = (&rt).runtime_metadata();

Part of: #12939.

Testing Done

Frame-metadata PR: paritytech/frame-metadata#48
Subxt PoC branch for generating the runtime interface subxt/lexnv/metadata_v15, example from subxt/lexnv/runtime_calls

    // Subxt PoC
    
    // Build payload
    let api_tx = polkadot::runtime_api::Metadata::metadata_versions();
    // Submit payload
    let bytes = api.runtime_api().at(None).await?.call(api_tx).await?;
    println!("Metadata::metadata_versions: {:?}", bytes);

    // Build payload
    let alice = AccountKeyring::Alice.to_account_id().into();
    let api_tx = polkadot::runtime_api::AccountNonceApi::account_nonce(alice);
    // Submit payload
    let bytes = api.runtime_api().at(None).await?.call(api_tx).await?;
    println!("AccountNonceApi::account_nonce: {:?}", bytes);

Runtime API metadata extracted from substrate for the Metadata trait:

RuntimeApiMetadata {
    name: "Metadata",
    methods: [
        RuntimeApiMethodMetadata {
            name: "metadata",
            inputs: [],
            output: UntrackedSymbol {
                id: 782,
                marker: PhantomData<fn() -> core::any::TypeId>,
            },
            docs: [
                " Returns the metadata of a runtime.",
            ],
        },
        RuntimeApiMethodMetadata {
            name: "metadata_at_version",
            inputs: [
                RuntimeApiMethodParamMetadata {
                    name: "version",
                    ty: UntrackedSymbol {
                        id: 4,
                        marker: PhantomData<fn() -> core::any::TypeId>,
                    },
                },
            ],
            output: UntrackedSymbol {
                id: 783,
                marker: PhantomData<fn() -> core::any::TypeId>,
            },
            docs: [
                " Returns the metadata at a given version.",
                "",
                " If the given `version` isn't supported, this will return `None`.",
                " Use [`Self::metadata_versions`] to find out about supported metadata version of the runtime.",
            ],
        },
        RuntimeApiMethodMetadata {
            name: "metadata_versions",
            inputs: [],
            output: UntrackedSymbol {
                id: 105,
                marker: PhantomData<fn() -> core::any::TypeId>,
            },
            docs: [
                " Returns the supported metadata versions.",
                "",
                " This can be used to call `metadata_at_version`.",
            ],
        },
    ],
    docs: [
        " The `Metadata` api trait that returns metadata for the runtime.",
    ],
}

Next Steps

  • Expose documentation under docs flag similar to frame
  • Adjust and add testing for the new metadata
  • Construct runtime metadata entirely in decl_runtime_api (poc commit)
  • Avoid breaking changes by abusing Deref (poc commit)

cumulus companion: paritytech/cumulus#2357

cc @paritytech/subxt-team

lexnv and others added 18 commits January 30, 2023 16:46
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
@github-actions github-actions bot added the A0-please_review Pull request needs code review. label Feb 2, 2023
@lexnv lexnv changed the base branch from master to lexnv/md15_expose_md_at_versions February 2, 2023 17:55
@lexnv lexnv self-assigned this Feb 2, 2023
@lexnv lexnv added B3-apinoteworthy D2-notlive 💤 PR contains changes in a runtime directory that is not deployed to a chain that requires an audit. D3-trivial 🧸 PR contains trivial changes in a runtime directory that do not require an audit C1-low PR touches the given topic and has a low impact on builders. and removed D2-notlive 💤 PR contains changes in a runtime directory that is not deployed to a chain that requires an audit. labels Feb 2, 2023
lexnv added 4 commits February 3, 2023 14:42
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Copy link
Member

@bkchr bkchr left a comment

Choose a reason for hiding this comment

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

Thank you! Nice work! :)

lexnv and others added 4 commits March 30, 2023 17:49
Co-authored-by: Bastian Köcher <git@kchr.de>
Co-authored-by: Bastian Köcher <git@kchr.de>
Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
@lexnv
Copy link
Contributor Author

lexnv commented Apr 10, 2023

bot rebase

@paritytech-processbot
Copy link

Rebased

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
@lexnv
Copy link
Contributor Author

lexnv commented Apr 11, 2023

bot merge

@paritytech-processbot paritytech-processbot bot merged commit 416b0f5 into master Apr 11, 2023
@paritytech-processbot paritytech-processbot bot deleted the lexnv/md15_runtime_api_v1 branch April 11, 2023 11:07
@Polkadot-Forum
Copy link

This pull request has been mentioned on Polkadot Forum. There might be relevant details there:

https://forum.polkadot.network/t/april-updates-for-substrate-and-polkadot-devs/2764/1

@Polkadot-Forum
Copy link

This pull request has been mentioned on Polkadot Forum. There might be relevant details there:

https://forum.polkadot.network/t/stablising-v15-metadata/2819/1

@lexnv lexnv mentioned this pull request Jun 29, 2023
AurevoirXavier added a commit to darwinia-network/darwinia that referenced this pull request Jul 11, 2023
nathanwhit pushed a commit to nathanwhit/substrate that referenced this pull request Jul 19, 2023
* impl_runtime_apis: Generate getters for `metadata_at` functions

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* runtime: Implement new `Metadata` runtime trait

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* runtime: Move `metadata_at` functions to construct_runtime macro

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* contruct_runtime: Use `OpaqueMetadata` from hidden imports

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* Adjust testing

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* frame/tests: Add tests for the new API

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* primitives/proc-macro: Helper to extract documentation literals

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* primitives/proc-macro: Helper to filter all `cfg` attributes

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* primitives/proc-macro: Generate documentation getters for metadata

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* primitives/proc-macro: Avoid trait collision with snake case methods

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* proc-macro/tests: Check doc getters

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* primitives/proc-macro: Generate metadata for runtime methods

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* primitives/api: Export scale-info and frame-metadata

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* primitives/proc-macro: Generate metadata for runtime traits

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* frame/runtime: Expose metadata v15 internally

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* test: Use metadata v15 from `lexnv/md_v15_test` branch

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* primitives/proc-macro: Generate crate access one module up

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* frame: Implement `runtime_metadata` for mocks and tests

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* primitives/proc-macro: Fix warnings

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* primitives/proc-macro: Add no-docs flag

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* frame: Adjust more tests

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* frame/tests: Check runtime metadata correctness

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* frame/benchmarking: Adjust benchmarks

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* frame/benchmarks: Adjust more benchmarks

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* primitives/api: Fix clippy

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* primitives/proc-macro: Generate runtime metadata on the `decl_runtime_apis`

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* frame: Abuse Deref to resolve `runtime_metadata`

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* Revert "frame: Implement `runtime_metadata` for mocks and tests"

This reverts commit e4782de.

Revert "frame: Adjust more tests"

This reverts commit de1352c.

Revert "frame/benchmarking: Adjust benchmarks"

This reverts commit ae85bbe.

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

Revert "frame/benchmarks: Adjust more benchmarks"

This reverts commit d37aa22.

* primitives/proc-macro: Remove unused imports and function

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* frame/support: Adjust runtime metadata test

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* primitives/tests: Remove doc getter test

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* frame/support: Enable `no-metadata-docs` feature from `sp-api`

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* primitives/tests: Add `TypeInfo` for test::extrinsic

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* primitives/api: Expose scale-info and frame-metadata

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* Update frame-metadata to include v15

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* Fix merge conflicts

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* frame/metadata_ir: Add IR for runtime API metadata

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* frame/metadata_ir: Convert IR to V15

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* primitives/api: Collect IR metadata for runtime API

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* primitives/api: Move `metadata_ir` from frame/support

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* frame/tests: Adjust testing

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* frame/tests: Adjust `metadata_versions` test

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* primitives/runtime_metadata: Exclude default type parameters from methods

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* Update primitives/api/proc-macro/src/runtime_metadata.rs

Co-authored-by: Bastian Köcher <git@kchr.de>

* Update primitives/api/src/metadata_ir/types.rs

Co-authored-by: Bastian Köcher <git@kchr.de>

* Update primitives/api/src/metadata_ir/mod.rs

Co-authored-by: Bastian Köcher <git@kchr.de>

* Update primitives/api/proc-macro/src/utils.rs

Co-authored-by: Bastian Köcher <git@kchr.de>

* Update primitives/api/proc-macro/src/runtime_metadata.rs

Co-authored-by: Bastian Köcher <git@kchr.de>

* Update primitives/api/proc-macro/src/runtime_metadata.rs

Co-authored-by: Bastian Köcher <git@kchr.de>

* Update primitives/api/proc-macro/src/runtime_metadata.rs

Co-authored-by: Bastian Köcher <git@kchr.de>

* Update primitives/api/proc-macro/src/runtime_metadata.rs

Co-authored-by: Bastian Köcher <git@kchr.de>

* Update primitives/api/proc-macro/src/runtime_metadata.rs

Co-authored-by: Bastian Köcher <git@kchr.de>

* Update primitives/api/proc-macro/src/runtime_metadata.rs

Co-authored-by: Bastian Köcher <git@kchr.de>

* primitives: Fix build

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* primitives/metadata-ir: Move IR to dedicated crate

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* primitives: Reexport metadata-ir and frame-metadata

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* frame: Use apis field instead of runtime

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* Better documentation for the `Deref` abstraction

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* ui-tests: Check empty `impl_runtime_apis`

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* primitives: Remove unneeded bounds on generic params

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* primitives: Rename `collect_where_bounds` to `get_argument_type_param`

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* primitives: Generate crate access per fn call

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* Revert "primitives: Remove unneeded bounds on generic params"

This reverts commit 5178e38.

* metadata-ir: Add no-std

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* primitives: Adjust where bounds

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* Change `frame-metadata` branch to "origin/main"

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* Update to `main` from origin

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* Update frame-metadata to crates.io v15.1

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* Revert "ui-tests: Check empty `impl_runtime_apis`"

This reverts commit cf78a71.

* Move ui test to primitives/ui

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* Update frame/support/test/tests/runtime_metadata.rs

Co-authored-by: Bastian Köcher <git@kchr.de>

* Update primitives/api/proc-macro/src/runtime_metadata.rs

Co-authored-by: Bastian Köcher <git@kchr.de>

* Test already covered by `empty_impl_runtime_apis_call.stderr`

This reverts commit 3bafb29.

* Retriger CI

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

* Import `TokenStream` as `TokenStream2`

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>

---------

Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
Co-authored-by: parity-processbot <>
Co-authored-by: Bastian Köcher <git@kchr.de>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
A0-please_review Pull request needs code review. B1-note_worthy Changes should be noted in the release notes C1-low PR touches the given topic and has a low impact on builders. D3-trivial 🧸 PR contains trivial changes in a runtime directory that do not require an audit T1-runtime This PR/Issue is related to the topic “runtime”.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants