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 */
1819use darkfi_serial::{Decodable, Encodable};
20use std::io::Cursor;
2122use crate::{
23 error::{ContractError, GenericResult},
24 tx::TransactionHash,
25};
2627/// Calls the `set_return_data` WASM function. Returns Ok(()) on success.
28/// Otherwise, convert the i64 error code into a [`ContractError`].
29pub fn set_return_data(data: &[u8]) -> Result<(), ContractError> {
30// Ensure that the number of bytes fits within the u32 data type.
31match u32::try_from(data.len()) {
32Ok(len) => unsafe {
33match set_return_data_(data.as_ptr(), len) {
340 => Ok(()),
35 errcode => Err(ContractError::from(errcode)),
36 }
37 },
38Err(_) => Err(ContractError::DataTooLarge),
39 }
40}
4142/// Internal function, get raw bytes from the objects store
43pub fn get_object_bytes(data: &mut [u8], object_index: u32) -> i64 {
44unsafe { get_object_bytes_(data.as_mut_ptr(), object_index) }
45}
4647/// Internal function, get bytes size for an object in the store
48pub fn get_object_size(object_index: u32) -> i64 {
49unsafe { get_object_size_(object_index) }
50}
5152/// Auxiliary function to parse db_get return value.
53/// If either of these functions returns a negative integer error code,
54/// convert it into a [`ContractError`].
55pub(crate) fn parse_ret(ret: i64) -> GenericResult<Option<Vec<u8>>> {
56// Negative values represent an error code.
57if ret < 0 {
58// However here on the special case, we'll return Ok(None)
59if ret == crate::error::DB_GET_EMPTY {
60return Ok(None)
61 }
6263return Err(ContractError::from(ret))
64 }
6566// Ensure that the returned value fits into the u32 datatype.
67 // Note that any negative cases should be caught by the `unimplemented`
68 // match arm above.
69let obj = match u32::try_from(ret) {
70Ok(obj) => obj,
71Err(_) => return Err(ContractError::SetRetvalError),
72 };
73let obj_size = get_object_size(obj);
74let mut buf = vec![0u8; obj_size as usize];
75 get_object_bytes(&mut buf, obj);
7677Ok(Some(buf))
78}
7980fn parse_retval_u32(ret: i64) -> GenericResult<u32> {
81if ret < 0 {
82return Err(ContractError::from(ret))
83 }
84assert!(ret >= 0);
85// This should always be possible
86let obj = ret as u32;
87Ok(obj)
88}
8990/// Everyone can call this. Will return runtime configured
91/// verifying block height.
92///
93/// ```
94/// block_height = get_verifying_block_height();
95/// ```
96pub fn get_verifying_block_height() -> GenericResult<u32> {
97let ret = unsafe { get_verifying_block_height_() };
98 parse_retval_u32(ret)
99}
100101/// Everyone can call this. Will return runtime configured
102/// block target.
103///
104/// ```
105/// block_target = get_block_target();
106/// ```
107pub fn get_block_target() -> GenericResult<u32> {
108let ret = unsafe { get_block_target_() };
109 parse_retval_u32(ret)
110}
111112/// Only deploy(), metadata() and exec() can call this. Will return runtime configured
113/// transaction hash.
114///
115/// ```
116/// tx_hash = get_tx_hash();
117/// ```
118pub fn get_tx_hash() -> GenericResult<TransactionHash> {
119let ret = unsafe { get_tx_hash_() };
120let obj = parse_retval_u32(ret)?;
121let mut tx_hash_data = [0u8; 32];
122assert_eq!(get_object_size(obj), 32);
123 get_object_bytes(&mut tx_hash_data, obj);
124Ok(TransactionHash(tx_hash_data))
125}
126127/// Only deploy(), metadata() and exec() can call this. Will return runtime configured
128/// verifying block height.
129///
130/// ```
131/// call_idx = get_call_index();
132/// ```
133pub fn get_call_index() -> GenericResult<u8> {
134let ret = unsafe { get_call_index_() };
135if ret < 0 {
136return Err(ContractError::from(ret))
137 }
138assert!(ret >= 0);
139// This should always be possible
140let obj = ret as u8;
141Ok(obj)
142}
143144/// Everyone can call this. Will return current blockchain timestamp.
145///
146/// ```
147/// timestamp = get_blockchain_time();
148/// ```
149pub fn get_blockchain_time() -> GenericResult<Option<Vec<u8>>> {
150let ret = unsafe { get_blockchain_time_() };
151 parse_ret(ret)
152}
153154/// Only exec() can call this. Will return last block height.
155///
156/// ```
157/// last_block_height = get_last_block_height();
158/// ```
159pub fn get_last_block_height() -> GenericResult<Option<Vec<u8>>> {
160let ret = unsafe { get_last_block_height_() };
161 parse_ret(ret)
162}
163164/// Only metadata() and exec() can call this. Will return transaction
165/// bytes by provided hash.
166///
167/// ```
168/// tx_bytes = get_tx(hash);
169/// tx = deserialize(&tx_bytes)?;
170/// ```
171pub fn get_tx(hash: &TransactionHash) -> GenericResult<Option<Vec<u8>>> {
172let mut buf = vec![];
173 hash.encode(&mut buf)?;
174175let ret = unsafe { get_tx_(buf.as_ptr()) };
176 parse_ret(ret)
177}
178179/// Only metadata() and exec() can call this. Will return transaction
180/// location by provided hash.
181///
182/// ```
183/// (block_height, tx_index) = get_tx_location(hash)?;
184/// ```
185pub fn get_tx_location(hash: &TransactionHash) -> GenericResult<(u32, u16)> {
186let mut buf = vec![];
187 hash.encode(&mut buf)?;
188189let ret = unsafe { get_tx_location_(buf.as_ptr()) };
190let loc_data = parse_ret(ret)?.ok_or(ContractError::DbGetFailed)?;
191let mut cursor = Cursor::new(loc_data);
192Ok((Decodable::decode(&mut cursor)?, Decodable::decode(&mut cursor)?))
193}
194195extern "C" {
196fn set_return_data_(ptr: *const u8, len: u32) -> i64;
197fn get_object_bytes_(ptr: *const u8, len: u32) -> i64;
198fn get_object_size_(len: u32) -> i64;
199200fn get_verifying_block_height_() -> i64;
201fn get_block_target_() -> i64;
202fn get_tx_hash_() -> i64;
203fn get_call_index_() -> i64;
204fn get_blockchain_time_() -> i64;
205fn get_last_block_height_() -> i64;
206fn get_tx_(ptr: *const u8) -> i64;
207fn get_tx_location_(ptr: *const u8) -> i64;
208}