massa_deferred_calls/
call.rs

1use massa_models::{
2    address::{Address, AddressDeserializer, AddressSerializer},
3    amount::{Amount, AmountDeserializer, AmountSerializer},
4    serialization::{StringDeserializer, StringSerializer, VecU8Deserializer, VecU8Serializer},
5    slot::{Slot, SlotDeserializer, SlotSerializer},
6};
7use massa_proto_rs::massa::api::v1 as grpc_api;
8use massa_serialization::{
9    BoolDeserializer, BoolSerializer, Deserializer, SerializeError, Serializer,
10    U16VarIntDeserializer, U16VarIntSerializer, U64VarIntDeserializer, U64VarIntSerializer,
11};
12use nom::{
13    error::{context, ContextError, ParseError},
14    sequence::tuple,
15    IResult, Parser,
16};
17use serde::{Deserialize, Serialize};
18use std::ops::Bound;
19
20use crate::config::DeferredCallsConfig;
21
22/// Definition of a call in the future
23#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
24pub struct DeferredCall {
25    // Sender address
26    pub sender_address: Address,
27    // The slot in which the call will be executed
28    pub target_slot: Slot,
29    // The address of the contract to call
30    pub target_address: Address,
31    // The function to call
32    pub target_function: String,
33    // The parameters of the call
34    pub parameters: Vec<u8>,
35    // The amount of coins to send to the contract
36    pub coins: Amount,
37    // The maximum amount of gas usable for the call (excluding the vm allocation cost)
38    // to get the effective gas, use get_effective_gas(&self)
39    pub max_gas: u64,
40    // The fee to pay for the reservation of the space for the call
41    pub fee: Amount,
42    // Whether the call is cancelled
43    pub cancelled: bool,
44}
45
46impl DeferredCall {
47    #[allow(clippy::too_many_arguments)]
48    pub fn new(
49        sender_address: Address,
50        target_slot: Slot,
51        target_address: Address,
52        target_function: String,
53        parameters: Vec<u8>,
54        coins: Amount,
55        max_gas: u64,
56        fee: Amount,
57        cancelled: bool,
58    ) -> Self {
59        DeferredCall {
60            sender_address,
61            target_slot,
62            target_address,
63            target_function,
64            parameters,
65            coins,
66            max_gas,
67            fee,
68            cancelled,
69        }
70    }
71
72    /// Get the effective gas of a call
73    /// This is the maximum gas of the call + vm allocation cost
74    pub fn get_effective_gas(&self, alloc_gas_cost: u64) -> u64 {
75        self.max_gas.saturating_add(alloc_gas_cost)
76    }
77
78    /// Get the storage cost for a call
79    pub fn get_storage_cost(
80        cost_per_byte: Amount,
81        params_size: u64,
82        max_function_name_length: u16,
83    ) -> Amount {
84        // 35 (sender_address) + 16 (target_slot) + 35 (target_address) + target_function.len() + params_size + 8 (coins) + 8 (max_gas) + 8 (fee) + 1 (cancelled)
85        let total_size = params_size
86            .saturating_add(max_function_name_length as u64)
87            .saturating_add(111); // 35 + 16 + 35 + 8 + 8 + 8 + 1
88        cost_per_byte.saturating_mul_u64(total_size)
89    }
90}
91
92impl From<DeferredCall> for grpc_api::DeferredCallInfoEntry {
93    fn from(call: DeferredCall) -> Self {
94        grpc_api::DeferredCallInfoEntry {
95            sender_address: call.sender_address.to_string(),
96            target_slot: Some(call.target_slot.into()),
97            target_address: call.target_address.to_string(),
98            target_function: call.target_function,
99            parameters: call.parameters,
100            coins: Some(call.coins.into()),
101            max_gas: call.max_gas,
102            fee: Some(call.fee.into()),
103            cancelled: call.cancelled,
104        }
105    }
106}
107
108/// Serializer for `AsyncCall`
109#[derive(Clone)]
110pub struct DeferredCallSerializer {
111    pub(crate) slot_serializer: SlotSerializer,
112    pub(crate) address_serializer: AddressSerializer,
113    pub(crate) string_serializer: StringSerializer<U16VarIntSerializer, u16>,
114    pub(crate) vec_u8_serializer: VecU8Serializer,
115    pub(crate) amount_serializer: AmountSerializer,
116    pub(crate) u64_var_int_serializer: U64VarIntSerializer,
117    pub(crate) bool_serializer: BoolSerializer,
118}
119
120impl DeferredCallSerializer {
121    /// Serializes an `DeferredCall` into a `Vec<u8>`
122    pub fn new() -> Self {
123        Self {
124            slot_serializer: SlotSerializer::new(),
125            address_serializer: AddressSerializer::new(),
126            string_serializer: StringSerializer::new(U16VarIntSerializer::new()),
127            vec_u8_serializer: VecU8Serializer::new(),
128            amount_serializer: AmountSerializer::new(),
129            u64_var_int_serializer: U64VarIntSerializer::new(),
130            bool_serializer: BoolSerializer::new(),
131        }
132    }
133}
134
135impl Serializer<DeferredCall> for DeferredCallSerializer {
136    fn serialize(&self, value: &DeferredCall, buffer: &mut Vec<u8>) -> Result<(), SerializeError> {
137        self.address_serializer
138            .serialize(&value.sender_address, buffer)?;
139        self.slot_serializer.serialize(&value.target_slot, buffer)?;
140        self.address_serializer
141            .serialize(&value.target_address, buffer)?;
142        self.string_serializer
143            .serialize(&value.target_function, buffer)?;
144        self.vec_u8_serializer
145            .serialize(&value.parameters, buffer)?;
146        self.amount_serializer.serialize(&value.coins, buffer)?;
147        self.u64_var_int_serializer
148            .serialize(&value.max_gas, buffer)?;
149        self.amount_serializer.serialize(&value.fee, buffer)?;
150        self.bool_serializer.serialize(&value.cancelled, buffer)?;
151        Ok(())
152    }
153}
154
155/// Deserializer for `AsyncCall`
156#[derive(Clone)]
157pub struct DeferredCallDeserializer {
158    slot_deserializer: SlotDeserializer,
159    pub(crate) address_deserializer: AddressDeserializer,
160    pub(crate) string_deserializer: StringDeserializer<U16VarIntDeserializer, u16>,
161    pub(crate) vec_u8_deserializer: VecU8Deserializer,
162    pub(crate) amount_deserializer: AmountDeserializer,
163    pub(crate) u64_var_int_deserializer: U64VarIntDeserializer,
164    pub(crate) bool_deserializer: BoolDeserializer,
165}
166
167impl DeferredCallDeserializer {
168    /// Deserializes a `Vec<u8>` into an `AsyncCall`
169    pub fn new(config: DeferredCallsConfig) -> Self {
170        Self {
171            slot_deserializer: SlotDeserializer::new(
172                (Bound::Included(0), Bound::Included(u64::MAX)),
173                (Bound::Included(0), Bound::Excluded(config.thread_count)),
174            ),
175            address_deserializer: AddressDeserializer::new(),
176            string_deserializer: StringDeserializer::new(U16VarIntDeserializer::new(
177                Bound::Included(0),
178                Bound::Included(config.max_function_name_length),
179            )),
180            vec_u8_deserializer: VecU8Deserializer::new(
181                std::ops::Bound::Included(0),
182                std::ops::Bound::Included(config.max_parameter_size as u64),
183            ),
184            amount_deserializer: AmountDeserializer::new(
185                Bound::Included(Amount::MIN),
186                Bound::Included(Amount::MAX),
187            ),
188            u64_var_int_deserializer: U64VarIntDeserializer::new(
189                Bound::Included(0),
190                Bound::Included(u64::MAX),
191            ),
192            bool_deserializer: BoolDeserializer::new(),
193        }
194    }
195}
196
197impl Deserializer<DeferredCall> for DeferredCallDeserializer {
198    fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
199        &self,
200        buffer: &'a [u8],
201    ) -> IResult<&'a [u8], DeferredCall, E> {
202        context(
203            "Failed AsyncCall deserialization",
204            tuple((
205                context("Failed sender_address deserialization", |input| {
206                    self.address_deserializer.deserialize(input)
207                }),
208                context("Failed target_slot deserialization", |input| {
209                    self.slot_deserializer.deserialize(input)
210                }),
211                context("Failed target_address deserialization", |input| {
212                    self.address_deserializer.deserialize(input)
213                }),
214                context("Failed target_function deserialization", |input| {
215                    self.string_deserializer.deserialize(input)
216                }),
217                context("Failed parameters deserialization", |input| {
218                    self.vec_u8_deserializer.deserialize(input)
219                }),
220                context("Failed coins deserialization", |input| {
221                    self.amount_deserializer.deserialize(input)
222                }),
223                context("Failed max_gas deserialization", |input| {
224                    self.u64_var_int_deserializer.deserialize(input)
225                }),
226                context("Failed fee deserialization", |input| {
227                    self.amount_deserializer.deserialize(input)
228                }),
229                context("Failed cancelled deserialization", |input| {
230                    self.bool_deserializer.deserialize(input)
231                }),
232            )),
233        )
234        .map(
235            |(
236                sender_address,
237                target_slot,
238                target_address,
239                target_function,
240                parameters,
241                coins,
242                max_gas,
243                fee,
244                cancelled,
245            )| {
246                DeferredCall::new(
247                    sender_address,
248                    target_slot,
249                    target_address,
250                    target_function,
251                    parameters,
252                    coins,
253                    max_gas,
254                    fee,
255                    cancelled,
256                )
257            },
258        )
259        .parse(buffer)
260    }
261}
262
263#[cfg(test)]
264mod tests {
265    use std::str::FromStr;
266
267    use massa_serialization::DeserializeError;
268
269    use super::*;
270
271    #[test]
272    fn test_serialization_deserialization() {
273        let call = DeferredCall::new(
274            Address::from_str("AU12dG5xP1RDEB5ocdHkymNVvvSJmUL9BgHwCksDowqmGWxfpm93x").unwrap(),
275            Slot::new(42, 0),
276            Address::from_str("AU12dG5xP1RDEB5ocdHkymNVvvSJmUL9BgHwCksDowqmGWxfpm93x").unwrap(),
277            "function".to_string(),
278            vec![0, 1, 2, 3],
279            Amount::from_raw(100),
280            500000,
281            Amount::from_raw(25),
282            false,
283        );
284        let serializer = DeferredCallSerializer::new();
285
286        let deserializer = DeferredCallDeserializer::new(DeferredCallsConfig::default());
287        let mut buffer = Vec::new();
288        serializer.serialize(&call, &mut buffer).unwrap();
289        let (rest, deserialized_call) = deserializer
290            .deserialize::<DeserializeError>(&buffer)
291            .unwrap();
292        assert_eq!(call, deserialized_call);
293        assert!(rest.is_empty());
294    }
295}