diff --git a/macro/src/wasm_loader.rs b/macro/src/wasm_loader.rs
index f8be106dce..24b261419e 100644
--- a/macro/src/wasm_loader.rs
+++ b/macro/src/wasm_loader.rs
@@ -4,7 +4,7 @@
use std::{borrow::Cow, path::Path};
-use codec::Decode;
+use codec::{Decode, Encode};
use polkadot_sdk::{
sc_executor::{self, WasmExecutionMethod, WasmExecutor},
sc_executor_common::runtime_blob::RuntimeBlob,
@@ -14,6 +14,8 @@ use polkadot_sdk::{
};
use subxt_codegen::{CodegenError, Metadata};
+static SUPPORTED_METADATA_VERSIONS: [u32; 2] = [14, 15];
+
/// Result type shorthand
pub type WasmMetadataResult = Result;
@@ -26,26 +28,18 @@ pub fn from_wasm_file(wasm_file_path: &Path) -> WasmMetadataResult {
}
fn call_and_decode(wasm_file: Vec) -> WasmMetadataResult {
- let mut ext: sp_state_machine::BasicExternalities = Default::default();
+ let mut executor = Executor::new(&wasm_file)?;
- let executor: WasmExecutor = WasmExecutor::builder()
- .with_execution_method(WasmExecutionMethod::default())
- .with_offchain_heap_alloc_strategy(sc_executor::HeapAllocStrategy::Dynamic {
- maximum_pages: Some(64),
- })
- .with_max_runtime_instances(1)
- .with_runtime_cache_size(1)
- .build();
+ if let Ok(versions) = executor.versions() {
+ let version = versions
+ .into_iter()
+ .max()
+ .expect("This is checked earlier and can't fail.");
- let runtime_blob =
- RuntimeBlob::new(&wasm_file).map_err(|e| CodegenError::Wasm(e.to_string()))?;
- let metadata_encoded = executor
- .uncached_call(runtime_blob, &mut ext, true, "Metadata_metadata", &[])
- .map_err(|_| CodegenError::Wasm("method \"Metadata_metadata\" doesnt exist".to_owned()))?;
-
- let metadata = >::decode(&mut &metadata_encoded[..]).map_err(CodegenError::Decode)?;
-
- decode(metadata)
+ executor.load_metadata_at_version(version)
+ } else {
+ executor.load_legacy_metadata()
+ }
}
fn decode(encoded_metadata: Vec) -> WasmMetadataResult {
@@ -57,3 +51,106 @@ fn maybe_decompress(file_contents: Vec) -> WasmMetadataResult> {
.map_err(|e| CodegenError::Wasm(e.to_string()))
.map(Cow::into_owned)
}
+
+struct Executor {
+ runtime_blob: RuntimeBlob,
+ executor: WasmExecutor,
+ externalities: sp_state_machine::BasicExternalities,
+}
+
+impl Executor {
+ fn new(wasm_file: &[u8]) -> WasmMetadataResult {
+ let externalities: sp_state_machine::BasicExternalities = Default::default();
+
+ let executor: WasmExecutor = WasmExecutor::builder()
+ .with_execution_method(WasmExecutionMethod::default())
+ .with_offchain_heap_alloc_strategy(sc_executor::HeapAllocStrategy::Dynamic {
+ maximum_pages: Some(64),
+ })
+ .with_max_runtime_instances(1)
+ .with_runtime_cache_size(1)
+ .build();
+
+ let runtime_blob =
+ RuntimeBlob::new(wasm_file).map_err(|e| CodegenError::Wasm(e.to_string()))?;
+
+ Ok(Self {
+ runtime_blob,
+ executor,
+ externalities,
+ })
+ }
+
+ fn versions(&mut self) -> WasmMetadataResult> {
+ let version = self
+ .executor
+ .uncached_call(
+ self.runtime_blob.clone(),
+ &mut self.externalities,
+ true,
+ "Metadata_metadata_versions",
+ &[],
+ )
+ .map_err(|_| {
+ CodegenError::Wasm("method \"Metadata_metadata_versions\" doesnt exist".to_owned())
+ })?;
+ let versions = >::decode(&mut &version[..])
+ .map_err(CodegenError::Decode)
+ .map(|x| {
+ x.into_iter()
+ .filter(|version| SUPPORTED_METADATA_VERSIONS.contains(version))
+ .collect::>()
+ })?;
+
+ if versions.is_empty() {
+ return Err(CodegenError::Other(
+ "No supported metadata versions were returned".to_owned(),
+ ));
+ }
+
+ Ok(versions)
+ }
+
+ fn load_legacy_metadata(&mut self) -> WasmMetadataResult {
+ let encoded_metadata = self
+ .executor
+ .uncached_call(
+ self.runtime_blob.clone(),
+ &mut self.externalities,
+ false,
+ "Metadata_metadata",
+ &[],
+ )
+ .map_err(|_| {
+ CodegenError::Wasm("method \"Metadata_metadata\" doesnt exist".to_owned())
+ })?;
+ let encoded_metadata =
+ >::decode(&mut &encoded_metadata[..]).map_err(CodegenError::Decode)?;
+ decode(encoded_metadata)
+ }
+
+ fn load_metadata_at_version(&mut self, version: u32) -> WasmMetadataResult {
+ let encoded_metadata = self
+ .executor
+ .uncached_call(
+ self.runtime_blob.clone(),
+ &mut self.externalities,
+ false,
+ "Metadata_metadata_at_version",
+ &version.encode(),
+ )
+ .map_err(|_| {
+ CodegenError::Wasm(
+ "method \"Metadata_metadata_at_version\" doesnt exist".to_owned(),
+ )
+ })?;
+ let Some(encoded_metadata) =
+