wevm/
lib.rs

1#[cfg(feature = "jvm")]
2mod env;
3
4#[cfg(feature = "jvm")]
5mod error;
6
7#[cfg(feature = "jvm")]
8mod exec;
9
10#[cfg(feature = "jvm")]
11mod jvm;
12
13mod modules;
14
15#[cfg(feature = "jvm")]
16mod node;
17
18#[cfg(feature = "jvm")]
19mod runtime;
20
21#[cfg(all(test, feature = "jvm"))]
22mod tests;
23
24#[cfg(feature = "jvm")]
25mod vm;
26
27pub use modules::v0;
28pub use modules::v1;
29
30#[cfg(feature = "jvm")]
31use crate::{error::JvmError, exec::Executable, vm::Vm};
32#[cfg(feature = "jvm")]
33use base58::ToBase58;
34#[cfg(feature = "jvm")]
35use jni::{
36    objects::{JByteArray, JClass, JObject, JString},
37    sys::{jint, jlong},
38    JNIEnv,
39};
40#[cfg(feature = "jvm")]
41use log::{debug, error};
42#[cfg(feature = "jvm")]
43use wasmi::Value;
44
45/// Size of allocated linear memory.
46pub const MEMORY: (u32, u32) = (2, 16);
47
48// This `#[no_mangle]` keeps rust from "mangling" the name and making it unique
49// for this crate. The name follow a strict naming convention so that the
50// JNI implementation will be able to automatically find the implementation
51// of a native method based on its name.
52//
53// The `'local` lifetime here represents the local frame within which any local
54// (temporary) references to Java objects will remain valid.
55//
56// It's usually not necessary to explicitly name the `'local` input lifetimes but
57// in this case we want to return a reference and show the compiler what
58// local frame lifetime it is associated with.
59
60/// External Java function to execute bytecode contract.
61#[cfg(feature = "jvm")]
62#[no_mangle]
63pub extern "system" fn Java_com_wavesenterprise_wasm_core_WASMExecutor_runContract<'local>(
64    mut env: JNIEnv<'local>,
65    _class: JClass<'local>,
66    contract_id: JByteArray<'local>,
67    bytecode: JByteArray<'local>,
68    func_name: JString<'local>,
69    params: JByteArray<'local>,
70    fuel_limit: jlong,
71    callback: JObject<'local>,
72) -> jint {
73    let _ = env_logger::try_init();
74    let contract_id = match env.convert_byte_array(contract_id) {
75        Ok(bytes) => bytes,
76        Err(_) => {
77            error!("{}", JvmError::ByteArrayConversion);
78            return JvmError::ByteArrayConversion.as_jint();
79        }
80    };
81
82    debug!(
83        "Started WEVM to execute the contract: {}",
84        contract_id.clone().to_base58()
85    );
86
87    let bytecode = match env.convert_byte_array(bytecode) {
88        Ok(bytes) => bytes,
89        Err(_) => {
90            error!("{}", JvmError::ByteArrayConversion);
91            return JvmError::ByteArrayConversion.as_jint();
92        }
93    };
94
95    let jvm = match env.get_java_vm() {
96        Ok(jvm) => jvm,
97        Err(_) => {
98            error!("{}", JvmError::GetJavaVM);
99            return JvmError::GetJavaVM.as_jint();
100        }
101    };
102
103    let callback = match env.new_global_ref(callback) {
104        Ok(callback) => callback,
105        Err(_) => {
106            error!("{}", JvmError::NewGlobalRef);
107            return JvmError::NewGlobalRef.as_jint();
108        }
109    };
110
111    let mut vm = match Vm::new(
112        contract_id,
113        bytecode,
114        MEMORY,
115        fuel_limit as u64,
116        modules(),
117        Some(jvm),
118        Some(callback),
119    ) {
120        Ok(vm) => vm,
121        Err(error) => {
122            error!("{}", error);
123            return error.as_jint();
124        }
125    };
126
127    let func_name: String = match env.get_string(&func_name) {
128        Ok(string) => string.into(),
129        Err(_) => {
130            error!("{}", JvmError::NewString);
131            return JvmError::NewString.as_jint();
132        }
133    };
134
135    let params = match env.convert_byte_array(params) {
136        Ok(bytes) => bytes,
137        Err(_) => {
138            error!("{}", JvmError::ByteArrayConversion);
139            return JvmError::ByteArrayConversion.as_jint();
140        }
141    };
142
143    let result = match vm.run(&func_name, &params) {
144        Ok(result) => result,
145        Err(error) => {
146            error!("{}", error);
147            return error.as_jint();
148        }
149    };
150
151    match result[0] {
152        Value::I32(value) => value as jint,
153        _ => 0 as jint,
154    }
155}
156
157/// External Java function to validate bytecode contract.
158#[cfg(feature = "jvm")]
159#[no_mangle]
160pub extern "system" fn Java_com_wavesenterprise_wasm_core_WASMExecutor_validateBytecode<'local>(
161    env: JNIEnv<'local>,
162    _class: JClass<'local>,
163    bytecode: JByteArray<'local>,
164) -> jint {
165    let bytecode = match env.convert_byte_array(bytecode) {
166        Ok(bytes) => bytes,
167        Err(_) => {
168            error!("{}", JvmError::ByteArrayConversion);
169            return JvmError::ByteArrayConversion.as_jint();
170        }
171    };
172
173    match Executable::validate_bytecode(&bytecode) {
174        Ok(_) => 0,
175        Err(error) => {
176            error!("{}", error);
177            error.as_jint()
178        }
179    }
180}
181
182#[cfg(feature = "jvm")]
183fn modules() -> Vec<modules::Module> {
184    let mut vec = vec![];
185    vec.extend(v0::modules::modules());
186    vec.extend(v1::modules::modules());
187    vec
188}