radix_engine/utils/
package_extractor.rs

1use crate::internal_prelude::*;
2use crate::system::system_modules::costing::SystemLoanFeeReserve;
3use crate::vm::wasm::*;
4use crate::vm::wasm_runtime::NoOpWasmRuntime;
5use crate::vm::ScryptoVmVersion;
6use crate::{errors::InvokeError, transaction::CostingParameters};
7use radix_engine_interface::blueprints::package::*;
8use radix_transactions::prelude::TransactionCostingParameters;
9use sbor::rust::iter;
10
11#[derive(Debug)]
12pub enum ExtractSchemaError {
13    InvalidWasm(PrepareError),
14    RunSchemaGenError(InvokeError<WasmRuntimeError>),
15    SchemaDecodeError(DecodeError),
16}
17
18impl From<PrepareError> for ExtractSchemaError {
19    fn from(value: PrepareError) -> Self {
20        ExtractSchemaError::InvalidWasm(value)
21    }
22}
23
24pub fn extract_definition(code: &[u8]) -> Result<PackageDefinition, ExtractSchemaError> {
25    let function_exports = WasmModule::init(code)
26        .and_then(WasmModule::to_bytes)?
27        .1
28        .into_iter()
29        .filter(|s| s.ends_with("_schema"));
30
31    // Validate WASM
32    let validator = ScryptoV1WasmValidator::new(ScryptoVmVersion::latest());
33    let code_hash = CodeHash(Hash([0u8; 32]));
34    let instrumented_code = validator
35        .validate(&code, iter::empty())
36        .map_err(|e| ExtractSchemaError::InvalidWasm(e))?
37        .0;
38
39    // Execute with empty state (with default cost unit limit)
40    let wasm_engine = DefaultWasmEngine::default();
41    let fee_reserve = SystemLoanFeeReserve::new(
42        CostingParameters::babylon_genesis(),
43        TransactionCostingParameters {
44            tip: Default::default(),
45            free_credit_in_xrd: Decimal::try_from(PREVIEW_CREDIT_IN_XRD).unwrap(),
46        },
47        false,
48    );
49    let mut wasm_execution_units_consumed = 0;
50    let mut runtime: Box<dyn WasmRuntime> = Box::new(NoOpWasmRuntime::new(
51        fee_reserve,
52        &mut wasm_execution_units_consumed,
53    ));
54    let mut instance = wasm_engine.instantiate(code_hash, &instrumented_code);
55    let mut blueprints = index_map_new();
56    for function_export in function_exports {
57        let rtn = instance
58            .invoke_export(&function_export, vec![], &mut runtime)
59            .map_err(ExtractSchemaError::RunSchemaGenError)?;
60
61        let name = function_export.replace("_schema", "").to_string();
62        let blueprint_setup: BlueprintDefinitionInit =
63            scrypto_decode(rtn.as_slice()).map_err(ExtractSchemaError::SchemaDecodeError)?;
64        blueprints.insert(name.clone(), blueprint_setup);
65    }
66
67    Ok(PackageDefinition { blueprints })
68}