1use crate::env::{
10 get_remaining_points_for_env, sub_remaining_gas, sub_remaining_gas_with_mult, Env,
11};
12use crate::settings;
13use crate::types::Response;
14use as_ffi_bindings::{Read as ASRead, StringPtr, Write as ASWrite};
15use wasmer::Memory;
16
17pub type ABIResult<T, E = wasmer::RuntimeError> = core::result::Result<T, E>;
18macro_rules! abi_bail {
19 ($err:expr) => {
20 return Err(wasmer::RuntimeError::new($err.to_string()))
21 };
22}
23macro_rules! get_memory {
24 ($env:ident) => {
25 match $env.wasm_env.memory.get_ref() {
26 Some(mem) => mem,
27 _ => abi_bail!("uninitialized memory"),
28 }
29 };
30}
31pub(crate) use abi_bail;
32pub(crate) use get_memory;
33
34fn call_module(
42 env: &Env,
43 address: &str,
44 function: &str,
45 param: &str,
46 raw_coins: i64,
47) -> ABIResult<Response> {
48 let raw_coins: u64 = match raw_coins.try_into() {
49 Ok(v) => v,
50 Err(_) => abi_bail!("negative amount of coins in Call"),
51 };
52 let module = &match env.interface.init_call(address, raw_coins) {
53 Ok(module) => module,
54 Err(err) => abi_bail!(err),
55 };
56 match crate::execution_impl::exec(
57 get_remaining_points_for_env(env)?,
58 None,
59 module,
60 function,
61 param,
62 &*env.interface,
63 ) {
64 Ok(resp) => match env.interface.finish_call() {
65 Ok(_) => Ok(resp),
66 Err(err) => abi_bail!(err),
67 },
68 Err(err) => abi_bail!(err),
69 }
70}
71
72pub(crate) fn assembly_script_get_call_coins(env: &Env) -> ABIResult<i64> {
74 sub_remaining_gas(env, settings::metering_get_call_coins())?;
75 match env.interface.get_call_coins() {
76 Ok(res) => Ok(res as i64),
77 Err(err) => abi_bail!(err),
78 }
79}
80
81pub(crate) fn assembly_script_transfer_coins(
83 env: &Env,
84 to_address: i32,
85 raw_amount: i64,
86) -> ABIResult<()> {
87 sub_remaining_gas(env, settings::metering_transfer())?;
88 if raw_amount.is_negative() {
89 abi_bail!("Negative raw amount.");
90 }
91 let memory = get_memory!(env);
92 let to_address = &get_string(memory, to_address)?;
93 match env.interface.transfer_coins(to_address, raw_amount as u64) {
94 Ok(res) => Ok(res),
95 Err(err) => abi_bail!(err),
96 }
97}
98
99pub(crate) fn assembly_script_transfer_coins_for(
101 env: &Env,
102 from_address: i32,
103 to_address: i32,
104 raw_amount: i64,
105) -> ABIResult<()> {
106 sub_remaining_gas(env, settings::metering_transfer())?;
107 if raw_amount.is_negative() {
108 abi_bail!("Negative raw amount.");
109 }
110 let memory = get_memory!(env);
111 let from_address = &get_string(memory, from_address)?;
112 let to_address = &get_string(memory, to_address)?;
113 match env
114 .interface
115 .transfer_coins_for(from_address, to_address, raw_amount as u64)
116 {
117 Ok(res) => Ok(res),
118 Err(err) => abi_bail!(err),
119 }
120}
121
122pub(crate) fn assembly_script_get_balance(env: &Env) -> ABIResult<i64> {
123 sub_remaining_gas(env, settings::metering_get_balance())?;
124 match env.interface.get_balance() {
125 Ok(res) => Ok(res as i64),
126 Err(err) => abi_bail!(err),
127 }
128}
129
130pub(crate) fn assembly_script_get_balance_for(env: &Env, address: i32) -> ABIResult<i64> {
131 sub_remaining_gas(env, settings::metering_get_balance())?;
132 let memory = get_memory!(env);
133 let address = &get_string(memory, address)?;
134 match env.interface.get_balance_for(address) {
135 Ok(res) => Ok(res as i64),
136 Err(err) => abi_bail!(err),
137 }
138}
139
140fn create_sc(env: &Env, bytecode: &[u8]) -> ABIResult<String> {
141 match env.interface.create_module(bytecode) {
142 Ok(address) => Ok(address),
143 Err(err) => abi_bail!(err),
144 }
145}
146
147#[doc = include_str!("../wasm/README.md")]
150pub(crate) fn assembly_script_call_module(
151 env: &Env,
152 address: i32,
153 function: i32,
154 param: i32,
155 call_coins: i64,
156) -> ABIResult<i32> {
157 sub_remaining_gas(env, settings::metering_call())?;
158 let memory = get_memory!(env);
159 let address = &get_string(memory, address)?;
160 let function = &get_string(memory, function)?;
161 let param = &get_string(memory, param)?;
162 let response = call_module(env, address, function, param, call_coins)?;
163 match StringPtr::alloc(&response.ret, &env.wasm_env) {
164 Ok(ret) => Ok(ret.offset() as i32),
165 _ => abi_bail!(format!(
166 "Cannot allocate response in call {}::{}",
167 address, function
168 )),
169 }
170}
171
172pub(crate) fn assembly_script_get_remaining_gas(env: &Env) -> ABIResult<i64> {
173 sub_remaining_gas(env, settings::metering_remaining_gas())?;
174 Ok(get_remaining_points_for_env(env)? as i64)
175}
176
177pub(crate) fn assembly_script_print(env: &Env, arg: i32) -> ABIResult<()> {
182 sub_remaining_gas(env, settings::metering_print())?;
183 let memory = get_memory!(env);
184 if let Err(err) = env.interface.print(&get_string(memory, arg)?) {
185 abi_bail!(err);
186 }
187 Ok(())
188}
189
190pub(crate) fn assembly_script_create_sc(env: &Env, bytecode: i32) -> ABIResult<i32> {
193 let memory = get_memory!(env);
194 let bytecode = match base64::decode(read_string_and_sub_gas(
196 env,
197 memory,
198 bytecode,
199 settings::metering_create_sc_mult(),
200 )?) {
201 Ok(bytecode) => bytecode,
202 Err(err) => abi_bail!(err),
203 };
204 let address = match create_sc(env, &bytecode) {
205 Ok(address) => address,
206 Err(err) => abi_bail!(err),
207 };
208 match StringPtr::alloc(&address, &env.wasm_env) {
209 Ok(ptr) => Ok(ptr.offset() as i32),
210 Err(err) => abi_bail!(err),
211 }
212}
213
214pub(crate) fn assembly_script_hash(env: &Env, value: i32) -> ABIResult<i32> {
216 sub_remaining_gas(env, settings::metering_hash_const())?;
217 let memory = get_memory!(env);
218 let value = read_string_and_sub_gas(env, memory, value, settings::metering_hash_per_byte())?;
219 match env.interface.hash(value.as_bytes()) {
220 Ok(h) => Ok(pointer_from_string(env, &h)?.offset() as i32),
221 Err(err) => abi_bail!(err),
222 }
223}
224
225pub(crate) fn assembly_script_set_data(env: &Env, key: i32, value: i32) -> ABIResult<()> {
227 sub_remaining_gas(env, settings::metering_set_data_const())?;
228 let memory = get_memory!(env);
229 let key = read_string_and_sub_gas(env, memory, key, settings::metering_set_data_key_mult())?;
230 let value =
231 read_string_and_sub_gas(env, memory, value, settings::metering_set_data_value_mult())?;
232 if let Err(err) = env.interface.raw_set_data(&key, value.as_bytes()) {
233 abi_bail!(err)
234 }
235 Ok(())
236}
237
238pub(crate) fn assembly_script_get_data(env: &Env, key: i32) -> ABIResult<i32> {
240 sub_remaining_gas(env, settings::metering_get_data_const())?;
241 let memory = get_memory!(env);
242 let key = read_string_and_sub_gas(env, memory, key, settings::metering_get_data_key_mult())?;
243 match env.interface.raw_get_data(&key) {
244 Ok(data) => {
245 sub_remaining_gas_with_mult(env, data.len(), settings::metering_get_data_value_mult())?;
246 Ok(pointer_from_utf8(env, &data)?.offset() as i32)
247 }
248 Err(err) => abi_bail!(err),
249 }
250}
251
252pub(crate) fn assembly_script_has_data(env: &Env, key: i32) -> ABIResult<i32> {
254 sub_remaining_gas(env, settings::metering_has_data_const())?;
255 let memory = get_memory!(env);
256 let key = read_string_and_sub_gas(env, memory, key, settings::metering_has_data_key_mult())?;
257 match env.interface.has_data(&key) {
258 Ok(true) => Ok(1),
259 Ok(false) => Ok(0),
260 Err(err) => abi_bail!(err),
261 }
262}
263
264pub(crate) fn assembly_script_set_data_for(
265 env: &Env,
266 address: i32,
267 key: i32,
268 value: i32,
269) -> ABIResult<()> {
270 sub_remaining_gas(env, settings::metering_set_data_const())?;
271 let memory = get_memory!(env);
272 let key = read_string_and_sub_gas(env, memory, key, settings::metering_set_data_key_mult())?;
273 let value =
274 read_string_and_sub_gas(env, memory, value, settings::metering_set_data_value_mult())?;
275 let address = get_string(memory, address)?;
276 if let Err(err) = env
277 .interface
278 .raw_set_data_for(&address, &key, value.as_bytes())
279 {
280 abi_bail!(err)
281 }
282 Ok(())
283}
284
285pub(crate) fn assembly_script_get_data_for(env: &Env, address: i32, key: i32) -> ABIResult<i32> {
286 sub_remaining_gas(env, settings::metering_get_data_const())?;
287 let memory = get_memory!(env);
288 let address = get_string(memory, address)?;
289 let key = read_string_and_sub_gas(env, memory, key, settings::metering_get_data_key_mult())?;
290 match env.interface.raw_get_data_for(&address, &key) {
291 Ok(data) => {
292 sub_remaining_gas_with_mult(env, data.len(), settings::metering_get_data_value_mult())?;
293 Ok(pointer_from_utf8(env, &data)?.offset() as i32)
294 }
295 Err(err) => abi_bail!(err),
296 }
297}
298
299pub(crate) fn assembly_script_has_data_for(env: &Env, address: i32, key: i32) -> ABIResult<i32> {
300 sub_remaining_gas(env, settings::metering_has_data_const())?;
301 let memory = get_memory!(env);
302 let address = get_string(memory, address)?;
303 let key = read_string_and_sub_gas(env, memory, key, settings::metering_has_data_key_mult())?;
304 match env.interface.has_data_for(&address, &key) {
305 Ok(true) => Ok(1),
306 Ok(false) => Ok(0),
307 Err(err) => abi_bail!(err),
308 }
309}
310
311pub(crate) fn assembly_script_get_owned_addresses_raw(env: &Env) -> ABIResult<i32> {
312 sub_remaining_gas(env, settings::metering_get_owned_addrs())?;
313 let data = match env.interface.get_owned_addresses() {
314 Ok(data) => data,
315 Err(err) => abi_bail!(err),
316 };
317 match StringPtr::alloc(&data.join(";"), &env.wasm_env) {
318 Ok(ptr) => Ok(ptr.offset() as i32),
319 Err(err) => abi_bail!(err),
320 }
321}
322
323pub(crate) fn assembly_script_get_call_stack_raw(env: &Env) -> ABIResult<i32> {
324 sub_remaining_gas(env, settings::metering_get_call_stack())?;
325 let data = match env.interface.get_call_stack() {
326 Ok(data) => data,
327 Err(err) => abi_bail!(err),
328 };
329 match StringPtr::alloc(&data.join(";"), &env.wasm_env) {
330 Ok(ptr) => Ok(ptr.offset() as i32),
331 Err(err) => abi_bail!(err),
332 }
333}
334
335pub(crate) fn assembly_script_get_owned_addresses(env: &Env) -> ABIResult<i32> {
336 sub_remaining_gas(env, settings::metering_get_owned_addrs())?;
337 match env.interface.get_owned_addresses() {
338 Ok(data) => alloc_string_array(env, &data),
339 Err(err) => abi_bail!(err),
340 }
341}
342
343pub(crate) fn assembly_script_get_call_stack(env: &Env) -> ABIResult<i32> {
344 sub_remaining_gas(env, settings::metering_get_call_stack())?;
345 match env.interface.get_call_stack() {
346 Ok(data) => alloc_string_array(env, &data),
347 Err(err) => abi_bail!(err),
348 }
349}
350
351pub(crate) fn assembly_script_generate_event(env: &Env, event: i32) -> ABIResult<()> {
352 sub_remaining_gas(env, settings::metering_generate_event())?;
353 let memory = get_memory!(env);
354 let event = get_string(memory, event)?;
355 if let Err(err) = env.interface.generate_event(event) {
356 abi_bail!(err)
357 }
358 Ok(())
359}
360
361pub(crate) fn assembly_script_signature_verify(
363 env: &Env,
364 data: i32,
365 signature: i32,
366 public_key: i32,
367) -> ABIResult<i32> {
368 sub_remaining_gas(env, settings::metering_signature_verify_const())?;
369 let memory = get_memory!(env);
370 let data = read_string_and_sub_gas(
371 env,
372 memory,
373 data,
374 settings::metering_signature_verify_data_mult(),
375 )?;
376 let signature = get_string(memory, signature)?;
377 let public_key = get_string(memory, public_key)?;
378 match env
379 .interface
380 .signature_verify(data.as_bytes(), &signature, &public_key)
381 {
382 Err(err) => abi_bail!(err),
383 Ok(false) => Ok(0),
384 Ok(true) => Ok(1),
385 }
386}
387
388pub(crate) fn assembly_script_address_from_public_key(
390 env: &Env,
391 public_key: i32,
392) -> ABIResult<i32> {
393 sub_remaining_gas(env, settings::metering_address_from_public_key())?;
394 let memory = get_memory!(env);
395 let public_key = get_string(memory, public_key)?;
396 match env.interface.address_from_public_key(&public_key) {
397 Err(err) => abi_bail!(err),
398 Ok(addr) => Ok(pointer_from_string(env, &addr)?.offset() as i32),
399 }
400}
401
402pub(crate) fn assembly_script_unsafe_random(env: &Env) -> ABIResult<i64> {
404 sub_remaining_gas(env, settings::metering_unsafe_random())?;
405 match env.interface.unsafe_random() {
406 Err(err) => abi_bail!(err),
407 Ok(rnd) => Ok(rnd),
408 }
409}
410
411pub(crate) fn assembly_script_get_time(env: &Env) -> ABIResult<i64> {
413 sub_remaining_gas(env, settings::metering_get_time())?;
414 match env.interface.get_time() {
415 Err(err) => abi_bail!(err),
416 Ok(t) => Ok(t as i64),
417 }
418}
419
420#[allow(clippy::too_many_arguments)]
422pub(crate) fn assembly_script_send_message(
423 env: &Env,
424 target_address: i32,
425 target_handler: i32,
426 validity_start_period: i64,
427 validity_start_thread: i32,
428 validity_end_period: i64,
429 validity_end_thread: i32,
430 max_gas: i64,
431 gas_price: i64,
432 raw_coins: i64,
433 data: i32,
434) -> ABIResult<()> {
435 sub_remaining_gas(env, settings::metering_send_message())?;
436 let validity_start: (u64, u8) = match (
437 validity_start_period.try_into(),
438 validity_start_thread.try_into(),
439 ) {
440 (Ok(p), Ok(t)) => (p, t),
441 (Err(_), _) => abi_bail!("negative validity start period"),
442 (_, Err(_)) => abi_bail!("invalid validity start thread"),
443 };
444 let validity_end: (u64, u8) = match (
445 validity_end_period.try_into(),
446 validity_end_thread.try_into(),
447 ) {
448 (Ok(p), Ok(t)) => (p, t),
449 (Err(_), _) => abi_bail!("negative validity end period"),
450 (_, Err(_)) => abi_bail!("invalid validity end thread"),
451 };
452 if max_gas.is_negative() {
453 abi_bail!("negative max gas");
454 }
455 if gas_price.is_negative() {
456 abi_bail!("negative gas price");
457 }
458 if raw_coins.is_negative() {
459 abi_bail!("negative coins")
460 }
461 let memory = get_memory!(env);
462 match env.interface.send_message(
463 &get_string(memory, target_address)?,
464 &get_string(memory, target_handler)?,
465 validity_start,
466 validity_end,
467 max_gas as u64,
468 gas_price as u64,
469 raw_coins as u64,
470 get_string(memory, data)?.as_bytes(),
471 ) {
472 Err(err) => abi_bail!(err),
473 Ok(_) => Ok(()),
474 }
475}
476
477pub(crate) fn assembly_script_get_current_period(env: &Env) -> ABIResult<i64> {
479 sub_remaining_gas(env, settings::metering_get_current_period())?;
480 match env.interface.get_current_period() {
481 Err(err) => abi_bail!(err),
482 Ok(v) => Ok(v as i64),
483 }
484}
485
486pub(crate) fn assembly_script_get_current_thread(env: &Env) -> ABIResult<i32> {
488 sub_remaining_gas(env, settings::metering_get_current_thread())?;
489 match env.interface.get_current_thread() {
490 Err(err) => abi_bail!(err),
491 Ok(v) => Ok(v as i32),
492 }
493}
494
495fn pointer_from_string(env: &Env, value: &str) -> ABIResult<StringPtr> {
497 match StringPtr::alloc(&value.into(), &env.wasm_env) {
498 Ok(ptr) => Ok(*ptr),
499 Err(err) => abi_bail!(err),
500 }
501}
502
503fn pointer_from_utf8(env: &Env, value: &[u8]) -> ABIResult<StringPtr> {
505 match std::str::from_utf8(value) {
506 Ok(data) => match StringPtr::alloc(&data.to_string(), &env.wasm_env) {
507 Ok(ptr) => Ok(*ptr),
508 Err(err) => abi_bail!(err),
509 },
510 Err(err) => abi_bail!(err),
511 }
512}
513
514fn read_string_and_sub_gas(
522 env: &Env,
523 memory: &Memory,
524 offset: i32,
525 mult: usize,
526) -> ABIResult<String> {
527 match StringPtr::new(offset as u32).read(memory) {
528 Ok(value) => {
529 sub_remaining_gas_with_mult(env, value.len(), mult)?;
530 Ok(value)
531 }
532 Err(err) => abi_bail!(err),
533 }
534}
535
536fn get_string(memory: &Memory, ptr: i32) -> ABIResult<String> {
538 match StringPtr::new(ptr as u32).read(memory) {
539 Ok(str) => Ok(str),
540 Err(err) => abi_bail!(err),
541 }
542}
543
544fn alloc_string_array(env: &Env, vec: &[String]) -> ABIResult<i32> {
546 let addresses = match serde_json::to_string(vec) {
547 Ok(list) => list,
548 Err(err) => abi_bail!(err),
549 };
550 match StringPtr::alloc(&addresses, &env.wasm_env) {
551 Ok(ptr) => Ok(ptr.offset() as i32),
552 Err(err) => abi_bail!(err),
553 }
554}