From d1351b2421b6f2ecec21db7211c7c88b18c8bdd2 Mon Sep 17 00:00:00 2001 From: Pavlo Khrystenko Date: Fri, 8 Nov 2024 14:24:49 +0100 Subject: [PATCH 1/3] use "metadata_at_version" closes #1858 --- macro/src/wasm_loader.rs | 47 ++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/macro/src/wasm_loader.rs b/macro/src/wasm_loader.rs index f8be106dce..4c55c46138 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, @@ -39,17 +39,50 @@ fn call_and_decode(wasm_file: Vec) -> WasmMetadataResult { 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)?; + let version = executor + .uncached_call( + runtime_blob.clone(), + &mut ext, + true, + "Metadata_metadata_versions", + &[], + ) + .map_err(|_| { + CodegenError::Wasm("method \"Metadata_metadata_versions\" doesnt exist".to_owned()) + })?; + let mut versions = >::decode(&mut &version[..]).map_err(CodegenError::Decode)?; - decode(metadata) + // Highest version will always be the last one in the vec + versions.sort(); + + let version = versions + .last() + .ok_or(CodegenError::Other( + "No metadata versions were returned".to_owned(), + )) + .map(|v| v.encode())?; + + let encoded_metadata = executor + .uncached_call( + runtime_blob, + &mut ext, + false, + "Metadata_metadata_at_version", + &version, + ) + .map_err(|e| { + dbg!(e); + CodegenError::Wasm("method \"Metadata_metadata_at_version\" doesnt exist".to_owned()) + })?; + + decode(encoded_metadata) } fn decode(encoded_metadata: Vec) -> WasmMetadataResult { - Metadata::decode(&mut encoded_metadata.as_ref()).map_err(Into::into) + // We slice the first byte from the metadata because it's wrapped inside an option and we know that its always `Some` + let metadata = >::decode(&mut &encoded_metadata[1..]).map_err(CodegenError::Decode)?; + Metadata::decode(&mut metadata.as_ref()).map_err(Into::into) } fn maybe_decompress(file_contents: Vec) -> WasmMetadataResult> { From fdb82e1e32b015ae6408455d24beef00ef9a0766 Mon Sep 17 00:00:00 2001 From: Pavlo Khrystenko Date: Mon, 11 Nov 2024 13:07:16 +0100 Subject: [PATCH 2/3] review comments --- macro/src/wasm_loader.rs | 174 +++++++++++++++++++++++++++------------ 1 file changed, 121 insertions(+), 53 deletions(-) diff --git a/macro/src/wasm_loader.rs b/macro/src/wasm_loader.rs index 4c55c46138..3fb2f0b9df 100644 --- a/macro/src/wasm_loader.rs +++ b/macro/src/wasm_loader.rs @@ -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,63 +28,17 @@ 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(); - - let runtime_blob = - RuntimeBlob::new(&wasm_file).map_err(|e| CodegenError::Wasm(e.to_string()))?; - - let version = executor - .uncached_call( - runtime_blob.clone(), - &mut ext, - true, - "Metadata_metadata_versions", - &[], - ) - .map_err(|_| { - CodegenError::Wasm("method \"Metadata_metadata_versions\" doesnt exist".to_owned()) - })?; - let mut versions = >::decode(&mut &version[..]).map_err(CodegenError::Decode)?; - - // Highest version will always be the last one in the vec - versions.sort(); - - let version = versions - .last() - .ok_or(CodegenError::Other( - "No metadata versions were returned".to_owned(), - )) - .map(|v| v.encode())?; - - let encoded_metadata = executor - .uncached_call( - runtime_blob, - &mut ext, - false, - "Metadata_metadata_at_version", - &version, - ) - .map_err(|e| { - dbg!(e); - CodegenError::Wasm("method \"Metadata_metadata_at_version\" doesnt exist".to_owned()) - })?; - - decode(encoded_metadata) + if let Ok(versions) = executor.versions() { + executor.load_metadata_at_latest_version(versions) + } else { + executor.metadata() + } } fn decode(encoded_metadata: Vec) -> WasmMetadataResult { - // We slice the first byte from the metadata because it's wrapped inside an option and we know that its always `Some` - let metadata = >::decode(&mut &encoded_metadata[1..]).map_err(CodegenError::Decode)?; - Metadata::decode(&mut metadata.as_ref()).map_err(Into::into) + Metadata::decode(&mut encoded_metadata.as_ref()).map_err(Into::into) } fn maybe_decompress(file_contents: Vec) -> WasmMetadataResult> { @@ -90,3 +46,115 @@ 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 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_latest_version( + &mut self, + versions: Vec, + ) -> WasmMetadataResult { + let version = versions + .into_iter() + .max() + .expect("This is checked earlier and can't fail."); + + let encoded_metadata = self + .executor + .uncached_call( + self.runtime_blob.clone(), + &mut self.externalities, + false, + "Metadata_metadata_at_version", + &version.encode(), + ) + .map_err(|e| { + dbg!(e); + CodegenError::Wasm( + "method \"Metadata_metadata_at_version\" doesnt exist".to_owned(), + ) + })?; + let Some(encoded_metadata) = + >>::decode(&mut &encoded_metadata[..]).map_err(CodegenError::Decode)? + else { + return Err(CodegenError::Other( + format!("Received empty metadata at version: v{version}").to_owned(), + )); + }; + decode(encoded_metadata) + } +} From f05a6aea252aefbb207f7dd80b112a9833daba7f Mon Sep 17 00:00:00 2001 From: Pavlo Khrystenko Date: Tue, 12 Nov 2024 11:24:56 +0100 Subject: [PATCH 3/3] fixups --- macro/src/wasm_loader.rs | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/macro/src/wasm_loader.rs b/macro/src/wasm_loader.rs index 3fb2f0b9df..24b261419e 100644 --- a/macro/src/wasm_loader.rs +++ b/macro/src/wasm_loader.rs @@ -31,9 +31,14 @@ fn call_and_decode(wasm_file: Vec) -> WasmMetadataResult { let mut executor = Executor::new(&wasm_file)?; if let Ok(versions) = executor.versions() { - executor.load_metadata_at_latest_version(versions) + let version = versions + .into_iter() + .max() + .expect("This is checked earlier and can't fail."); + + executor.load_metadata_at_version(version) } else { - executor.metadata() + executor.load_legacy_metadata() } } @@ -106,7 +111,7 @@ impl Executor { Ok(versions) } - fn metadata(&mut self) -> WasmMetadataResult { + fn load_legacy_metadata(&mut self) -> WasmMetadataResult { let encoded_metadata = self .executor .uncached_call( @@ -124,15 +129,7 @@ impl Executor { decode(encoded_metadata) } - fn load_metadata_at_latest_version( - &mut self, - versions: Vec, - ) -> WasmMetadataResult { - let version = versions - .into_iter() - .max() - .expect("This is checked earlier and can't fail."); - + fn load_metadata_at_version(&mut self, version: u32) -> WasmMetadataResult { let encoded_metadata = self .executor .uncached_call( @@ -142,8 +139,7 @@ impl Executor { "Metadata_metadata_at_version", &version.encode(), ) - .map_err(|e| { - dbg!(e); + .map_err(|_| { CodegenError::Wasm( "method \"Metadata_metadata_at_version\" doesnt exist".to_owned(), )