dusk_core/transfer/
data.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4//
5// Copyright (c) DUSK NETWORK. All rights reserved.
6
7//! Extra data that may be sent with the `data` field of either transaction
8//! type.
9
10use alloc::string::String;
11use alloc::vec::Vec;
12use alloc::{format, vec};
13
14use bytecheck::CheckBytes;
15use dusk_bytes::{DeserializableSlice, Error as BytesError, Serializable};
16use piecrust_uplink::StandardBufSerializer;
17use rkyv::ser::serializers::{
18    BufferScratch, BufferSerializer, CompositeSerializer,
19};
20use rkyv::ser::Serializer;
21use rkyv::validation::validators::DefaultValidator;
22use rkyv::{Archive, Deserialize, Infallible, Serialize};
23
24use crate::abi::ContractId;
25use crate::Error;
26
27/// The maximum size of a memo.
28pub const MAX_MEMO_SIZE: usize = 512;
29
30/// Data for either contract call or contract deployment.
31#[derive(Debug, Clone, PartialEq, Eq, Archive, Serialize, Deserialize)]
32#[archive_attr(derive(CheckBytes))]
33#[allow(clippy::large_enum_variant)]
34pub enum TransactionData {
35    /// Data for a contract call.
36    Call(ContractCall),
37    /// Data for a contract deployment.
38    Deploy(ContractDeploy),
39    /// Additional data added to a transaction, that is not a deployment or a
40    /// call.
41    Memo(Vec<u8>),
42}
43
44impl From<ContractCall> for TransactionData {
45    fn from(c: ContractCall) -> Self {
46        TransactionData::Call(c)
47    }
48}
49
50impl From<ContractDeploy> for TransactionData {
51    fn from(d: ContractDeploy) -> Self {
52        TransactionData::Deploy(d)
53    }
54}
55
56impl From<Vec<u8>> for TransactionData {
57    fn from(d: Vec<u8>) -> Self {
58        TransactionData::Memo(d)
59    }
60}
61
62impl From<String> for TransactionData {
63    fn from(d: String) -> Self {
64        TransactionData::Memo(d.as_bytes().to_vec())
65    }
66}
67
68/// Data for performing a contract deployment
69#[derive(Debug, Clone, PartialEq, Eq, Archive, Serialize, Deserialize)]
70#[archive_attr(derive(CheckBytes))]
71pub struct ContractDeploy {
72    /// Bytecode of the contract to be deployed.
73    pub bytecode: ContractBytecode,
74    /// Owner of the contract to be deployed.
75    pub owner: Vec<u8>,
76    /// Init method arguments of the deployed contract.
77    pub init_args: Option<Vec<u8>>,
78    /// Nonce for contract id uniqueness and vanity
79    pub nonce: u64,
80}
81
82/// All the data the transfer-contract needs to perform a contract-call.
83#[derive(Debug, Clone, PartialEq, Eq, Archive, Serialize, Deserialize)]
84#[archive_attr(derive(CheckBytes))]
85pub struct ContractCall {
86    /// The unique ID of the contract to be called.
87    pub contract: ContractId,
88    /// The function of the contract that should be called.
89    pub fn_name: String,
90    /// The function arguments for the contract call, in bytes.
91    pub fn_args: Vec<u8>,
92}
93
94impl ContractDeploy {
95    /// Serialize a `ContractDeploy` into a variable length byte buffer.
96    #[must_use]
97    pub fn to_var_bytes(&self) -> Vec<u8> {
98        let mut bytes = Vec::new();
99
100        bytes.extend(&self.bytecode.to_var_bytes());
101
102        bytes.extend((self.owner.len() as u64).to_bytes());
103        bytes.extend(&self.owner);
104
105        match &self.init_args {
106            Some(init_args) => {
107                bytes.push(1);
108                bytes.extend((init_args.len() as u64).to_bytes());
109                bytes.extend(init_args);
110            }
111            None => bytes.push(0),
112        }
113
114        bytes.extend(self.nonce.to_bytes());
115
116        bytes
117    }
118
119    /// Deserialize a `ContractDeploy` from a byte buffer.
120    ///
121    /// # Errors
122    /// Errors when the bytes are not canonical.
123    pub fn from_slice(buf: &[u8]) -> Result<Self, BytesError> {
124        let mut buf = buf;
125
126        let bytecode = ContractBytecode::from_buf(&mut buf)?;
127
128        let owner = crate::read_vec(&mut buf)?;
129
130        let init_args = match u8::from_reader(&mut buf)? {
131            0 => None,
132            1 => Some(crate::read_vec(&mut buf)?),
133            _ => return Err(BytesError::InvalidData),
134        };
135
136        let nonce = u64::from_reader(&mut buf)?;
137
138        Ok(Self {
139            bytecode,
140            owner,
141            init_args,
142            nonce,
143        })
144    }
145}
146
147impl ContractCall {
148    /// Creates a new contract call with empty `fn_args`.
149    ///
150    /// Initializes a contract call by setting the function arguments to an
151    /// empty vector.
152    ///
153    /// # Parameters
154    /// - `contract`: A value convertible into a `ContractId`, representing the
155    ///   target contract.
156    /// - `fn_name`: A value convertible into a `String`, specifying the name of
157    ///   the function to be called.
158    pub fn new(
159        contract: impl Into<ContractId>,
160        fn_name: impl Into<String>,
161    ) -> Self {
162        Self {
163            contract: contract.into(),
164            fn_name: fn_name.into(),
165            fn_args: vec![],
166        }
167    }
168
169    /// Consumes `self` and returns a new contract call with raw function
170    /// arguments.
171    ///
172    /// Updates the contract call with raw serialized arguments provided as a
173    /// `Vec<u8>`.
174    ///
175    /// # Parameters
176    /// - `fn_args`: A `Vec<u8>` representing pre-serialized function arguments.
177    #[must_use]
178    pub fn with_raw_args(mut self, fn_args: Vec<u8>) -> Self {
179        self.fn_args = fn_args;
180        self
181    }
182
183    /// Consumes `self` and returns a new contract call with serialized function
184    /// arguments.
185    ///
186    /// Serializes the provided function arguments using `rkyv` serialization
187    /// and returns an updated contract call.
188    ///
189    /// # Parameters
190    /// - `fn_args`: A reference to an object implementing `Serialize` for the
191    ///   given `AllocSerializer`.
192    ///
193    /// # Returns
194    /// - `Ok(Self)`: If the serialization is successful.
195    /// - `Err(Error::Rkyv)`: If the `rkyv` serialization fails.
196    ///
197    /// # Errors
198    /// Returns an error if `rkyv` serialization fails.
199    pub fn with_args<A>(self, fn_arg: &A) -> Result<Self, Error>
200    where
201        A: for<'b> Serialize<StandardBufSerializer<'b>>,
202        A::Archived: for<'b> CheckBytes<DefaultValidator<'b>>,
203    {
204        // scratch-space and page-size values taken from piecrust-uplink
205        const SCRATCH_SPACE: usize = 1024;
206        const PAGE_SIZE: usize = 0x1000;
207
208        let mut sbuf = [0u8; SCRATCH_SPACE];
209        let scratch = BufferScratch::new(&mut sbuf);
210        let mut buffer = [0u8; PAGE_SIZE];
211        let ser = BufferSerializer::new(&mut buffer[..]);
212        let mut ser = CompositeSerializer::new(ser, scratch, Infallible);
213
214        ser.serialize_value(fn_arg)
215            .map_err(|e| Error::Rkyv(format!("{e:?}")))?;
216        let pos = ser.pos();
217
218        let fn_args = buffer[..pos].to_vec();
219
220        Ok(self.with_raw_args(fn_args))
221    }
222
223    /// Serialize a `ContractCall` into a variable length byte buffer.
224    #[must_use]
225    pub fn to_var_bytes(&self) -> Vec<u8> {
226        let mut bytes = Vec::new();
227
228        bytes.extend(self.contract.as_bytes());
229
230        let fn_name_bytes = self.fn_name.as_bytes();
231        bytes.extend((fn_name_bytes.len() as u64).to_bytes());
232        bytes.extend(fn_name_bytes);
233
234        bytes.extend((self.fn_args.len() as u64).to_bytes());
235        bytes.extend(&self.fn_args);
236
237        bytes
238    }
239
240    /// Deserialize a `ContractCall` from a byte buffer.
241    ///
242    /// # Errors
243    /// Errors when the bytes are not canonical.
244    pub fn from_slice(buf: &[u8]) -> Result<Self, BytesError> {
245        let mut buf = buf;
246
247        let contract = crate::read_arr::<32>(&mut buf)?;
248
249        let fn_name = crate::read_str(&mut buf)?;
250
251        let fn_args = crate::read_vec(&mut buf)?;
252
253        Ok(Self {
254            contract: contract.into(),
255            fn_name,
256            fn_args,
257        })
258    }
259}
260
261#[derive(Debug, Clone, PartialEq, Eq, Archive, Serialize, Deserialize)]
262#[archive_attr(derive(CheckBytes))]
263/// Holds bytes of bytecode and its hash.
264pub struct ContractBytecode {
265    /// Blake3 hash of the bytecode bytes.
266    pub hash: [u8; 32],
267    /// Bytecode bytes.
268    pub bytes: Vec<u8>,
269}
270
271impl ContractBytecode {
272    /// Provides contribution bytes for an external hash.
273    #[must_use]
274    pub fn to_hash_input_bytes(&self) -> Vec<u8> {
275        self.hash.to_vec()
276    }
277
278    /// Serializes this object into a variable length buffer
279    #[must_use]
280    pub fn to_var_bytes(&self) -> Vec<u8> {
281        let mut bytes = Vec::new();
282        bytes.extend(self.hash);
283        bytes.extend((self.bytes.len() as u64).to_bytes());
284        bytes.extend(&self.bytes);
285        bytes
286    }
287
288    /// Deserialize from a bytes buffer.
289    /// Resets buffer to a position after the bytes read.
290    ///
291    /// # Errors
292    /// Errors when the bytes are not available.
293    pub fn from_buf(buf: &mut &[u8]) -> Result<Self, BytesError> {
294        let hash = crate::read_arr::<32>(buf)?;
295        let bytes = crate::read_vec(buf)?;
296        Ok(Self { hash, bytes })
297    }
298}