3

Polkadot is capable of allowing you to defining the native runtimes you want included within the final node binary (with flags like polkadot-native, kusama-native and so on..). Attempting to port the ability to do something similar has resulted with an odd problem.

When building with enable-runtime-one or enable-runtime-two (the equivalent flags in the codebase I'm working on), the code is successfully able to compile but attempting to compile with both flags seems to cause overlapping symbols.

  error: symbol `AccountNonceApi_account_nonce` is already defined
      --> /src/runtime/runtime/src/runtime/lib.rs:1281:1
       |
  1281 | / sp_api::impl_runtime_apis! {
  1282 | |     impl sp_api::Core<Block> for Runtime {
  1283 | |         fn version() -> RuntimeVersion {
  1284 | |             VERSION
  ...    |
  1539 | |     }
  1540 | | }
       | |_^
       |
       = note: this error originates in the macro `sp_api::impl_runtime_apis` (in Nightly builds, run with -Z macro-backtrace for more info)

Now, I don't see any deduplication between Polkadot, Kusama or Westend's runtime logic. I initially thought that perhaps I could deduplicate it by placing it in the common runtime but that causes more problems than solving them.

How do I resolve the problem with repeating symbols (and I've tried just removing the symbol from one and keeping the other and the errors it has given me seem to indicate that it's a bad idea)

As for additional information, the codebase is built upon the polkadot-v0.9.15-1 branch using Rust stable 1.57 and WASM nightly 2021-11-29.

2
  • Can you paste a link to a repo in which this error can be reproduced? also, looking at the error, it seems to me like you are using the same frame macros, such as construct_runtime in the same scope, i.e. in the same file, and they are not designed to be used like that. If so, try separating these feature-gated runtimes into separate modules or crates, similar to polkadot, kusama and westend crates of the polkadot repo.
    – kianenigma
    Mar 29, 2022 at 9:53
  • They were already placed into separate, feature gated modules but they were within the same crate, so naturally the next layer of separation was distinct crates and once I refactored it, things started to work! Mar 30, 2022 at 4:47

2 Answers 2

2

You can not combine two runtimes into one wasm binary. The problem is the runtime api. The runtime api exposes its functions as extern "C" functions. As both of your runtimes probably implement the same runtime apis like Core, you are defining the same exported functions multiple times.

For Polkadot/Kusama/Westend they all are compiled into individual wasm binaries. The features you have mentioned e.g. polkadot-native already contain the "native" in their name. Native here means the native runtime and for the native runtime we don't expose these extern "C" functions and thus, don't have these problems in Polkadot.

0

Each client for the different networks are behind feature flags in the Polkadot repo. Take a look at:

polkadot/cli/Cargo.toml

# Configure the native runtimes to use. Polkadot is enabled by default.
#
# Validators require the native runtime currently
polkadot-native = ["service/polkadot-native"]
kusama-native = ["service/kusama-native"]
westend-native = ["service/westend-native"]
rococo-native = ["service/rococo-native"]

Then you can see feature gated code all over the repo like this:

fn native_runtime_version(spec: &Box<dyn service::ChainSpec>) -> &'static RuntimeVersion {
    #[cfg(feature = "kusama-native")]
    if spec.is_kusama() {
        return &service::kusama_runtime::VERSION
    }

    #[cfg(feature = "westend-native")]
    if spec.is_westend() {
        return &service::westend_runtime::VERSION
    }

    #[cfg(feature = "rococo-native")]
    if spec.is_rococo() || spec.is_wococo() || spec.is_versi() {
        return &service::rococo_runtime::VERSION
    }

    #[cfg(not(all(
        feature = "rococo-native",
        feature = "westend-native",
        feature = "kusama-native"
    )))]
    let _ = spec;

    #[cfg(feature = "polkadot-native")]
    {
        return &service::polkadot_runtime::VERSION
    }

    #[cfg(not(feature = "polkadot-native"))]
    panic!("No runtime feature (polkadot, kusama, westend, rococo) is enabled")
}

As Basti has mentioned, you should make sure things like the runtime-api are only compiled once per runtime.

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.