soil_runtime_utilities/
lib.rs1#![warn(missing_docs)]
12
13use codec::{Decode, Encode};
14use error::{Error, Result};
15use soil_client::executor::WasmExecutor;
16use std::borrow::Cow;
17use subsoil::core::{
18 traits::{CallContext, CodeExecutor, FetchRuntimeCode, RuntimeCode},
19 OpaqueMetadata,
20};
21use subsoil::state_machine::BasicExternalities;
22use subsoil::wasm_interface::HostFunctions;
23
24pub mod error;
25
26pub fn fetch_latest_metadata_from_code_blob<HF: HostFunctions>(
28 executor: &WasmExecutor<HF>,
29 code_bytes: Cow<[u8]>,
30) -> Result<OpaqueMetadata> {
31 let runtime_caller = RuntimeCaller::new(executor, code_bytes);
32 let version_result = runtime_caller.call("Metadata_metadata_versions", ());
33
34 match version_result {
35 Ok(supported_versions) => {
36 let supported_versions = Vec::<u32>::decode(&mut supported_versions.as_slice())?;
37 let latest_stable = supported_versions
38 .into_iter()
39 .filter(|v| *v != u32::MAX && *v < 16)
42 .max()
43 .ok_or(Error::StableMetadataVersionNotFound)?;
44
45 let encoded = runtime_caller.call("Metadata_metadata_at_version", latest_stable)?;
46
47 Option::<OpaqueMetadata>::decode(&mut encoded.as_slice())?
48 .ok_or(Error::OpaqueMetadataNotFound)
49 },
50 Err(_) => {
51 let encoded = runtime_caller.call("Metadata_metadata", ())?;
52 Decode::decode(&mut encoded.as_slice()).map_err(Into::into)
53 },
54 }
55}
56
57struct BasicCodeFetcher<'a> {
58 code: Cow<'a, [u8]>,
59 hash: Vec<u8>,
60}
61
62impl<'a> FetchRuntimeCode for BasicCodeFetcher<'a> {
63 fn fetch_runtime_code(&self) -> Option<Cow<'_, [u8]>> {
64 Some(self.code.as_ref().into())
65 }
66}
67
68impl<'a> BasicCodeFetcher<'a> {
69 fn new(code: Cow<'a, [u8]>) -> Self {
70 Self { hash: subsoil_crypto_hashing::blake2_256(&code).to_vec(), code }
71 }
72
73 fn runtime_code(&'a self) -> RuntimeCode<'a> {
74 RuntimeCode {
75 code_fetcher: self as &'a dyn FetchRuntimeCode,
76 heap_pages: None,
77 hash: self.hash.clone(),
78 }
79 }
80}
81
82pub struct RuntimeCaller<'a, 'b, HF: HostFunctions> {
84 executor: &'b WasmExecutor<HF>,
85 code_fetcher: BasicCodeFetcher<'a>,
86}
87
88impl<'a, 'b, HF: HostFunctions> RuntimeCaller<'a, 'b, HF> {
89 pub fn new(executor: &'b WasmExecutor<HF>, code_bytes: Cow<'a, [u8]>) -> Self {
91 Self { executor, code_fetcher: BasicCodeFetcher::new(code_bytes) }
92 }
93
94 pub fn call(&self, method: &str, data: impl Encode) -> Result<Vec<u8>> {
97 let mut ext = BasicExternalities::default();
98 self.executor
99 .call(
100 &mut ext,
101 &self.code_fetcher.runtime_code(),
102 method,
103 &data.encode(),
104 CallContext::Offchain,
105 )
106 .0
107 .map_err(Into::into)
108 }
109}