darkfi_sdk/wasm/
entrypoint.rs

1/* This file is part of DarkFi (https://dark.fi)
2 *
3 * Copyright (C) 2020-2025 Dyne.org foundation
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as
7 * published by the Free Software Foundation, either version 3 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 */
18
19use core::{mem::size_of, slice::from_raw_parts};
20
21use crate::crypto::ContractId;
22
23/// Success exit code for a contract
24pub const SUCCESS: i64 = 0;
25
26#[macro_export]
27macro_rules! define_contract {
28    (
29        init: $init_func:ident,
30        exec: $exec_func:ident,
31        apply: $apply_func:ident,
32        metadata: $metadata_func:ident
33    ) => {
34        /// # Safety
35        #[no_mangle]
36        pub unsafe extern "C" fn __initialize(input: *mut u8) -> i64 {
37            let (contract_id, instruction_data) = $crate::wasm::entrypoint::deserialize(input);
38
39            match $init_func(contract_id, &instruction_data) {
40                Ok(()) => $crate::wasm::entrypoint::SUCCESS,
41                Err(e) => e.into(),
42            }
43        }
44        #[no_mangle]
45        pub unsafe extern "C" fn __entrypoint(input: *mut u8) -> i64 {
46            let (contract_id, instruction_data) = $crate::wasm::entrypoint::deserialize(input);
47
48            match $exec_func(contract_id, &instruction_data) {
49                Ok(()) => $crate::wasm::entrypoint::SUCCESS,
50                Err(e) => e.into(),
51            }
52        }
53        #[no_mangle]
54        pub unsafe extern "C" fn __update(input: *mut u8) -> i64 {
55            let (contract_id, update_data) = $crate::wasm::entrypoint::deserialize(input);
56
57            match $apply_func(contract_id, &update_data) {
58                Ok(()) => $crate::wasm::entrypoint::SUCCESS,
59                Err(e) => e.into(),
60            }
61        }
62        #[no_mangle]
63        pub unsafe extern "C" fn __metadata(input: *mut u8) -> i64 {
64            let (contract_id, instruction_data) = $crate::wasm::entrypoint::deserialize(input);
65
66            match $metadata_func(contract_id, &instruction_data) {
67                Ok(()) => $crate::wasm::entrypoint::SUCCESS,
68                Err(e) => e.into(),
69            }
70        }
71    };
72}
73
74/// Deserialize a given payload in `entrypoint`
75/// The return values from this are the input values for the above defined functions.
76/// # Safety
77pub unsafe fn deserialize<'a>(input: *mut u8) -> (ContractId, &'a [u8]) {
78    let mut offset: usize = 0;
79
80    let contract_id_len = 32;
81    let contract_id_slice = { from_raw_parts(input.add(offset), contract_id_len) };
82    offset += contract_id_len;
83
84    let instruction_data_len = *(input.add(offset) as *const u64) as usize;
85    offset += size_of::<u64>();
86    let instruction_data = { from_raw_parts(input.add(offset), instruction_data_len) };
87
88    let contract_id = ContractId::from_bytes(contract_id_slice.try_into().unwrap());
89    // We unwrap here because if this panics, something's wrong in the runtime:
90    let contract_id = contract_id.unwrap();
91
92    (contract_id, instruction_data)
93}