Skip to main content

freenet_stdlib/
memory.rs

1//! Internally used functionality to interact between WASM and the host environment.
2//! Most of the usage of types is unsafe and requires knowledge on how
3//! the WASM runtime is set and used. Use with caution.
4//!
5//! End users should be using higher levels of abstraction to write contracts
6//! and shouldn't need to manipulate functions and types in this module directly.
7//! Use with caution.
8
9pub mod buf;
10
11#[non_exhaustive]
12#[derive(Debug, Clone, Copy)]
13pub struct WasmLinearMem {
14    pub start_ptr: *const u8,
15    pub size: u64,
16}
17
18impl WasmLinearMem {
19    /// # Safety
20    /// Ensure that the passed pointer is a valid pointer to the start of
21    /// the WASM linear memory
22    pub unsafe fn new(start_ptr: *const u8, size: u64) -> Self {
23        Self { start_ptr, size }
24    }
25}
26
27#[cfg(feature = "contract")]
28pub mod wasm_interface {
29    use crate::prelude::*;
30
31    fn set_logger() -> Result<(), ContractInterfaceResult> {
32        #[cfg(feature = "trace")]
33        {
34            use crate::prelude::*;
35            use tracing_subscriber as tra;
36            if let Err(err) = tra::fmt()
37                .with_env_filter("warn,freenet_stdlib=trace")
38                .try_init()
39            {
40                return Err(ContractInterfaceResult::from(Err::<ValidateResult, _>(
41                    ContractError::Other(format!("{}", err)),
42                )));
43            }
44        }
45        Ok(())
46    }
47
48    use std::io::Read;
49
50    /// Read all bytes from a streaming buffer into a Vec.
51    fn read_streaming_bytes(ptr: i64) -> Result<Vec<u8>, ContractInterfaceResult> {
52        let mut reader = unsafe { super::buf::StreamingBuffer::from_ptr(ptr) };
53        let mut bytes = Vec::with_capacity(reader.total_remaining());
54        reader.read_to_end(&mut bytes).map_err(|e| {
55            ContractInterfaceResult::from(Err::<ValidateResult, _>(ContractError::Other(format!(
56                "streaming read failed: {e}"
57            ))))
58        })?;
59        Ok(bytes)
60    }
61
62    pub fn inner_validate_state<T: ContractInterface>(
63        parameters: i64,
64        state: i64,
65        related: i64,
66    ) -> i64 {
67        if let Err(e) = set_logger().map_err(|e| e.into_raw()) {
68            return e;
69        }
70        let parameters = match read_streaming_bytes(parameters) {
71            Ok(bytes) => Parameters::from(bytes),
72            Err(e) => return e.into_raw(),
73        };
74        let state = match read_streaming_bytes(state) {
75            Ok(bytes) => State::from(bytes),
76            Err(e) => return e.into_raw(),
77        };
78        let related_bytes = match read_streaming_bytes(related) {
79            Ok(bytes) => bytes,
80            Err(e) => return e.into_raw(),
81        };
82        let related: RelatedContracts<'static> =
83            match bincode::deserialize::<RelatedContracts>(&related_bytes) {
84                Ok(v) => v.into_owned(),
85                Err(err) => {
86                    return ContractInterfaceResult::from(Err::<::core::primitive::bool, _>(
87                        ContractError::Deser(format!("{}", err)),
88                    ))
89                    .into_raw()
90                }
91            };
92        let result = <T as ContractInterface>::validate_state(parameters, state, related);
93        ContractInterfaceResult::from(result).into_raw()
94    }
95
96    pub fn inner_update_state<T: ContractInterface>(
97        parameters: i64,
98        state: i64,
99        updates: i64,
100    ) -> i64 {
101        if let Err(e) = set_logger().map_err(|e| e.into_raw()) {
102            return e;
103        }
104        let parameters = match read_streaming_bytes(parameters) {
105            Ok(bytes) => Parameters::from(bytes),
106            Err(e) => return e.into_raw(),
107        };
108        let state = match read_streaming_bytes(state) {
109            Ok(bytes) => State::from(bytes),
110            Err(e) => return e.into_raw(),
111        };
112        let updates_bytes = match read_streaming_bytes(updates) {
113            Ok(bytes) => bytes,
114            Err(e) => return e.into_raw(),
115        };
116        let updates: Vec<UpdateData<'static>> =
117            match bincode::deserialize::<Vec<UpdateData>>(&updates_bytes) {
118                Ok(v) => v.into_iter().map(|u| u.into_owned()).collect(),
119                Err(err) => {
120                    return ContractInterfaceResult::from(Err::<ValidateResult, _>(
121                        ContractError::Deser(format!("{}", err)),
122                    ))
123                    .into_raw()
124                }
125            };
126        let result = <T as ContractInterface>::update_state(parameters, state, updates);
127        ContractInterfaceResult::from(result).into_raw()
128    }
129
130    pub fn inner_summarize_state<T: ContractInterface>(parameters: i64, state: i64) -> i64 {
131        if let Err(e) = set_logger().map_err(|e| e.into_raw()) {
132            return e;
133        }
134        let parameters = match read_streaming_bytes(parameters) {
135            Ok(bytes) => Parameters::from(bytes),
136            Err(e) => return e.into_raw(),
137        };
138        let state = match read_streaming_bytes(state) {
139            Ok(bytes) => State::from(bytes),
140            Err(e) => return e.into_raw(),
141        };
142        let summary = <T as ContractInterface>::summarize_state(parameters, state);
143        ContractInterfaceResult::from(summary).into_raw()
144    }
145
146    pub fn inner_get_state_delta<T: ContractInterface>(
147        parameters: i64,
148        state: i64,
149        summary: i64,
150    ) -> i64 {
151        if let Err(e) = set_logger().map_err(|e| e.into_raw()) {
152            return e;
153        }
154        let parameters = match read_streaming_bytes(parameters) {
155            Ok(bytes) => Parameters::from(bytes),
156            Err(e) => return e.into_raw(),
157        };
158        let state = match read_streaming_bytes(state) {
159            Ok(bytes) => State::from(bytes),
160            Err(e) => return e.into_raw(),
161        };
162        let summary = match read_streaming_bytes(summary) {
163            Ok(bytes) => StateSummary::from(bytes),
164            Err(e) => return e.into_raw(),
165        };
166        let new_delta = <T as ContractInterface>::get_state_delta(parameters, state, summary);
167        ContractInterfaceResult::from(new_delta).into_raw()
168    }
169}