1mod error;
2mod externf;
3use ave_common::ValueWrapper;
4use borsh::{BorshDeserialize, BorshSerialize};
5use error::Error;
6use serde::{Deserialize, Serialize};
7
8const MAX_DATA_SIZE: i32 = 10_000_000; #[derive(Serialize, Deserialize, Debug)]
14pub struct Context<Event> {
15 pub event: Event,
17 pub is_owner: bool,
19}
20
21#[derive(Serialize, Deserialize, Debug)]
23pub struct ContractResult<State> {
24 pub state: State,
26 pub success: bool,
28 pub error: String,
30}
31
32#[derive(Serialize, Deserialize, Debug, Default)]
34pub struct ContractInitCheck {
35 pub success: bool,
37 pub error: String,
39}
40
41#[derive(BorshSerialize)]
43struct ContractResultBorsh {
44 pub final_state: ValueWrapper,
46 pub success: bool,
48 pub error: String,
50}
51
52impl ContractResultBorsh {
53 pub fn error(error: &str) -> Self {
55 Self {
56 final_state: ValueWrapper(serde_json::Value::Null),
57 success: false,
58 error: error.to_owned(),
59 }
60 }
61}
62
63#[derive(BorshSerialize)]
65struct ContractInitCheckBorsh {
66 pub success: bool,
68 pub error: String,
70}
71
72impl ContractInitCheckBorsh {
73 pub fn error(error: &str) -> Self {
75 Self {
76 success: false,
77 error: error.to_owned(),
78 }
79 }
80
81 pub fn ok() -> Self {
83 Self {
84 success: true,
85 error: String::default(),
86 }
87 }
88}
89
90impl<State> ContractResult<State> {
91 pub fn new(state: State) -> Self {
95 Self {
96 state,
97 success: false,
98 error: String::default(),
99 }
100 }
101}
102
103pub fn check_init_data<State, F>(state_ptr: i32, callback: F) -> u32
133where
134 State: for<'a> Deserialize<'a> + Serialize + Clone,
135 F: Fn(&State, &mut ContractInitCheck),
136{
137 {
138 let error: String;
139 'process: {
140 let Ok(state_bytes) = get_from_context(state_ptr) else {
141 error = "Can not read State from host memory".to_owned();
142 break 'process;
143 };
144 let Ok(state_value) = deserialize(state_bytes) else {
145 error = "Can not deserialize State".to_owned();
146 break 'process;
147 };
148 let Ok(state) = serde_json::from_value::<State>(state_value.0) else {
149 error = "Can not convert State from value".to_owned();
150 break 'process;
151 };
152 let mut contract_result = ContractInitCheck::default();
153 callback(&state, &mut contract_result);
154
155 if !contract_result.success {
156 error = format!(
157 "Error running init contract data: {}",
158 contract_result.error
159 );
160 break 'process;
161 }
162
163 let Ok(result_ptr) = store(&ContractInitCheckBorsh::ok()) else {
164 error = "Can not return init contract result".to_owned();
165 break 'process;
166 };
167 return result_ptr;
168 }
169 store(&ContractInitCheckBorsh::error(&error)).unwrap_or(0)
172 }
173}
174
175pub fn execute_contract<F, State, Event>(
225 state_ptr: i32,
226 init_state_ptr: i32,
227 event_ptr: i32,
228 is_owner: i32,
229 callback: F,
230) -> u32
231where
232 State: for<'a> Deserialize<'a> + Serialize + Clone,
233 Event: for<'a> Deserialize<'a> + Serialize,
234 F: Fn(&Context<Event>, &mut ContractResult<State>),
235{
236 {
237 let error: String;
238 'process: {
239 let Ok(state_bytes) = get_from_context(state_ptr) else {
240 error = "Can not read State from host memory".to_owned();
241 break 'process;
242 };
243 let Ok(state_value) = deserialize(state_bytes) else {
244 error = "Can not deserialize State".to_owned();
245 break 'process;
246 };
247 let state = match serde_json::from_value::<State>(state_value.0) {
248 Ok(state) => state,
249 Err(_) => {
250 let Ok(init_state_bytes) = get_from_context(init_state_ptr) else {
251 error = "Can not read Init State from host memory".to_owned();
252 break 'process;
253 };
254 let Ok(init_state) = deserialize(init_state_bytes) else {
255 error = "Can not deserialize Init State".to_owned();
256 break 'process;
257 };
258
259 let Ok(init_state) = serde_json::from_value::<State>(init_state.0) else {
260 error = "Can not convert State from value".to_owned();
261 break 'process;
262 };
263
264 init_state
265 }
266 };
267 let Ok(event_bytes) = get_from_context(event_ptr) else {
268 error = "Can not read Event from host memory".to_owned();
269 break 'process;
270 };
271 let Ok(event_value) = deserialize(event_bytes) else {
272 error = "Can not deserialize Event".to_owned();
273 break 'process;
274 };
275 let Ok(event) = serde_json::from_value::<Event>(event_value.0) else {
276 error = "Can not convert Event from value".to_owned();
277 break 'process;
278 };
279 let is_owner = is_owner == 1;
280 let context = Context { event, is_owner };
281 let mut contract_result = ContractResult::new(state);
282 callback(&context, &mut contract_result);
283 let Ok(state_value) = serde_json::to_value(&contract_result.state) else {
284 error = "Can not convert contract final state into Value".to_owned();
285 break 'process;
286 };
287 let result = ContractResultBorsh {
288 final_state: ValueWrapper(state_value),
289 success: contract_result.success,
290 error: format!("Error running contract event: {}", contract_result.error),
291 };
292 let Ok(result_ptr) = store(&result) else {
293 error = "Can not return contract result".to_owned();
294 break 'process;
295 };
296 return result_ptr;
297 };
298 store(&ContractResultBorsh::error(&error)).unwrap_or(0)
301 }
302}
303
304fn deserialize(bytes: Vec<u8>) -> Result<ValueWrapper, Error> {
306 BorshDeserialize::try_from_slice(&bytes).map_err(|e| Error::Deserialization(e.to_string()))
307}
308
309fn serialize<S: BorshSerialize>(data: S) -> Result<Vec<u8>, Error> {
311 borsh::to_vec(&data).map_err(|e| Error::Serialization(e.to_string()))
312}
313
314fn get_from_context(pointer: i32) -> Result<Vec<u8>, Error> {
318 unsafe {
319 let len = externf::pointer_len(pointer);
320
321 if len > MAX_DATA_SIZE {
323 return Err(Error::MemoryLimitExceeded {
324 requested: len as usize,
325 max: MAX_DATA_SIZE as usize,
326 });
327 }
328
329 if len < 0 {
331 return Err(Error::Deserialization(
332 "Invalid negative length from host".to_owned(),
333 ));
334 }
335
336 let mut data = Vec::with_capacity(len as usize);
337 for i in 0..len {
338 let read_ptr = pointer.checked_add(i).ok_or_else(|| {
340 Error::IntegerOverflow(format!("Pointer arithmetic overflow: {} + {}", pointer, i))
341 })?;
342 data.push(externf::read_byte(read_ptr));
343 }
344 Ok(data)
345 }
346}
347
348fn store<S>(data: &S) -> Result<u32, Error>
352where
353 S: BorshSerialize,
354{
355 let bytes = serialize(data).map_err(|e| Error::Serialization(e.to_string()))?;
356
357 let len = u32::try_from(bytes.len()).map_err(|_| {
359 Error::IntegerOverflow(format!(
360 "Serialized data too large: {} bytes exceeds u32::MAX",
361 bytes.len()
362 ))
363 })?;
364
365 unsafe {
366 let ptr = externf::alloc(len) as u32;
367 for (index, byte) in bytes.into_iter().enumerate() {
368 externf::write_byte(ptr, index as u32, byte);
369 }
370 Ok(ptr)
371 }
372}
373
374#[cfg(test)]
375mod tests {
376 use super::*;
377 use serde::{Deserialize, Serialize};
378
379 #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
380 struct TestState {
381 value: i32,
382 name: String,
383 }
384
385 #[derive(Serialize, Deserialize, Debug)]
386 enum TestEvent {
387 Increment,
388 Decrement,
389 SetValue(i32),
390 Rename(String),
391 }
392
393 #[test]
394 fn test_context_creation() {
395 let event = TestEvent::Increment;
396 let context = Context {
397 event,
398 is_owner: true,
399 };
400 assert!(context.is_owner);
401 }
402
403 #[test]
404 fn test_contract_result_new() {
405 let state = TestState {
406 value: 42,
407 name: "test".to_string(),
408 };
409 let result = ContractResult::new(state.clone());
410 assert_eq!(result.state.value, 42);
411 assert!(!result.success);
412 assert_eq!(result.error, "");
413 }
414
415 #[test]
416 fn test_contract_result_success() {
417 let state = TestState {
418 value: 10,
419 name: "Alice".to_string(),
420 };
421 let mut result = ContractResult::new(state);
422 result.state.value = 20;
423 result.success = true;
424
425 assert_eq!(result.state.value, 20);
426 assert!(result.success);
427 assert_eq!(result.error, "");
428 }
429
430 #[test]
431 fn test_contract_result_error() {
432 let state = TestState {
433 value: 5,
434 name: "Bob".to_string(),
435 };
436 let mut result = ContractResult::new(state);
437 result.success = false;
438 result.error = "Invalid operation".to_string();
439
440 assert!(!result.success);
441 assert_eq!(result.error, "Invalid operation");
442 }
443
444 #[test]
445 fn test_contract_init_check_default() {
446 let check = ContractInitCheck::default();
447 assert!(!check.success);
448 assert_eq!(check.error, "");
449 }
450
451 #[test]
452 fn test_contract_init_check_success() {
453 let mut check = ContractInitCheck::default();
454 check.success = true;
455 assert!(check.success);
456 assert_eq!(check.error, "");
457 }
458
459 #[test]
460 fn test_contract_init_check_error() {
461 let mut check = ContractInitCheck::default();
462 check.success = false;
463 check.error = "Invalid initial state".to_string();
464 assert!(!check.success);
465 assert_eq!(check.error, "Invalid initial state");
466 }
467
468 #[test]
469 fn test_contract_result_borsh_error() {
470 let result = ContractResultBorsh::error("test error");
471 assert!(!result.success);
472 assert_eq!(result.error, "test error");
473 assert_eq!(result.final_state.0, serde_json::Value::Null);
474 }
475
476 #[test]
477 fn test_contract_init_check_borsh_ok() {
478 let result = ContractInitCheckBorsh::ok();
479 assert!(result.success);
480 assert_eq!(result.error, "");
481 }
482
483 #[test]
484 fn test_contract_init_check_borsh_error() {
485 let result = ContractInitCheckBorsh::error("validation failed");
486 assert!(!result.success);
487 assert_eq!(result.error, "validation failed");
488 }
489
490 #[test]
491 fn test_serialize_deserialize_roundtrip() {
492 let state = TestState {
493 value: 100,
494 name: "test".to_string(),
495 };
496 let value = serde_json::to_value(&state).unwrap();
497 let wrapper = ValueWrapper(value);
498
499 let serialized = serialize(&wrapper).unwrap();
500 let deserialized = deserialize(serialized).unwrap();
501
502 let recovered_state: TestState = serde_json::from_value(deserialized.0).unwrap();
503 assert_eq!(recovered_state.value, 100);
504 assert_eq!(recovered_state.name, "test");
505 }
506
507 #[test]
508 fn test_serialize_contract_result_borsh() {
509 let state = TestState {
510 value: 42,
511 name: "Alice".to_string(),
512 };
513 let state_value = serde_json::to_value(&state).unwrap();
514 let result = ContractResultBorsh {
515 final_state: ValueWrapper(state_value),
516 success: true,
517 error: String::new(),
518 };
519
520 let serialized = serialize(&result);
521 assert!(serialized.is_ok());
522 }
523
524 #[test]
525 fn test_serialize_contract_init_check_borsh() {
526 let check = ContractInitCheckBorsh {
527 success: true,
528 error: String::new(),
529 };
530
531 let serialized = serialize(&check);
532 assert!(serialized.is_ok());
533 }
534
535 #[test]
536 fn test_deserialize_invalid_data() {
537 let invalid_bytes = vec![0xFF, 0xFF, 0xFF, 0xFF];
538 let result = deserialize(invalid_bytes);
539 assert!(result.is_err());
540 }
541
542 #[test]
543 fn test_context_is_owner_true() {
544 let event = TestEvent::SetValue(100);
545 let context = Context {
546 event,
547 is_owner: true,
548 };
549 assert!(context.is_owner);
550 }
551
552 #[test]
553 fn test_context_is_owner_false() {
554 let event = TestEvent::SetValue(100);
555 let context = Context {
556 event,
557 is_owner: false,
558 };
559 assert!(!context.is_owner);
560 }
561
562 #[test]
563 fn test_contract_result_state_modification() {
564 let initial_state = TestState {
565 value: 0,
566 name: "Initial".to_string(),
567 };
568 let mut result = ContractResult::new(initial_state);
569
570 result.state.value = 999;
571 result.state.name = "Modified".to_string();
572 result.success = true;
573
574 assert_eq!(result.state.value, 999);
575 assert_eq!(result.state.name, "Modified");
576 assert!(result.success);
577 }
578
579 #[test]
580 fn test_serialize_complex_nested_structure() {
581 let mut inner_map = serde_json::Map::new();
582 inner_map.insert("nested".to_string(), serde_json::json!({"deep": "value"}));
583
584 let complex_value = serde_json::json!({
585 "array": [1, 2, 3],
586 "object": inner_map,
587 "string": "test",
588 "number": 42,
589 "bool": true,
590 "null": null
591 });
592
593 let wrapper = ValueWrapper(complex_value);
594 let serialized = serialize(&wrapper).unwrap();
595 let deserialized = deserialize(serialized).unwrap();
596
597 assert_eq!(wrapper, deserialized);
598 }
599
600 #[test]
601 fn test_max_data_size_constant() {
602 assert_eq!(MAX_DATA_SIZE, 10_000_000);
603 }
604
605 #[test]
606 fn test_contract_result_json_serialization() {
607 let state = TestState {
608 value: 123,
609 name: "JsonTest".to_string(),
610 };
611 let result = ContractResult {
612 state,
613 success: true,
614 error: String::new(),
615 };
616
617 let json = serde_json::to_string(&result);
618 assert!(json.is_ok());
619
620 let json_str = json.unwrap();
621 assert!(json_str.contains("123"));
622 assert!(json_str.contains("JsonTest"));
623 assert!(json_str.contains("true"));
624 }
625
626 #[test]
627 fn test_context_json_serialization() {
628 let event = TestEvent::Increment;
629 let context = Context {
630 event,
631 is_owner: true,
632 };
633
634 let json = serde_json::to_string(&context);
635 assert!(json.is_ok());
636 }
637
638 #[test]
639 fn test_contract_init_check_json_serialization() {
640 let check = ContractInitCheck {
641 success: true,
642 error: String::new(),
643 };
644
645 let json = serde_json::to_string(&check);
646 assert!(json.is_ok());
647
648 let json_str = json.unwrap();
649 assert!(json_str.contains("true"));
650 }
651
652 #[test]
653 fn test_multiple_contract_results() {
654 let states = vec![
655 TestState {
656 value: 1,
657 name: "one".to_string(),
658 },
659 TestState {
660 value: 2,
661 name: "two".to_string(),
662 },
663 TestState {
664 value: 3,
665 name: "three".to_string(),
666 },
667 ];
668
669 let results: Vec<ContractResult<TestState>> =
670 states.into_iter().map(ContractResult::new).collect();
671
672 assert_eq!(results.len(), 3);
673 assert_eq!(results[0].state.value, 1);
674 assert_eq!(results[1].state.value, 2);
675 assert_eq!(results[2].state.value, 3);
676 }
677
678 #[test]
679 fn test_value_wrapper_public_access() {
680 let value = serde_json::json!({"test": "value"});
681 let wrapper = ValueWrapper(value.clone());
682 assert_eq!(wrapper.0, value);
683 }
684
685 #[test]
686 fn test_empty_error_string() {
687 let state = TestState {
688 value: 0,
689 name: String::new(),
690 };
691 let result = ContractResult::new(state);
692 assert_eq!(result.error.len(), 0);
693 }
694}