1#![allow(unused_variables)]
14#![allow(clippy::missing_safety_doc)]
15
16macro_rules! unimplemented_ffi {
18 ($fn_name:expr) => {{
19 eprintln!("FFI function {} called but not implemented", $fn_name);
20 let error: u32 = ApiError::Unhandled.into();
21 error as i32
22 }};
23 ($fn_name:expr, void) => {{
24 eprintln!("FFI function {} called but not implemented", $fn_name);
25 }};
26}
27
28use std::{
29 cell::RefCell,
30 collections::{BTreeMap, VecDeque},
31 mem,
32 ptr::NonNull,
33 sync::{Arc, RwLock},
34};
35
36use casper_types::{
37 AccessRights, ApiError, CLTyped, CLValue, Key, StoredValue, U256, U512, URef, URefAddr,
38 api_error,
39 bytesrepr::{self, ToBytes},
40};
41
42#[derive(Debug, Clone)]
44pub struct RevertError {
45 pub status: u32,
46 pub api_error: ApiError,
47}
48
49impl core::fmt::Display for RevertError {
50 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
51 write!(f, "Casper revert: {:?} ({})", self.api_error, self.status)
52 }
53}
54
55impl core::error::Error for RevertError {}
56
57unsafe impl Send for RevertError {}
59unsafe impl Sync for RevertError {}
60
61thread_local! {
63 static REVERT_ERROR: RefCell<Option<RevertError>> = const { RefCell::new(None) };
64}
65
66pub fn check_revert() -> Option<RevertError> {
68 REVERT_ERROR.with(|r| r.borrow().clone())
69}
70
71pub fn clear_revert() {
73 REVERT_ERROR.with(|r| *r.borrow_mut() = None);
74}
75
76#[derive(Debug, Clone, PartialEq, Eq, Hash)]
77pub enum HostFunction {
78 CasperReadValue,
79 CasperWrite,
80 CasperAdd,
81 CasperNewUref,
82 CasperLoadAuthorizationKeys,
83 CasperLoadNamedKeys,
84 CasperRet,
85 CasperGetKey(String),
86 CasperHasKey(String),
87 CasperPutKey(String, Key),
88 CasperRemoveKey(String),
89 CasperRevert,
90 CasperIsValidUref,
91 CasperAddAssociatedKey,
92 CasperRemoveAssociatedKey,
93 CasperUpdateAssociatedKey,
94 CasperSetActionThreshold,
95 CasperGetCaller,
96 CasperGetBlocktime,
97 CasperCreatePurse,
98 CasperTransferToAccount,
99 CasperTransferFromPurseToAccount,
100 CasperTransferFromPurseToPurse,
101 CasperGetBalance,
102 CasperGetPhase,
103 CasperGetSystemContract,
104 CasperGetMainPurse,
105 CasperReadHostBuffer,
106 CasperCreateContractPackageAtHash,
107 CasperCreateContractUserGroup,
108 CasperAddContractVersion,
109 CasperAddContractVersionWithMessageTopics,
110 CasperAddPackageVersionWithMessageTopics,
111 CasperDisableContractVersion,
112 CasperCallContract,
113 CasperCallVersionedContract,
114 CasperGetNamedArgSize,
115 CasperGetNamedArg,
116 CasperRemoveContractUserGroup,
117 CasperProvisionContractUserGroupUref,
118 CasperRemoveContractUserGroupUrefs,
119 CasperBlake2b,
120 CasperLoadCallStack,
121 CasperPrint,
122 CasperNewDictionary,
123 CasperDictionaryGet,
124 CasperDictionaryRead,
125 CasperDictionaryPut,
126 CasperRandomBytes,
127 CasperEnableContractVersion,
128 CasperManageMessageTopic,
129 CasperEmitMessage,
130 CasperLoadCallerInformation,
131 CasperGetBlockInfo,
132 CasperGenericHash,
133 CasperRecoverSecp256k1,
134 CasperVerifySignature,
135 CasperCallPackageVersion,
136}
137
138#[derive(Debug, Default)]
139pub struct EnvImpl {
140 address_generator: U256,
142 database: BTreeMap<Key, StoredValue>,
143 args: BTreeMap<String, CLValue>,
144 named_keys: BTreeMap<String, Key>,
145 host_buffer: Option<CLValue>,
146 dictionaries: BTreeMap<URefAddr, BTreeMap<String, CLValue>>,
147 trace: Vec<HostFunction>,
149}
150
151#[derive(Debug, Clone)]
152pub struct Env {
153 env_impl: Arc<RwLock<EnvImpl>>,
154}
155
156impl EnvImpl {
157 pub fn new() -> Self {
158 Self::default()
159 }
160 pub fn next_address(&mut self) -> [u8; 32] {
161 self.address_generator += U256::one();
162 let mut output = [0; 32];
163 self.address_generator.to_little_endian(&mut output);
164 output
165 }
166}
167
168impl Env {
169 pub fn named_keys(&self) -> BTreeMap<String, Key> {
170 self.env_impl.read().unwrap().named_keys.clone()
171 }
172
173 pub fn trace(&self) -> Vec<HostFunction> {
177 mem::take(&mut self.env_impl.write().unwrap().trace)
178 }
179}
180
181#[derive(Debug)]
182pub struct EnvBuilder {
183 address_generator: U256,
184 database: BTreeMap<Key, StoredValue>,
185 args: BTreeMap<String, CLValue>,
186 named_keys: BTreeMap<String, Key>,
187 dictionaries: BTreeMap<URefAddr, BTreeMap<String, CLValue>>,
188}
189
190impl EnvBuilder {
191 pub fn new() -> Self {
192 Self {
193 address_generator: U256::zero(),
194 database: BTreeMap::new(),
195 args: BTreeMap::new(),
196 named_keys: BTreeMap::new(),
197 dictionaries: BTreeMap::new(),
198 }
199 }
200
201 pub fn with_address_generator(mut self, address_generator: U256) -> Self {
202 self.address_generator = address_generator;
203 self
204 }
205
206 pub fn with_database(mut self, database: BTreeMap<Key, StoredValue>) -> Self {
207 self.database = database;
208 self
209 }
210
211 pub fn with_args(mut self, args: BTreeMap<String, CLValue>) -> Self {
212 self.args = args;
213 self
214 }
215
216 pub fn with_arg<T: ToBytes + CLTyped>(mut self, name: impl Into<String>, value: T) -> Self {
217 let value = CLValue::from_t(value).expect("Failed to convert value to CLValue");
218 self.args.insert(name.into(), value);
219 self
220 }
221
222 pub fn with_storage(mut self, key: Key, value: StoredValue) -> Self {
223 self.database.insert(key, value);
224 self
225 }
226
227 pub fn with_named_keys(mut self, named_keys: BTreeMap<String, Key>) -> Self {
228 self.named_keys = named_keys;
229 self
230 }
231
232 pub fn with_named_key(mut self, name: impl Into<String>, key: Key) -> Self {
233 self.named_keys.insert(name.into(), key);
234 self
235 }
236
237 pub fn build(self) -> Env {
238 Env {
239 env_impl: Arc::new(RwLock::new(EnvImpl {
240 address_generator: self.address_generator,
241 database: self.database,
242 args: self.args,
243 named_keys: self.named_keys,
244 host_buffer: None,
245 dictionaries: self.dictionaries,
246 trace: Vec::new(),
247 })),
248 }
249 }
250}
251
252impl Default for EnvBuilder {
253 fn default() -> Self {
254 Self::new()
255 }
256}
257
258thread_local! {
259 static ENV: RefCell<RwLock<VecDeque<Env>>> = const { RefCell::new(RwLock::new(VecDeque::new())) };
260
261}
262
263pub fn dispatch_with<F>(new_env: Env, func: F)
264where
265 F: FnOnce(&Env),
266{
267 ENV.with(|stack| {
268 let env = stack.borrow();
269 env.write().unwrap().push_back(new_env.clone());
270
271 clear_revert();
273
274 func(&new_env);
277
278 env.write().unwrap().pop_back();
279 })
280}
281
282fn with_current_env<F, R>(func: F) -> R
283where
284 F: FnOnce(&mut EnvImpl) -> R,
285{
286 ENV.with(|stack| {
287 let env = stack.borrow();
288 let binding = env.read().unwrap();
289 let back_mut = binding.back().expect("Env should not be empty");
290 func(&mut back_mut.env_impl.write().unwrap())
291 })
292}
293
294#[unsafe(no_mangle)]
295pub unsafe extern "C" fn casper_read_value(
296 key_ptr: *const u8,
297 key_size: usize,
298 output_size: *mut usize,
299) -> i32 {
300 let key = unsafe { core::slice::from_raw_parts(key_ptr, key_size) };
301 let key: Key = bytesrepr::deserialize_from_slice(key).expect("Failed to deserialize key");
302 let mut output_size = NonNull::new(output_size).expect("output_size pointer must not be null");
303
304 with_current_env(|env| {
305 env.trace.push(HostFunction::CasperReadValue);
306 match env.database.get(&key) {
307 Some(value) => {
308 let cl_value: CLValue = value
309 .clone()
310 .try_into()
311 .expect("Failed to convert to CLValue");
312
313 unsafe {
314 *output_size.as_mut() = cl_value.inner_bytes().len();
315 }
316
317 let old_host_buffer = env.host_buffer.replace(cl_value);
318 if let Some(old_host_buffer) = &old_host_buffer {
319 panic!("Host buffer should be empty before writing to it: {old_host_buffer:?}");
320 }
321
322 0 }
324 None => -1, }
326 })
327}
328#[unsafe(no_mangle)]
329pub unsafe extern "C" fn casper_write(
330 key_ptr: *const u8,
331 key_size: usize,
332 value_ptr: *const u8,
333 value_size: usize,
334) {
335 let key = unsafe { core::slice::from_raw_parts(key_ptr, key_size) };
336 let key: Key = bytesrepr::deserialize_from_slice(key).expect("Failed to deserialize key");
337 let value = unsafe { core::slice::from_raw_parts(value_ptr, value_size) };
338 let value: CLValue =
339 bytesrepr::deserialize_from_slice(value).expect("Failed to deserialize value");
340
341 with_current_env(|env| {
342 env.trace.push(HostFunction::CasperWrite);
343 env.database.insert(key, StoredValue::CLValue(value));
344 })
345}
346#[unsafe(no_mangle)]
347pub unsafe extern "C" fn casper_add(
348 key_ptr: *const u8,
349 key_size: usize,
350 value_ptr: *const u8,
351 value_size: usize,
352) {
353 todo!()
354}
355#[unsafe(no_mangle)]
356pub unsafe extern "C" fn casper_new_uref(
357 uref_ptr: *mut u8,
358 value_ptr: *const u8,
359 value_size: usize,
360) {
361 let value = unsafe { core::slice::from_raw_parts(value_ptr, value_size) };
362 let value: CLValue =
363 bytesrepr::deserialize_from_slice(value).expect("Failed to deserialize value");
364
365 with_current_env(|env| {
366 env.trace.push(HostFunction::CasperNewUref);
367 let uref = URef::new(env.next_address(), AccessRights::READ_ADD_WRITE);
368 let key = Key::URef(uref);
369 env.database.insert(key, StoredValue::CLValue(value));
370
371 let key_bytes = uref.to_bytes().expect("Failed to serialize URef");
372 unsafe {
373 core::ptr::copy_nonoverlapping(key_bytes.as_ptr(), uref_ptr, key_bytes.len());
374 }
375 })
376}
377#[unsafe(no_mangle)]
378pub unsafe extern "C" fn casper_load_authorization_keys(
379 total_keys: *mut usize,
380 result_size: *mut usize,
381) -> i32 {
382 todo!()
383}
384#[unsafe(no_mangle)]
385pub unsafe extern "C" fn casper_load_named_keys(
386 total_keys: *mut usize,
387 result_size: *mut usize,
388) -> i32 {
389 todo!()
390}
391#[unsafe(no_mangle)]
392pub unsafe extern "C" fn casper_ret(value_ptr: *const u8, value_size: usize) -> ! {
393 todo!()
394}
395#[unsafe(no_mangle)]
396pub unsafe extern "C" fn casper_get_key(
397 name_ptr: *const u8,
398 name_size: usize,
399 output_ptr: *mut u8,
400 output_size: usize,
401 bytes_written_ptr: *mut usize,
402) -> i32 {
403 let result = with_current_env(|env| {
404 let name_bytes = unsafe { core::slice::from_raw_parts(name_ptr, name_size) };
405 let name: String =
406 bytesrepr::deserialize_from_slice(name_bytes).expect("Failed to deserialize name");
407 env.trace.push(HostFunction::CasperGetKey(name.clone()));
408
409 match env.named_keys.get(&name) {
410 Some(key) => {
411 let key_bytes = key.to_bytes().expect("Failed to serialize key");
412 if key_bytes.len() > output_size {
413 return Err(ApiError::BufferTooSmall);
414 }
415 unsafe {
416 core::ptr::copy_nonoverlapping(key_bytes.as_ptr(), output_ptr, key_bytes.len());
417 *bytes_written_ptr = key_bytes.len();
418 }
419 Ok(()) }
421 None => Err(ApiError::MissingKey), }
423 });
424 api_error::i32_from(result)
425}
426#[unsafe(no_mangle)]
427pub unsafe extern "C" fn casper_has_key(name_ptr: *const u8, name_size: usize) -> i32 {
428 with_current_env(|env| {
429 let name_bytes = unsafe { core::slice::from_raw_parts(name_ptr, name_size) };
430 let name: String =
431 bytesrepr::deserialize_from_slice(name_bytes).expect("Failed to deserialize name");
432 env.trace.push(HostFunction::CasperHasKey(name.clone()));
433 if env.named_keys.contains_key(&name) {
434 0 } else {
436 1 }
438 })
439}
440#[unsafe(no_mangle)]
441pub unsafe extern "C" fn casper_put_key(
442 name_ptr: *const u8,
443 name_size: usize,
444 key_ptr: *const u8,
445 key_size: usize,
446) {
447 with_current_env(|env| {
448 let name_bytes = unsafe { core::slice::from_raw_parts(name_ptr, name_size) };
449 let name: String =
450 bytesrepr::deserialize_from_slice(name_bytes).expect("Failed to deserialize name");
451 let key_bytes = unsafe { core::slice::from_raw_parts(key_ptr, key_size) };
452 let key: Key =
453 bytesrepr::deserialize_from_slice(key_bytes).expect("Failed to deserialize key");
454 env.trace
455 .push(HostFunction::CasperPutKey(name.clone(), key));
456 env.named_keys.insert(name, key);
457 });
458}
459#[unsafe(no_mangle)]
460pub unsafe extern "C" fn casper_remove_key(name_ptr: *const u8, name_size: usize) {
461 with_current_env(|env| {
462 let name_bytes = unsafe { core::slice::from_raw_parts(name_ptr, name_size) };
463 let name: String =
464 bytesrepr::deserialize_from_slice(name_bytes).expect("Failed to deserialize name");
465 env.trace.push(HostFunction::CasperRemoveKey(name.clone()));
466 env.named_keys.remove(&name);
467 });
468}
469#[unsafe(no_mangle)]
470pub unsafe extern "C" fn casper_revert(status: u32) -> ! {
471 let api_error = ApiError::from(status);
472
473 REVERT_ERROR.with(|r| *r.borrow_mut() = Some(RevertError { status, api_error }));
475
476 eprintln!("=== CASPER REVERT ===");
478 eprintln!("Status: {}", status);
479 eprintln!("API Error: {:?}", api_error);
480 eprintln!("This indicates the smart contract execution was reverted.");
481 eprintln!("====================");
482
483 std::process::abort();
485}
486#[unsafe(no_mangle)]
487pub unsafe extern "C" fn casper_is_valid_uref(uref_ptr: *const u8, uref_size: usize) -> i32 {
488 todo!()
489}
490#[unsafe(no_mangle)]
491pub unsafe extern "C" fn casper_add_associated_key(
492 account_hash_ptr: *const u8,
493 account_hash_size: usize,
494 weight: i32,
495) -> i32 {
496 todo!()
497}
498#[unsafe(no_mangle)]
499pub unsafe extern "C" fn casper_remove_associated_key(
500 account_hash_ptr: *const u8,
501 account_hash_size: usize,
502) -> i32 {
503 todo!()
504}
505#[unsafe(no_mangle)]
506pub unsafe extern "C" fn casper_update_associated_key(
507 account_hash_ptr: *const u8,
508 account_hash_size: usize,
509 weight: i32,
510) -> i32 {
511 todo!()
512}
513#[unsafe(no_mangle)]
514pub unsafe extern "C" fn casper_set_action_threshold(permission_level: u32, threshold: u32) -> i32 {
515 todo!()
516}
517#[unsafe(no_mangle)]
518pub unsafe extern "C" fn casper_get_caller(output_size_ptr: *mut usize) -> i32 {
519 todo!()
520}
521#[unsafe(no_mangle)]
522pub unsafe extern "C" fn casper_get_blocktime(dest_ptr: *const u8) {
523 todo!()
524}
525#[unsafe(no_mangle)]
526pub unsafe extern "C" fn casper_create_purse(purse_ptr: *mut u8, purse_size: usize) -> i32 {
527 with_current_env(|env| {
528 env.trace.push(HostFunction::CasperCreatePurse);
529 let uref = URef::new(env.next_address(), AccessRights::READ_ADD_WRITE);
530 let key_1 = Key::URef(uref);
531 let value_1 = StoredValue::CLValue(CLValue::unit());
532 env.database.insert(key_1, value_1);
533
534 let key_2 = Key::Balance(uref.addr());
535 let value_2 = StoredValue::CLValue(
536 CLValue::from_t(U512::zero()).expect("Failed to create CLValue for balance"),
537 );
538 env.database.insert(key_2, value_2);
539
540 let key_bytes = uref.to_bytes().expect("Failed to serialize URef");
541 unsafe {
542 core::ptr::copy_nonoverlapping(key_bytes.as_ptr(), purse_ptr, purse_size);
543 }
544 });
545
546 0 }
548#[unsafe(no_mangle)]
549pub unsafe extern "C" fn casper_transfer_to_account(
550 target_ptr: *const u8,
551 target_size: usize,
552 amount_ptr: *const u8,
553 amount_size: usize,
554 id_ptr: *const u8,
555 id_size: usize,
556 result_ptr: *const i32,
557) -> i32 {
558 todo!()
559}
560#[unsafe(no_mangle)]
561pub unsafe extern "C" fn casper_transfer_from_purse_to_account(
562 source_ptr: *const u8,
563 source_size: usize,
564 target_ptr: *const u8,
565 target_size: usize,
566 amount_ptr: *const u8,
567 amount_size: usize,
568 id_ptr: *const u8,
569 id_size: usize,
570 result_ptr: *const i32,
571) -> i32 {
572 todo!()
573}
574#[unsafe(no_mangle)]
575pub unsafe extern "C" fn casper_transfer_from_purse_to_purse(
576 source_ptr: *const u8,
577 source_size: usize,
578 target_ptr: *const u8,
579 target_size: usize,
580 amount_ptr: *const u8,
581 amount_size: usize,
582 id_ptr: *const u8,
583 id_size: usize,
584) -> i32 {
585 todo!()
586}
587#[unsafe(no_mangle)]
588pub unsafe extern "C" fn casper_get_balance(
589 purse_ptr: *const u8,
590 purse_size: usize,
591 result_size: *mut usize,
592) -> i32 {
593 todo!()
594}
595#[unsafe(no_mangle)]
596pub unsafe extern "C" fn casper_get_phase(dest_ptr: *mut u8) {
597 todo!()
598}
599#[unsafe(no_mangle)]
600pub unsafe extern "C" fn casper_get_system_contract(
601 system_contract_index: u32,
602 dest_ptr: *mut u8,
603 dest_size: usize,
604) -> i32 {
605 todo!()
606}
607#[unsafe(no_mangle)]
608pub unsafe extern "C" fn casper_get_main_purse(dest_ptr: *mut u8) {
609 todo!()
610}
611#[unsafe(no_mangle)]
612pub unsafe extern "C" fn casper_read_host_buffer(
613 dest_ptr: *mut u8,
614 dest_size: usize,
615 bytes_written: *mut usize,
616) -> i32 {
617 let result = with_current_env(|env| match env.host_buffer.take() {
618 Some(host_buffer) => {
619 let bytes = host_buffer.inner_bytes();
620
621 unsafe {
622 *bytes_written = bytes.len();
623 assert_eq!(bytes.len(), dest_size, "Host buffer size mismatch");
624 core::ptr::copy_nonoverlapping(bytes.as_ptr(), dest_ptr, dest_size);
625 }
626 Ok(())
627 }
628 None => Err(ApiError::HostBufferEmpty),
629 });
630 api_error::i32_from(result)
631}
632#[unsafe(no_mangle)]
633pub unsafe extern "C" fn casper_create_contract_package_at_hash(
634 hash_addr_ptr: *mut u8,
635 access_addr_ptr: *mut u8,
636 is_locked: bool,
637) {
638 todo!();
639}
640#[unsafe(no_mangle)]
641pub unsafe extern "C" fn casper_create_contract_user_group(
642 contract_package_hash_ptr: *const u8,
643 contract_package_hash_size: usize,
644 label_ptr: *const u8,
645 label_size: usize,
646 num_new_urefs: u8,
647 existing_urefs_ptr: *const u8,
648 existing_urefs_size: usize,
649 output_size_ptr: *mut usize,
650) -> i32 {
651 todo!()
652}
653#[unsafe(no_mangle)]
654pub unsafe extern "C" fn casper_add_contract_version(
655 contract_package_hash_ptr: *const u8,
656 contract_package_hash_size: usize,
657 version_ptr: *const u32,
658 entry_points_ptr: *const u8,
659 entry_points_size: usize,
660 named_keys_ptr: *const u8,
661 named_keys_size: usize,
662 output_ptr: *mut u8,
663 output_size: usize,
664 bytes_written_ptr: *mut usize,
665) -> i32 {
666 todo!()
667}
668#[unsafe(no_mangle)]
669pub unsafe extern "C" fn casper_add_contract_version_with_message_topics(
670 contract_package_hash_ptr: *const u8,
671 contract_package_hash_size: usize,
672 version_ptr: *const u32,
673 entry_points_ptr: *const u8,
674 entry_points_size: usize,
675 named_keys_ptr: *const u8,
676 named_keys_size: usize,
677 message_topics_ptr: *const u8,
678 message_topics_size: usize,
679 output_ptr: *mut u8,
680 output_size: usize,
681) -> i32 {
682 0
683}
684#[unsafe(no_mangle)]
685pub unsafe extern "C" fn casper_add_package_version_with_message_topics(
686 package_hash_ptr: *const u8,
687 package_hash_size: usize,
688 version_ptr: *const u32,
689 entry_points_ptr: *const u8,
690 entry_points_size: usize,
691 named_keys_ptr: *const u8,
692 named_keys_size: usize,
693 message_topics_ptr: *const u8,
694 message_topics_size: usize,
695 output_ptr: *mut u8,
696 output_size: usize,
697) -> i32 {
698 todo!()
699}
700#[unsafe(no_mangle)]
701pub unsafe extern "C" fn casper_disable_contract_version(
702 contract_package_hash_ptr: *const u8,
703 contract_package_hash_size: usize,
704 contract_hash_ptr: *const u8,
705 contract_hash_size: usize,
706) -> i32 {
707 todo!()
708}
709#[unsafe(no_mangle)]
710pub unsafe extern "C" fn casper_call_contract(
711 contract_hash_ptr: *const u8,
712 contract_hash_size: usize,
713 entry_point_name_ptr: *const u8,
714 entry_point_name_size: usize,
715 runtime_args_ptr: *const u8,
716 runtime_args_size: usize,
717 result_size: *mut usize,
718) -> i32 {
719 todo!()
720}
721#[unsafe(no_mangle)]
722pub unsafe extern "C" fn casper_call_versioned_contract(
723 contract_package_hash_ptr: *const u8,
724 contract_package_hash_size: usize,
725 contract_version_ptr: *const u8,
726 contract_version_size: usize,
727 entry_point_name_ptr: *const u8,
728 entry_point_name_size: usize,
729 runtime_args_ptr: *const u8,
730 runtime_args_size: usize,
731 result_size: *mut usize,
732) -> i32 {
733 todo!()
734}
735
736#[unsafe(no_mangle)]
737pub unsafe extern "C" fn casper_get_named_arg_size(
738 name_ptr: *const u8,
739 name_size: usize,
740 dest_size: *mut usize,
741) -> i32 {
742 let name: &[u8] = unsafe { core::slice::from_raw_parts(name_ptr, name_size) };
743 let name: &str = core::str::from_utf8(name).expect("Failed to convert bytes to str");
744 with_current_env(|env| {
745 env.trace.push(HostFunction::CasperGetNamedArgSize);
746 match env.args.get(name) {
747 Some(value) => {
748 let size = value.inner_bytes().len();
749 unsafe {
750 *dest_size = size;
751 }
752 0 }
754 None => {
755 unsafe {
756 *dest_size = 0;
757 }
758 let i: u32 = ApiError::MissingArgument.into();
759 i as i32 }
761 }
762 })
763}
764#[unsafe(no_mangle)]
765pub unsafe extern "C" fn casper_get_named_arg(
766 name_ptr: *const u8,
767 name_size: usize,
768 dest_ptr: *mut u8,
769 dest_size: usize,
770) -> i32 {
771 let name: &[u8] = unsafe { core::slice::from_raw_parts(name_ptr, name_size) };
772 let name: &str = core::str::from_utf8(name).expect("Failed to convert bytes to str");
773 let result = with_current_env(|env| {
774 env.trace.push(HostFunction::CasperGetNamedArg);
775 match env.args.get(name) {
776 Some(value) => {
777 let bytes = value.inner_bytes();
778 if bytes.len() > dest_size {
779 return Err(ApiError::BufferTooSmall);
780 }
781 unsafe {
782 core::ptr::copy_nonoverlapping(bytes.as_ptr(), dest_ptr, bytes.len());
783 }
784 Ok(()) }
786 None => Err(ApiError::MissingArgument),
787 }
788 });
789
790 api_error::i32_from(result)
791}
792#[unsafe(no_mangle)]
793pub unsafe extern "C" fn casper_remove_contract_user_group(
794 contract_package_hash_ptr: *const u8,
795 contract_package_hash_size: usize,
796 label_ptr: *const u8,
797 label_size: usize,
798) -> i32 {
799 todo!()
800}
801#[unsafe(no_mangle)]
802pub unsafe extern "C" fn casper_provision_contract_user_group_uref(
803 contract_package_hash_ptr: *const u8,
804 contract_package_hash_size: usize,
805 label_ptr: *const u8,
806 label_size: usize,
807 value_size_ptr: *const usize,
808) -> i32 {
809 todo!()
810}
811#[unsafe(no_mangle)]
812pub unsafe extern "C" fn casper_remove_contract_user_group_urefs(
813 contract_package_hash_ptr: *const u8,
814 contract_package_hash_size: usize,
815 label_ptr: *const u8,
816 label_size: usize,
817 urefs_ptr: *const u8,
818 urefs_size: usize,
819) -> i32 {
820 todo!()
821}
822#[deprecated(note = "Superseded by ext_ffi::casper_generic_hash")]
823#[unsafe(no_mangle)]
824pub unsafe extern "C" fn casper_blake2b(
825 in_ptr: *const u8,
826 in_size: usize,
827 out_ptr: *mut u8,
828 out_size: usize,
829) -> i32 {
830 todo!()
831}
832#[deprecated]
833#[unsafe(no_mangle)]
834pub unsafe extern "C" fn casper_load_call_stack(
835 call_stack_len_ptr: *mut usize,
836 result_size_ptr: *mut usize,
837) -> i32 {
838 todo!()
839}
840
841#[unsafe(no_mangle)]
842pub unsafe extern "C" fn casper_print(text_ptr: *const u8, text_size: usize) {
843 let text: &[u8] = unsafe { core::slice::from_raw_parts(text_ptr, text_size) };
844 let text: String =
845 bytesrepr::deserialize_from_slice(text).expect("Failed to deserialize text for printing");
846
847 eprintln!("Print: {text}");
848}
849
850#[unsafe(no_mangle)]
854pub unsafe extern "C" fn casper_new_dictionary(output_size_ptr: *mut usize) -> i32 {
855 with_current_env(|env| {
856 let uref = URef::new(env.next_address(), AccessRights::READ_ADD_WRITE);
857 let key = Key::URef(uref);
858
859 let cl_value = CLValue::unit();
860
861 env.database
862 .insert(key, StoredValue::CLValue(cl_value.clone()));
863
864 env.dictionaries.entry(uref.addr()).or_default();
865
866 let old_host_buffer = env
867 .host_buffer
868 .replace(CLValue::from_t(uref).expect("Failed to create CLValue from URef"));
869 if let Some(old_value) = old_host_buffer {
870 panic!("Host buffer already contains a value, cannot overwrite it: {old_value:?}");
871 }
872 let key_bytes = uref.to_bytes().expect("Failed to serialize URef");
873 unsafe {
874 *output_size_ptr = key_bytes.len();
875 }
876 0 })
878}
879#[unsafe(no_mangle)]
880pub unsafe extern "C" fn casper_dictionary_get(
881 uref_ptr: *const u8,
882 uref_size: usize,
883 key_bytes_ptr: *const u8,
884 key_bytes_size: usize,
885 output_size: *mut usize,
886) -> i32 {
887 todo!()
888}
889#[unsafe(no_mangle)]
890pub unsafe extern "C" fn casper_dictionary_read(
891 key_ptr: *const u8,
892 key_size: usize,
893 output_size: *mut usize,
894) -> i32 {
895 todo!()
896}
897#[unsafe(no_mangle)]
901pub unsafe extern "C" fn casper_dictionary_put(
902 uref_ptr: *const u8,
903 uref_size: usize,
904 key_ptr: *const u8,
905 key_size: usize,
906 value_ptr: *const u8,
907 value_size: usize,
908) -> i32 {
909 with_current_env(|env| {
910 let uref_bytes = unsafe { core::slice::from_raw_parts(uref_ptr, uref_size) };
911 let uref: URef =
912 bytesrepr::deserialize_from_slice(uref_bytes).expect("Failed to deserialize URef");
913
914 let key_bytes = unsafe { core::slice::from_raw_parts(key_ptr, key_size) };
915 let key =
916 String::from_utf8(key_bytes.to_vec()).expect("Failed to convert key bytes to String");
917
918 let value_bytes = unsafe { core::slice::from_raw_parts(value_ptr, value_size) };
919 let value: CLValue =
920 bytesrepr::deserialize_from_slice(value_bytes).expect("Failed to deserialize value");
921
922 if let Some(dict) = env.dictionaries.get_mut(&uref.addr()) {
923 dict.insert(key, value);
924 0 } else {
926 -1 }
928 })
929}
930#[unsafe(no_mangle)]
931pub unsafe extern "C" fn casper_random_bytes(out_ptr: *mut u8, out_size: usize) -> i32 {
932 todo!()
933}
934#[unsafe(no_mangle)]
935pub unsafe extern "C" fn casper_enable_contract_version(
936 contract_package_hash_ptr: *const u8,
937 contract_package_hash_size: usize,
938 contract_hash_ptr: *const u8,
939 contract_hash_size: usize,
940) -> i32 {
941 todo!()
942}
943#[unsafe(no_mangle)]
944pub unsafe extern "C" fn casper_manage_message_topic(
945 topic_name_ptr: *const u8,
946 topic_name_size: usize,
947 operation_ptr: *const u8,
948 operation_size: usize,
949) -> i32 {
950 todo!()
951}
952#[unsafe(no_mangle)]
953pub unsafe extern "C" fn casper_emit_message(
954 topic_name_ptr: *const u8,
955 topic_name_size: usize,
956 message_ptr: *const u8,
957 message_size: usize,
958) -> i32 {
959 todo!()
960}
961
962#[unsafe(no_mangle)]
963pub unsafe extern "C" fn casper_load_caller_information(
964 action: u8,
965 call_stack_len_ptr: *mut usize,
966 result_size_ptr: *mut usize,
967) -> i32 {
968 unimplemented_ffi!("casper_load_caller_information")
969}
970
971#[unsafe(no_mangle)]
972pub unsafe extern "C" fn casper_get_block_info(field_idx: u8, dest_ptr: *const u8) {
973 todo!("casper_get_block_info")
974}
975
976#[allow(dead_code)]
978fn keccak256<T: AsRef<[u8]>>(data: T) -> [u8; 32] {
979 use keccak_asm::Digest as KeccakDigest;
980 use keccak_asm::Keccak256;
981
982 let mut h = Keccak256::new();
983 KeccakDigest::update(&mut h, &data);
984 let mut out = [0u8; 32];
985 let result = KeccakDigest::finalize(h);
986 out.copy_from_slice(&result);
987 out
988}
989
990#[unsafe(no_mangle)]
991pub unsafe extern "C" fn casper_generic_hash(
992 in_ptr: *const u8,
993 in_size: usize,
994 hash_algo_type: u8,
995 out_ptr: *const u8,
996 out_size: usize,
997) -> i32 {
998 let result = {
999 Err(ApiError::InvalidArgument)
1002 };
1003
1004 api_error::i32_from(result)
1005}
1006
1007#[unsafe(no_mangle)]
1008pub unsafe extern "C" fn casper_recover_secp256k1(
1009 message_ptr: *const u8,
1010 message_size: usize,
1011 signature_ptr: *const u8,
1012 signature_size: usize,
1013 out_ptr: *const u8,
1014 recovery_id: u8,
1015) -> i32 {
1016 todo!()
1017}
1018
1019#[unsafe(no_mangle)]
1020pub unsafe extern "C" fn casper_verify_signature(
1021 message_ptr: *const u8,
1022 message_size: usize,
1023 signature_ptr: *const u8,
1024 signature_size: usize,
1025 public_key_ptr: *const u8,
1026 public_key_size: usize,
1027) -> i32 {
1028 todo!()
1029}
1030
1031#[unsafe(no_mangle)]
1032pub unsafe extern "C" fn casper_call_package_version(
1033 contract_package_hash_ptr: *const u8,
1034 contract_package_hash_size: usize,
1035 major_version_ptr: *const u8,
1036 major_version_size: usize,
1037 contract_version_ptr: *const u8,
1038 contract_version_size: usize,
1039 entry_point_name_ptr: *const u8,
1040 entry_point_name_size: usize,
1041 runtime_args_ptr: *const u8,
1042 runtime_args_size: usize,
1043 result_size: *mut usize,
1044) -> i32 {
1045 todo!()
1046}