smart_contract/
payload.rs

1use alloc::string::String;
2use alloc::{vec, vec::Vec};
3
4pub trait Writeable {
5    fn write_to(&self, buffer: &mut Vec<u8>);
6}
7
8macro_rules! writeable {
9    ( $($x:ident), *) => {
10        $(
11            impl Writeable for $x {
12                fn write_to(&self, buffer: &mut Vec<u8>) {
13                    unsafe {
14                        let x = ::alloc::slice::from_raw_parts(self as *const _ as *const u8, ::core::mem::size_of::<Self>());
15                        buffer.extend_from_slice(x);
16                    }
17                }
18            }
19        )*
20    }
21}
22
23macro_rules! writeable_array {
24    ( $n:expr) => {
25        impl<U: Writeable> Writeable for [U; $n] {
26            fn write_to(&self, buffer: &mut Vec<u8>) {
27                for i in self {
28                    i.write_to(buffer);
29                }
30            }
31        }
32    };
33}
34
35writeable![usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128, f32, f64];
36writeable_array![32];
37
38impl Writeable for bool {
39    fn write_to(&self, buffer: &mut Vec<u8>) {
40        if *self {
41            1u8.write_to(buffer);
42        } else {
43            0u8.write_to(buffer);
44        }
45    }
46}
47
48impl Writeable for String {
49    fn write_to(&self, buffer: &mut Vec<u8>) {
50        for x in self.chars() {
51            (x as u8).write_to(buffer);
52        }
53
54        0u8.write_to(buffer);
55    }
56}
57
58impl Writeable for str {
59    fn write_to(&self, buffer: &mut Vec<u8>) {
60        for x in self.chars() {
61            (x as u8).write_to(buffer);
62        }
63
64        0u8.write_to(buffer);
65    }
66}
67
68impl<T: Writeable> Writeable for Vec<T> {
69    fn write_to(&self, buffer: &mut Vec<u8>) {
70        self.len().write_to(buffer);
71
72        for x in self {
73            x.write_to(buffer);
74        }
75    }
76}
77
78impl<T: Writeable> Writeable for [T] {
79    fn write_to(&self, buffer: &mut Vec<u8>) {
80        self.len().write_to(buffer);
81
82        for x in self {
83            x.write_to(buffer);
84        }
85    }
86}
87
88pub trait Readable {
89    fn read_from(buffer: &[u8], pos: &mut u64) -> Self;
90}
91
92macro_rules! readable {
93    ( $($x:ident), *) => {
94        $(
95            impl Readable for $x {
96                fn read_from(buffer: &[u8], pos: &mut u64) -> Self {
97                    unsafe {
98                        let ptr = buffer.as_ptr().offset(*pos as isize);
99
100                        let size = ::core::mem::size_of::<$x>();
101
102                        let x = ::alloc::slice::from_raw_parts(ptr, size);
103                        *pos += size as u64;
104
105                        let mut ret: $x = ::core::mem::MaybeUninit::uninit().assume_init();
106                        ::core::ptr::copy(x.as_ptr(), &mut ret as *mut _ as *mut u8, ::core::mem::size_of::<$x>());
107
108                        ret
109                    }
110                }
111            }
112        )*
113    }
114}
115
116macro_rules! readable_array {
117    ( $n:expr) => {
118        impl<U: Readable + Copy + Default> Readable for [U; $n] {
119            fn read_from(buffer: &[u8], pos: &mut u64) -> [U; $n] {
120                let mut buf: [U; $n] = [U::default(); $n];
121
122                for i in 0..$n {
123                    buf[i] = U::read_from(buffer, pos);
124                }
125
126                buf
127            }
128        }
129    };
130}
131
132readable![usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128, f32, f64];
133readable_array![32];
134
135impl Readable for bool {
136    fn read_from(buffer: &[u8], pos: &mut u64) -> bool {
137        u8::read_from(buffer, pos) == 1
138    }
139}
140
141impl Readable for String {
142    fn read_from(buffer: &[u8], pos: &mut u64) -> String {
143        let mut buf = vec![];
144
145        loop {
146            let chr = u8::read_from(buffer, pos);
147
148            if chr == 0 {
149                break;
150            }
151
152            buf.push(chr);
153        }
154
155        String::from_utf8(buf).unwrap()
156    }
157}
158
159impl<U: Readable> Readable for Vec<U> {
160    fn read_from(buffer: &[u8], pos: &mut u64) -> Vec<U> {
161        let mut buf: Vec<U> = vec![];
162        let len = usize::read_from(buffer, pos);
163
164        for _ in 0..len {
165            buf.push(U::read_from(buffer, pos));
166        }
167
168        buf
169    }
170}
171
172// Incoming parameters for a smart contract function call.
173#[derive(Default)]
174pub struct Parameters {
175    pub round_idx: u64,
176    pub round_id: [u8; 32],
177    pub transaction_id: [u8; 32],
178    pub sender: [u8; 32],
179    pub amount: u64, // can be extended or removed
180
181    parameters: Vec<u8>,
182    pos: u64,
183}
184
185impl Parameters {
186    pub fn load() -> Parameters {
187        let payload_len = unsafe { crate::sys::_payload_len() };
188        let mut payload_bytes = Vec::with_capacity(payload_len);
189
190        unsafe {
191            payload_bytes.set_len(payload_len);
192            crate::sys::_payload(payload_bytes.as_mut_ptr())
193        }
194
195        let mut parameters = Parameters::default();
196        parameters.parameters = payload_bytes;
197
198        parameters.round_idx = parameters.read();
199        parameters.round_id = parameters.read();
200        parameters.transaction_id = parameters.read();
201        parameters.sender = parameters.read();
202        parameters.amount = parameters.read();
203
204        parameters
205    }
206
207    pub fn read<T: Readable>(&mut self) -> T {
208        T::read_from(&self.parameters, &mut self.pos)
209    }
210}
211
212#[derive(Default)]
213pub struct ParametersBuilder {
214    params: Parameters,
215}
216
217impl ParametersBuilder {
218    pub fn new() -> ParametersBuilder {
219        Default::default()
220    }
221
222    pub fn with_round_idx(self, round_idx: u64) -> Self {
223        Self {
224            params: Parameters {
225                round_idx,
226                ..self.params
227            },
228        }
229    }
230
231    pub fn with_round_id(self, round_id: [u8; 32]) -> Self {
232        Self {
233            params: Parameters {
234                round_id,
235                ..self.params
236            },
237        }
238    }
239
240    pub fn with_transaction_id(self, transaction_id: [u8; 32]) -> Self {
241        Self {
242            params: Parameters {
243                transaction_id,
244                ..self.params
245            },
246        }
247    }
248
249    pub fn with_sender(self, sender: [u8; 32]) -> Self {
250        Self {
251            params: Parameters {
252                sender,
253                ..self.params
254            },
255        }
256    }
257
258    pub fn with_amount(self, amount: u64) -> Self {
259        Self {
260            params: Parameters {
261                amount,
262                ..self.params
263            },
264        }
265    }
266
267    pub fn write<T: Writeable + ?Sized>(&mut self, x: &T) {
268        x.write_to(&mut self.params.parameters);
269    }
270
271    pub fn build(self) -> Parameters {
272        self.params
273    }
274}
275
276#[cfg(test)]
277mod tests {
278    use super::*;
279
280    #[test]
281    fn test_parameters_builder() {
282        const ROUND_IDX: u64 = 100;
283        const ROUND_ID: [u8; 32] = [42; 32];
284        const TRANSACTION_ID: [u8; 32] = [0; 32];
285        const SENDER: [u8; 32] = [1; 32];
286        const AMOUNT: u64 = 20;
287
288        let mut builder = ParametersBuilder::new()
289            .with_round_idx(ROUND_IDX)
290            .with_round_id(ROUND_ID)
291            .with_transaction_id(TRANSACTION_ID)
292            .with_sender(SENDER)
293            .with_amount(AMOUNT);
294
295        builder.write(&100u64);
296        builder.write("Hello");
297
298        let mut params = builder.build();
299
300        assert_eq!(params.round_idx, ROUND_IDX);
301        assert_eq!(params.round_id, ROUND_ID);
302        assert_eq!(params.transaction_id, TRANSACTION_ID);
303        assert_eq!(params.sender, SENDER);
304        assert_eq!(params.amount, AMOUNT);
305
306        assert_eq!(params.read::<u64>(), 100);
307        assert_eq!(params.read::<String>(), "Hello");
308    }
309}