pchain_runtime/contract/
module.rs1use pchain_types::cryptography::PublicAddress;
9
10use crate::{
11 contract::{blank, Importable},
12 wasmer::cache::ModuleMetadata,
13 Cache as SmartContractCache,
14};
15
16use super::{
17 instance::{ContractValidateError, Instance},
18 CONTRACT_METHOD,
19};
20
21pub(crate) struct Module(pub wasmer::Module, pub ModuleMetadata);
24
25impl Module {
26 pub fn from_cache(
28 address: PublicAddress,
29 cache: &SmartContractCache,
30 wasmer_store: &wasmer::Store,
31 ) -> Option<Module> {
32 match cache.load(address, wasmer_store) {
33 Ok((m, d)) => Some(Module(m, d)),
34 Err(_) => None,
35 }
36 }
37
38 pub fn cache_to(&self, address: PublicAddress, cache: &mut SmartContractCache) {
40 let _ = cache.store(address, &self.0, self.1.bytes_length);
41 }
42
43 pub fn from_wasm_bytecode(
46 cbi_version: u32,
47 bytecode: &Vec<u8>,
48 wasmer_store: &wasmer::Store,
49 ) -> Result<Module, ModuleBuildError> {
50 let wasmer_module = match wasmer::Module::from_binary(wasmer_store, bytecode) {
51 Ok(m) => m,
52 Err(e) => {
53 if e.to_string().contains("OpcodeError") {
54 return Err(ModuleBuildError::DisallowedOpcodePresent);
55 }
56 return Err(ModuleBuildError::Else);
57 }
58 };
59
60 Ok(Module(
61 wasmer_module,
62 ModuleMetadata {
63 cbi_version,
64 bytes_length: bytecode.len(),
65 },
66 ))
67 }
68
69 pub fn from_wasm_bytecode_unchecked(
73 cbi_version: u32,
74 bytecode: &Vec<u8>,
75 wasmer_store: &wasmer::Store,
76 ) -> Result<Module, ModuleBuildError> {
77 let wasmer_module =
78 match unsafe { wasmer::Module::from_binary_unchecked(wasmer_store, bytecode) } {
79 Ok(m) => m,
80 Err(e) => {
81 if e.to_string().contains("OpcodeError") {
82 return Err(ModuleBuildError::DisallowedOpcodePresent);
83 }
84 return Err(ModuleBuildError::Else);
85 }
86 };
87
88 Ok(Module(
89 wasmer_module,
90 ModuleMetadata {
91 cbi_version,
92 bytes_length: bytecode.len(),
93 },
94 ))
95 }
96
97 pub fn bytes_length(&self) -> usize {
99 self.1.bytes_length
100 }
101
102 pub fn instantiate(
104 &self,
105 importable: &Importable,
106 gas_limit: u64,
107 ) -> Result<Instance, wasmer::InstantiationError> {
108 let wasmer_instance = wasmer::Instance::new(&self.0, &importable.0)?;
110 wasmer_middlewares::metering::set_remaining_points(&wasmer_instance, gas_limit);
112 Ok(Instance(wasmer_instance))
113 }
114
115 pub fn validate_contract(
118 &self,
119 wasmer_store: &wasmer::Store,
120 ) -> Result<(), ContractValidateError> {
121 if !self
122 .0
123 .exports()
124 .functions()
125 .any(|f| f.name() == CONTRACT_METHOD)
126 {
127 return Err(ContractValidateError::MethodNotFound);
128 }
129 let imports_object = blank::imports(wasmer_store);
130 if let Ok(instance) = wasmer::Instance::new(&self.0, &imports_object) {
131 if instance
132 .exports
133 .get_native_function::<(), ()>(CONTRACT_METHOD)
134 .is_ok()
135 {
136 return Ok(());
137 }
138 }
139 Err(ContractValidateError::InstantiateError)
140 }
141}
142
143#[derive(Debug)]
146pub(crate) enum ModuleBuildError {
147 DisallowedOpcodePresent,
149 Else,
151}