substrate_wasm_builder/
metadata_hash.rs1use crate::builder::MetadataExtraInfo;
19use codec::{Decode, Encode};
20use frame_metadata::{RuntimeMetadata, RuntimeMetadataPrefixed};
21use merkleized_metadata::{generate_metadata_digest, ExtraInfo};
22use sc_executor::WasmExecutor;
23use sp_core::traits::{CallContext, CodeExecutor, RuntimeCode, WrappedRuntimeCode};
24use std::path::Path;
25
26type HostFunctions = (
30 sp_io::allocator::HostFunctions,
32 sp_io::logging::HostFunctions,
34 sp_io::storage::HostFunctions,
38 sp_io::hashing::HostFunctions,
40);
41
42pub fn generate_metadata_hash(wasm: &Path, extra_info: MetadataExtraInfo) -> [u8; 32] {
49 sp_tracing::try_init_simple();
50
51 let wasm = std::fs::read(wasm).expect("Wasm file was just created and should be readable.");
52
53 let executor = WasmExecutor::<HostFunctions>::builder()
54 .with_allow_missing_host_functions(true)
55 .build();
56
57 let runtime_code = RuntimeCode {
58 code_fetcher: &WrappedRuntimeCode(wasm.into()),
59 heap_pages: None,
60 hash: vec![1, 2, 3],
62 };
63
64 let metadata = executor
65 .call(
66 &mut sp_io::TestExternalities::default().ext(),
67 &runtime_code,
68 "Metadata_metadata_at_version",
69 &15u32.encode(),
70 CallContext::Offchain,
71 )
72 .0
73 .expect("`Metadata::metadata_at_version` should exist.");
74
75 let metadata = Option::<Vec<u8>>::decode(&mut &metadata[..])
76 .ok()
77 .flatten()
78 .expect("Metadata V15 support is required.");
79
80 let metadata = RuntimeMetadataPrefixed::decode(&mut &metadata[..])
81 .expect("Invalid encoded metadata?")
82 .1;
83
84 let runtime_version = executor
85 .call(
86 &mut sp_io::TestExternalities::default().ext(),
87 &runtime_code,
88 "Core_version",
89 &[],
90 CallContext::Offchain,
91 )
92 .0
93 .expect("`Core_version` should exist.");
94 let runtime_version = sp_version::RuntimeVersion::decode(&mut &runtime_version[..])
95 .expect("Invalid `RuntimeVersion` encoding");
96
97 let base58_prefix = extract_ss58_prefix(&metadata);
98
99 let extra_info = ExtraInfo {
100 spec_version: runtime_version.spec_version,
101 spec_name: runtime_version.spec_name.into(),
102 base58_prefix,
103 decimals: extra_info.decimals,
104 token_symbol: extra_info.token_symbol,
105 };
106
107 generate_metadata_digest(&metadata, extra_info)
108 .expect("Failed to generate the metadata digest")
109 .hash()
110}
111
112fn extract_ss58_prefix(metadata: &RuntimeMetadata) -> u16 {
114 let RuntimeMetadata::V15(ref metadata) = metadata else {
115 panic!("Metadata version 15 required")
116 };
117
118 let system = metadata
119 .pallets
120 .iter()
121 .find(|p| p.name == "System")
122 .expect("Each FRAME runtime has the `System` pallet; qed");
123
124 system
125 .constants
126 .iter()
127 .find_map(|c| {
128 (c.name == "SS58Prefix")
129 .then(|| u16::decode(&mut &c.value[..]).expect("SS58 is an `u16`; qed"))
130 })
131 .expect("`SS58PREFIX` exists in the `System` constants; qed")
132}