massa_models/
operation.rs

1// Copyright (c) 2022 MASSA LABS <info@massa.net>
2
3use crate::address::AddressSerializer;
4use crate::datastore::{Datastore, DatastoreDeserializer, DatastoreSerializer};
5use crate::prehash::{PreHashSet, PreHashed};
6use crate::secure_share::{
7    Id, SecureShare, SecureShareContent, SecureShareDeserializer, SecureShareSerializer,
8};
9use crate::{
10    address::{Address, AddressDeserializer},
11    amount::{Amount, AmountDeserializer, AmountSerializer},
12    error::ModelsError,
13    serialization::{StringDeserializer, StringSerializer, VecU8Deserializer, VecU8Serializer},
14};
15use massa_hash::{Hash, HashDeserializer};
16use massa_serialization::{
17    DeserializeError, Deserializer, SerializeError, Serializer, U16VarIntDeserializer,
18    U16VarIntSerializer, U32VarIntDeserializer, U32VarIntSerializer, U64VarIntDeserializer,
19    U64VarIntSerializer,
20};
21use massa_signature::PublicKey;
22use nom::error::{context, ErrorKind};
23use nom::multi::length_count;
24use nom::sequence::tuple;
25use nom::AsBytes;
26use nom::Parser;
27use nom::{
28    error::{ContextError, ParseError},
29    IResult,
30};
31use num_enum::{IntoPrimitive, TryFromPrimitive};
32use serde::{Deserialize, Serialize};
33use serde_with::{serde_as, DeserializeFromStr, SerializeDisplay};
34use std::convert::TryInto;
35use std::fmt::Formatter;
36use std::{ops::Bound::Included, ops::RangeInclusive, str::FromStr};
37use transition::Versioned;
38
39/// Size in bytes of the serialized operation ID prefix
40pub const OPERATION_ID_PREFIX_SIZE_BYTES: usize = 17;
41
42/// operation id
43#[allow(missing_docs)]
44#[transition::versioned(versions("0"))]
45#[derive(
46    Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, SerializeDisplay, DeserializeFromStr,
47)]
48pub struct OperationId(Hash);
49
50const OPERATIONID_PREFIX: char = 'O';
51
52/// Left part of the operation id hash stored in a vector of size [`OPERATION_ID_PREFIX_SIZE_BYTES`]
53#[allow(missing_docs)]
54#[transition::versioned(versions("0"))]
55#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
56#[allow(unused_macros)]
57pub struct OperationPrefixId([u8; OPERATION_ID_PREFIX_SIZE_BYTES]);
58
59impl std::fmt::Display for OperationPrefixId {
60    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
61        match self {
62            OperationPrefixId::OperationPrefixIdV0(prefix) => write!(f, "{}", prefix),
63        }
64    }
65}
66
67#[transition::impl_version(versions("0"))]
68impl std::fmt::Display for OperationPrefixId {
69    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
70        let u64_serializer = U64VarIntSerializer::new();
71        // might want to allocate the vector with capacity in order to avoid re-allocation
72        let mut bytes: Vec<u8> = Vec::new();
73        u64_serializer
74            .serialize(&Self::VERSION, &mut bytes)
75            .map_err(|_| std::fmt::Error)?;
76        bytes.extend(self.0.as_bytes());
77        write!(f, "{}", bs58::encode(bytes).into_string())
78    }
79}
80
81impl std::fmt::Debug for OperationPrefixId {
82    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
83        match self {
84            OperationPrefixId::OperationPrefixIdV0(prefix) => write!(f, "{:?}", prefix),
85        }
86    }
87}
88
89#[transition::impl_version(versions("0"))]
90impl std::fmt::Debug for OperationPrefixId {
91    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
92        write!(f, "{}", self)
93    }
94}
95
96impl std::fmt::Display for OperationId {
97    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
98        match self {
99            OperationId::OperationIdV0(id) => write!(f, "{}", id),
100        }
101    }
102}
103
104#[transition::impl_version(versions("0"))]
105impl std::fmt::Display for OperationId {
106    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
107        let u64_serializer = U64VarIntSerializer::new();
108        // might want to allocate the vector with capacity in order to avoid re-allocation
109        let mut bytes: Vec<u8> = Vec::new();
110        u64_serializer
111            .serialize(&Self::VERSION, &mut bytes)
112            .map_err(|_| std::fmt::Error)?;
113        bytes.extend(self.0.to_bytes());
114        write!(
115            f,
116            "{}{}",
117            OPERATIONID_PREFIX,
118            bs58::encode(bytes).with_check().into_string()
119        )
120    }
121}
122
123impl std::fmt::Debug for OperationId {
124    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
125        match self {
126            OperationId::OperationIdV0(id) => write!(f, "{:?}", id),
127        }
128    }
129}
130
131#[transition::impl_version(versions("0"))]
132impl std::fmt::Debug for OperationId {
133    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
134        write!(f, "{}", self)
135    }
136}
137
138impl FromStr for OperationId {
139    type Err = ModelsError;
140    /// ## Example
141    /// ```rust
142    /// # use massa_hash::Hash;
143    /// # use std::str::FromStr;
144    /// # use massa_serialization::{Deserializer, DeserializeError};
145    /// # use massa_models::operation::{OperationId, OperationIdDeserializer};
146    /// # let op_id_deserializer = OperationIdDeserializer::new();
147    /// # let (_, op_id): (&[u8], OperationId) = op_id_deserializer.deserialize::<DeserializeError>(&[0; 33]).unwrap();
148    /// let ser = op_id.to_string();
149    /// let res_op_id = OperationId::from_str(&ser).unwrap();
150    /// assert_eq!(op_id, res_op_id);
151    /// ```
152    fn from_str(s: &str) -> Result<Self, Self::Err> {
153        let mut chars = s.chars();
154        match chars.next() {
155            Some(prefix) if prefix == OPERATIONID_PREFIX => {
156                let data = chars.collect::<String>();
157                let decoded_bs58_check = bs58::decode(data)
158                    .with_check(None)
159                    .into_vec()
160                    .map_err(|_| ModelsError::OperationIdParseError)?;
161                let operation_id_deserializer = OperationIdDeserializer::new();
162                let (rest, op_id) = operation_id_deserializer
163                    .deserialize::<DeserializeError>(&decoded_bs58_check[..])
164                    .map_err(|_| ModelsError::OperationIdParseError)?;
165                if rest.is_empty() {
166                    Ok(op_id)
167                } else {
168                    Err(ModelsError::OperationIdParseError)
169                }
170            }
171            _ => Err(ModelsError::OperationIdParseError),
172        }
173    }
174}
175
176#[transition::impl_version(versions("0"))]
177impl FromStr for OperationId {
178    type Err = ModelsError;
179    fn from_str(s: &str) -> Result<Self, Self::Err> {
180        let mut chars = s.chars();
181        match chars.next() {
182            Some(prefix) if prefix == OPERATIONID_PREFIX => {
183                let data = chars.collect::<String>();
184                let decoded_bs58_check = bs58::decode(data)
185                    .with_check(None)
186                    .into_vec()
187                    .map_err(|_| ModelsError::OperationIdParseError)?;
188                let operation_id_deserializer = OperationIdDeserializer::new();
189                let (rest, op_id) = operation_id_deserializer
190                    .deserialize::<DeserializeError>(&decoded_bs58_check[..])
191                    .map_err(|_| ModelsError::OperationIdParseError)?;
192                if rest.is_empty() {
193                    Ok(op_id)
194                } else {
195                    Err(ModelsError::OperationIdParseError)
196                }
197            }
198            _ => Err(ModelsError::OperationIdParseError),
199        }
200    }
201}
202
203impl PreHashed for OperationId {}
204
205impl Id for OperationId {
206    fn new(hash: Hash) -> Self {
207        OperationId::OperationIdV0(OperationIdV0(hash))
208    }
209
210    fn get_hash(&self) -> &Hash {
211        match self {
212            OperationId::OperationIdV0(op_id) => op_id.get_hash(),
213        }
214    }
215}
216
217impl PreHashed for OperationPrefixId {}
218
219impl From<&[u8; OPERATION_ID_PREFIX_SIZE_BYTES]> for OperationPrefixId {
220    /// get prefix of the operation id of size `OPERATION_ID_PREFIX_SIZE_BIT`
221    fn from(bytes: &[u8; OPERATION_ID_PREFIX_SIZE_BYTES]) -> Self {
222        OperationPrefixIdVariant!["0"](OperationPrefixId!["0"](*bytes))
223    }
224}
225
226impl From<&OperationPrefixId> for Vec<u8> {
227    fn from(prefix: &OperationPrefixId) -> Self {
228        match prefix {
229            OperationPrefixId::OperationPrefixIdV0(prefix) => prefix.0.to_vec(),
230        }
231    }
232}
233
234impl OperationId {
235    /// convert the [`OperationId`] into a [`OperationPrefixId`]
236    pub fn into_prefix(self) -> OperationPrefixId {
237        match self {
238            OperationId::OperationIdV0(op_id) => op_id.into_prefix(),
239        }
240    }
241
242    /// get a prefix from the [`OperationId`] by copying it
243    pub fn prefix(&self) -> OperationPrefixId {
244        match self {
245            OperationId::OperationIdV0(op_id) => op_id.prefix(),
246        }
247    }
248
249    /// Get the version of the operation by looking at the first bytes of the id
250    pub fn get_version(&self) -> u64 {
251        match self {
252            OperationId::OperationIdV0(op_id) => op_id.get_version(),
253        }
254    }
255}
256
257#[transition::impl_version(versions("0"))]
258impl OperationId {
259    /// convert the [`OperationId`] into a [`OperationPrefixId`]
260    pub fn into_prefix(self) -> OperationPrefixId {
261        OperationPrefixId::OperationPrefixIdV0(OperationPrefixIdV0(
262            self.0.into_bytes()[..OPERATION_ID_PREFIX_SIZE_BYTES]
263                .try_into()
264                .expect("failed to truncate prefix from OperationId"),
265        ))
266    }
267
268    /// get a prefix from the [`OperationId`] by copying it
269    pub fn prefix(&self) -> OperationPrefixId {
270        OperationPrefixId::OperationPrefixIdV0(OperationPrefixIdV0(
271            self.0.to_bytes()[..OPERATION_ID_PREFIX_SIZE_BYTES]
272                .try_into()
273                .expect("failed to truncate prefix from OperationId"),
274        ))
275    }
276
277    fn get_hash(&self) -> &Hash {
278        &self.0
279    }
280
281    fn get_version(&self) -> u64 {
282        Self::VERSION
283    }
284}
285
286/// Serializer for `OperationId`
287#[derive(Default, Clone)]
288pub struct OperationIdSerializer {
289    version_serializer: U64VarIntSerializer,
290}
291
292impl OperationIdSerializer {
293    /// Creates a new serializer for `OperationId`
294    pub fn new() -> Self {
295        Self {
296            version_serializer: U64VarIntSerializer::new(),
297        }
298    }
299}
300
301impl Serializer<OperationId> for OperationIdSerializer {
302    fn serialize(&self, value: &OperationId, buffer: &mut Vec<u8>) -> Result<(), SerializeError> {
303        self.version_serializer
304            .serialize(&value.get_version(), buffer)?;
305        match value {
306            OperationId::OperationIdV0(id) => self.serialize(id, buffer),
307        }
308    }
309}
310
311#[transition::impl_version(versions("0"), structures("OperationId"))]
312impl Serializer<OperationId> for OperationIdSerializer {
313    fn serialize(&self, value: &OperationId, buffer: &mut Vec<u8>) -> Result<(), SerializeError> {
314        buffer.extend(value.0.to_bytes());
315        Ok(())
316    }
317}
318
319/// Deserializer for `OperationId`
320#[derive(Clone)]
321pub struct OperationIdDeserializer {
322    hash_deserializer: HashDeserializer,
323    version_deserializer: U64VarIntDeserializer,
324}
325
326impl OperationIdDeserializer {
327    /// Creates a new deserializer for `OperationId`
328    pub fn new() -> Self {
329        Self {
330            hash_deserializer: HashDeserializer::new(),
331            version_deserializer: U64VarIntDeserializer::new(Included(0), Included(u64::MAX)),
332        }
333    }
334}
335
336impl Default for OperationIdDeserializer {
337    fn default() -> Self {
338        Self::new()
339    }
340}
341
342impl Deserializer<OperationId> for OperationIdDeserializer {
343    fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
344        &self,
345        buffer: &'a [u8],
346    ) -> IResult<&'a [u8], OperationId, E> {
347        // Verify that we at least have a version and something else
348        if buffer.len() < 2 {
349            return Err(nom::Err::Error(E::from_error_kind(buffer, ErrorKind::Eof)));
350        }
351        let (rest, op_id_version) =
352            self.version_deserializer
353                .deserialize(buffer)
354                .map_err(|_: nom::Err<E>| {
355                    nom::Err::Error(E::from_error_kind(buffer, ErrorKind::Eof))
356                })?;
357        match op_id_version {
358            <OperationId!["0"]>::VERSION => {
359                let (rest, op_id) = self.deserialize(rest)?;
360                Ok((rest, OperationIdVariant!["0"](op_id)))
361            }
362            _ => Err(nom::Err::Error(E::from_error_kind(buffer, ErrorKind::Eof))),
363        }
364    }
365}
366
367#[transition::impl_version(versions("0"), structures("OperationId"))]
368impl Deserializer<OperationId> for OperationIdDeserializer {
369    fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
370        &self,
371        buffer: &'a [u8],
372    ) -> IResult<&'a [u8], OperationId, E> {
373        context("Failed OperationId deserialization", |input| {
374            self.hash_deserializer.deserialize(input)
375        })
376        .map(OperationId)
377        .parse(buffer)
378    }
379}
380
381#[derive(IntoPrimitive, Debug, Eq, PartialEq, TryFromPrimitive)]
382#[repr(u32)]
383enum OperationTypeId {
384    Transaction = 0,
385    RollBuy = 1,
386    RollSell = 2,
387    ExecuteSC = 3,
388    CallSC = 4,
389}
390
391/// the operation as sent in the network
392#[derive(Debug, Clone, Serialize, Deserialize)]
393// Only for unit test, otherwise, comparison should be made between OperationId
394#[cfg_attr(test, derive(PartialEq))]
395pub struct Operation {
396    /// the fee they have decided for this operation
397    pub fee: Amount,
398    /// after `expire_period` slot the operation won't be included in a block
399    pub expire_period: u64,
400    /// the type specific operation part
401    pub op: OperationType,
402}
403
404impl std::fmt::Display for Operation {
405    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
406        writeln!(f, "Fee: {}", self.fee)?;
407        writeln!(f, "Expire period: {}", self.expire_period)?;
408        writeln!(f, "Operation type: {}", self.op)?;
409        Ok(())
410    }
411}
412
413/// signed operation
414pub type SecureShareOperation = SecureShare<Operation, OperationId>;
415
416impl SecureShareContent for Operation {
417    fn compute_hash(
418        &self,
419        content_serialized: &[u8],
420        content_creator_pub_key: &PublicKey,
421        chain_id: u64,
422    ) -> Hash {
423        let mut hash_data = Vec::new();
424        // Note: Add chain id before content hash in order to avoid replay attacks,
425        //       otherwise someone can copy an operation from testnet and execute it on main net
426        // Note 2: This makes the OperationId unique (per chain id)
427        hash_data.extend(chain_id.to_be_bytes());
428        hash_data.extend(content_creator_pub_key.to_bytes());
429        hash_data.extend(content_serialized);
430        Hash::compute_from(&hash_data)
431    }
432}
433
434/// Serializer for `Operation`
435pub struct OperationSerializer {
436    u64_serializer: U64VarIntSerializer,
437    amount_serializer: AmountSerializer,
438    op_type_serializer: OperationTypeSerializer,
439}
440
441impl OperationSerializer {
442    /// Creates a new `OperationSerializer`
443    pub fn new() -> Self {
444        Self {
445            u64_serializer: U64VarIntSerializer::new(),
446            amount_serializer: AmountSerializer::new(),
447            op_type_serializer: OperationTypeSerializer::new(),
448        }
449    }
450}
451
452impl Default for OperationSerializer {
453    fn default() -> Self {
454        Self::new()
455    }
456}
457
458impl Serializer<Operation> for OperationSerializer {
459    /// ## Example:
460    /// ```rust
461    /// use massa_models::{amount::Amount, address::Address, operation::{OperationType, OperationSerializer, Operation}};
462    /// use massa_signature::KeyPair;
463    /// use massa_serialization::Serializer;
464    /// use std::str::FromStr;
465    ///
466    /// let keypair = KeyPair::generate(0).unwrap();
467    /// let op = OperationType::Transaction {
468    ///    recipient_address: Address::from_public_key(&keypair.get_public_key()),
469    ///    amount: Amount::from_str("300").unwrap(),
470    /// };
471    /// let operation = Operation {
472    ///   fee: Amount::from_str("20").unwrap(),
473    ///   op,
474    ///   expire_period: 50,
475    /// };
476    /// let mut buffer = Vec::new();
477    /// OperationSerializer::new().serialize(&operation, &mut buffer).unwrap();
478    /// ```
479    fn serialize(&self, value: &Operation, buffer: &mut Vec<u8>) -> Result<(), SerializeError> {
480        self.amount_serializer.serialize(&value.fee, buffer)?;
481        self.u64_serializer
482            .serialize(&value.expire_period, buffer)?;
483        self.op_type_serializer.serialize(&value.op, buffer)?;
484        Ok(())
485    }
486}
487
488/// Serializer for `Operation`
489pub struct OperationDeserializer {
490    expire_period_deserializer: U64VarIntDeserializer,
491    amount_deserializer: AmountDeserializer,
492    op_type_deserializer: OperationTypeDeserializer,
493}
494
495impl OperationDeserializer {
496    /// Creates a `OperationDeserializer`
497    pub fn new(
498        max_bytecode_size: u64,
499        max_function_name_length: u16,
500        max_parameters_size: u32,
501        max_op_datastore_entry_count: u64,
502        max_op_datastore_key_length: u8,
503        max_op_datastore_value_length: u64,
504    ) -> Self {
505        Self {
506            expire_period_deserializer: U64VarIntDeserializer::new(Included(0), Included(u64::MAX)),
507            amount_deserializer: AmountDeserializer::new(
508                Included(Amount::MIN),
509                Included(Amount::MAX),
510            ),
511            op_type_deserializer: OperationTypeDeserializer::new(
512                max_bytecode_size,
513                max_function_name_length,
514                max_parameters_size,
515                max_op_datastore_entry_count,
516                max_op_datastore_key_length,
517                max_op_datastore_value_length,
518            ),
519        }
520    }
521}
522
523impl Deserializer<Operation> for OperationDeserializer {
524    /// ## Example:
525    /// ```rust
526    /// use massa_models::{amount::Amount, address::Address, operation::{OperationType, OperationSerializer, Operation, OperationDeserializer}};
527    /// use massa_signature::KeyPair;
528    /// use massa_serialization::{Serializer, Deserializer, DeserializeError};
529    /// use std::str::FromStr;
530    ///
531    /// let keypair = KeyPair::generate(0).unwrap();
532    /// let op = OperationType::Transaction {
533    ///    recipient_address: Address::from_public_key(&keypair.get_public_key()),
534    ///    amount: Amount::from_str("300").unwrap(),
535    /// };
536    /// let operation = Operation {
537    ///   fee: Amount::from_str("20").unwrap(),
538    ///   op,
539    ///   expire_period: 50,
540    /// };
541    /// let mut buffer = Vec::new();
542    /// OperationSerializer::new().serialize(&operation, &mut buffer).unwrap();
543    /// let (rest, deserialized_operation) = OperationDeserializer::new(10000, 10000, 10000, 100, 255, 10_000).deserialize::<DeserializeError>(&buffer).unwrap();
544    /// assert_eq!(rest.len(), 0);
545    /// assert_eq!(deserialized_operation.fee, operation.fee);
546    /// assert_eq!(deserialized_operation.expire_period, operation.expire_period);
547    /// match deserialized_operation.op {
548    ///   OperationType::Transaction {
549    ///     recipient_address,
550    ///     amount,
551    ///   } => {
552    ///     assert_eq!(recipient_address, Address::from_public_key(&keypair.get_public_key()));
553    ///     assert_eq!(amount, Amount::from_str("300").unwrap());
554    ///   }
555    ///   _ => panic!("wrong operation type"),
556    /// };
557    /// ```
558    fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
559        &self,
560        buffer: &'a [u8],
561    ) -> IResult<&'a [u8], Operation, E> {
562        context(
563            "Failed Operation deserialization",
564            tuple((
565                context("Failed fee deserialization", |input| {
566                    self.amount_deserializer.deserialize(input)
567                }),
568                context("Failed expire_period deserialization", |input| {
569                    self.expire_period_deserializer.deserialize(input)
570                }),
571                context("Failed op deserialization", |input| {
572                    let (rest, op) = self.op_type_deserializer.deserialize(input)?;
573                    Ok((rest, op))
574                }),
575            )),
576        )
577        .map(|(fee, expire_period, op)| Operation {
578            fee,
579            expire_period,
580            op,
581        })
582        .parse(buffer)
583    }
584}
585
586/// Type specific operation content
587#[serde_as]
588#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
589pub enum OperationType {
590    /// transfer coins from sender to recipient
591    Transaction {
592        /// recipient address
593        recipient_address: Address,
594        /// amount
595        amount: Amount,
596    },
597    /// the sender buys `roll_count` rolls. Roll price is defined in configuration
598    RollBuy {
599        /// roll count
600        roll_count: u64,
601    },
602    /// the sender sells `roll_count` rolls. Roll price is defined in configuration
603    RollSell {
604        /// roll count
605        roll_count: u64,
606    },
607    /// Execute a smart contract.
608    ExecuteSC {
609        /// Smart contract bytecode.
610        data: Vec<u8>,
611        /// The maximum amount of gas that the execution of the contract is allowed to cost.
612        max_gas: u64,
613        /// Max amount of coins allowed to be spent by the execution
614        max_coins: Amount,
615        /// A key-value store associating a hash to arbitrary bytes
616        #[serde_as(as = "Vec<(_, _)>")]
617        datastore: Datastore,
618    },
619    /// Calls an exported function from a stored smart contract
620    CallSC {
621        /// Target smart contract address
622        target_addr: Address,
623        /// Target function name. No function is called if empty.
624        target_func: String,
625        /// Parameter to pass to the target function
626        param: Vec<u8>,
627        /// The maximum amount of gas that the execution of the contract is allowed to cost.
628        max_gas: u64,
629        /// Extra coins that are spent from the caller's balance and transferred to the target
630        coins: Amount,
631    },
632}
633
634impl std::fmt::Display for OperationType {
635    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
636        match self {
637            OperationType::Transaction {
638                recipient_address,
639                amount,
640            } => {
641                writeln!(f, "Transaction:")?;
642                writeln!(f, "\t- Recipient:{}", recipient_address)?;
643                writeln!(f, "\t  Amount:{}", amount)?;
644            }
645            OperationType::RollBuy { roll_count } => {
646                writeln!(f, "Buy rolls:")?;
647                writeln!(f, "\t- Roll count:{}", roll_count)?;
648            }
649            OperationType::RollSell { roll_count } => {
650                writeln!(f, "Sell rolls:")?;
651                writeln!(f, "\t- Roll count:{}", roll_count)?;
652            }
653            OperationType::ExecuteSC {
654                max_gas,
655                max_coins,
656                ..
657                // data & datastore, // these fields are ignored because bytes eh
658            } => {
659                writeln!(f, "ExecuteSC: ")?;
660                writeln!(f, "\t- max_coins:{}", max_coins)?;
661                writeln!(f, "\t- max_gas:{}", max_gas)?;
662            },
663            OperationType::CallSC {
664                max_gas,
665                coins,
666                target_addr,
667                target_func,
668                param
669            } => {
670                writeln!(f, "CallSC:")?;
671                writeln!(f, "\t- target address:{}", target_addr)?;
672                writeln!(f, "\t- target function:{}", target_func)?;
673                writeln!(f, "\t- target parameter:{:?}", param)?;
674                writeln!(f, "\t- max_gas:{}", max_gas)?;
675                writeln!(f, "\t- coins:{}", coins)?;
676            }
677        }
678        Ok(())
679    }
680}
681
682/// Serializer for `OperationType`
683pub struct OperationTypeSerializer {
684    u32_serializer: U32VarIntSerializer,
685    u64_serializer: U64VarIntSerializer,
686    vec_u8_serializer: VecU8Serializer,
687    amount_serializer: AmountSerializer,
688    address_serializer: AddressSerializer,
689    function_name_serializer: StringSerializer<U16VarIntSerializer, u16>,
690    datastore_serializer: DatastoreSerializer,
691}
692
693impl OperationTypeSerializer {
694    /// Creates a new `OperationTypeSerializer`
695    pub fn new() -> Self {
696        Self {
697            u32_serializer: U32VarIntSerializer::new(),
698            u64_serializer: U64VarIntSerializer::new(),
699            vec_u8_serializer: VecU8Serializer::new(),
700            amount_serializer: AmountSerializer::new(),
701            address_serializer: AddressSerializer::new(),
702            function_name_serializer: StringSerializer::new(U16VarIntSerializer::new()),
703            datastore_serializer: DatastoreSerializer::new(),
704        }
705    }
706}
707
708impl Default for OperationTypeSerializer {
709    fn default() -> Self {
710        Self::new()
711    }
712}
713
714impl Serializer<OperationType> for OperationTypeSerializer {
715    /// ## Example:
716    /// ```rust
717    /// use std::collections::BTreeMap;
718    /// use massa_models::{operation::{OperationTypeSerializer, OperationTypeDeserializer,OperationType}, address::Address, amount::Amount};
719    /// use massa_signature::KeyPair;
720    /// use massa_serialization::{Deserializer, Serializer, DeserializeError};
721    /// use std::str::FromStr;
722    ///
723    /// let keypair = KeyPair::generate(0).unwrap();
724    /// let op = OperationType::ExecuteSC {
725    ///    data: vec![0x01, 0x02, 0x03],
726    ///    max_gas: 100,
727    ///    max_coins: Amount::from_str("5000000").unwrap(),
728    ///    datastore: BTreeMap::default(),
729    /// };
730    /// let mut buffer = Vec::new();
731    /// OperationTypeSerializer::new().serialize(&op, &mut buffer).unwrap();
732    /// ```
733    fn serialize(&self, value: &OperationType, buffer: &mut Vec<u8>) -> Result<(), SerializeError> {
734        match value {
735            OperationType::Transaction {
736                recipient_address,
737                amount,
738            } => {
739                self.u32_serializer
740                    .serialize(&u32::from(OperationTypeId::Transaction), buffer)?;
741                self.address_serializer
742                    .serialize(recipient_address, buffer)?;
743                self.amount_serializer.serialize(amount, buffer)?;
744            }
745            OperationType::RollBuy { roll_count } => {
746                self.u32_serializer
747                    .serialize(&u32::from(OperationTypeId::RollBuy), buffer)?;
748                self.u64_serializer.serialize(roll_count, buffer)?;
749            }
750            OperationType::RollSell { roll_count } => {
751                self.u32_serializer
752                    .serialize(&u32::from(OperationTypeId::RollSell), buffer)?;
753                self.u64_serializer.serialize(roll_count, buffer)?;
754            }
755            OperationType::ExecuteSC {
756                data,
757                max_gas,
758                max_coins,
759                datastore,
760            } => {
761                self.u32_serializer
762                    .serialize(&u32::from(OperationTypeId::ExecuteSC), buffer)?;
763                self.u64_serializer.serialize(max_gas, buffer)?;
764                self.amount_serializer.serialize(max_coins, buffer)?;
765                self.vec_u8_serializer.serialize(data, buffer)?;
766                self.datastore_serializer.serialize(datastore, buffer)?;
767            }
768            OperationType::CallSC {
769                target_addr,
770                target_func,
771                param,
772                max_gas,
773                coins,
774            } => {
775                self.u32_serializer
776                    .serialize(&u32::from(OperationTypeId::CallSC), buffer)?;
777                self.u64_serializer.serialize(max_gas, buffer)?;
778                self.amount_serializer.serialize(coins, buffer)?;
779                self.address_serializer.serialize(target_addr, buffer)?;
780                self.function_name_serializer
781                    .serialize(target_func, buffer)?;
782                self.vec_u8_serializer.serialize(param, buffer)?;
783            }
784        }
785        Ok(())
786    }
787}
788
789/// Deserializer for `OperationType`
790pub struct OperationTypeDeserializer {
791    id_deserializer: U32VarIntDeserializer,
792    rolls_number_deserializer: U64VarIntDeserializer,
793    max_gas_deserializer: U64VarIntDeserializer,
794    address_deserializer: AddressDeserializer,
795    data_deserializer: VecU8Deserializer,
796    amount_deserializer: AmountDeserializer,
797    function_name_deserializer: StringDeserializer<U16VarIntDeserializer, u16>,
798    parameter_deserializer: VecU8Deserializer,
799    datastore_deserializer: DatastoreDeserializer,
800}
801
802impl OperationTypeDeserializer {
803    /// Creates a new `OperationTypeDeserializer`
804    pub fn new(
805        max_bytecode_size: u64,
806        max_function_name_length: u16,
807        max_parameters_size: u32,
808        max_op_datastore_entry_count: u64,
809        max_op_datastore_key_length: u8,
810        max_op_datastore_value_length: u64,
811    ) -> Self {
812        Self {
813            id_deserializer: U32VarIntDeserializer::new(Included(0), Included(u32::MAX)),
814            rolls_number_deserializer: U64VarIntDeserializer::new(Included(0), Included(u64::MAX)),
815            max_gas_deserializer: U64VarIntDeserializer::new(Included(0), Included(u64::MAX)),
816            address_deserializer: AddressDeserializer::new(),
817            data_deserializer: VecU8Deserializer::new(Included(0), Included(max_bytecode_size)),
818            amount_deserializer: AmountDeserializer::new(
819                Included(Amount::MIN),
820                Included(Amount::MAX),
821            ),
822            function_name_deserializer: StringDeserializer::new(U16VarIntDeserializer::new(
823                Included(0),
824                Included(max_function_name_length),
825            )),
826            parameter_deserializer: VecU8Deserializer::new(
827                Included(0),
828                Included(max_parameters_size as u64),
829            ),
830            datastore_deserializer: DatastoreDeserializer::new(
831                max_op_datastore_entry_count,
832                max_op_datastore_key_length,
833                max_op_datastore_value_length,
834            ),
835        }
836    }
837}
838
839impl Deserializer<OperationType> for OperationTypeDeserializer {
840    /// ## Example:
841    /// ```rust
842    /// use std::collections::BTreeMap;
843    /// use massa_models::{operation::{OperationTypeSerializer, OperationTypeDeserializer, OperationType}, address::Address, amount::Amount};
844    /// use massa_signature::KeyPair;
845    /// use massa_serialization::{Deserializer, Serializer, DeserializeError};
846    /// use std::str::FromStr;
847    ///
848    /// let keypair = KeyPair::generate(0).unwrap();
849    /// let op = OperationType::ExecuteSC {
850    ///    data: vec![0x01, 0x02, 0x03],
851    ///    max_gas: 100,
852    ///    max_coins: Amount::from_str("5000000").unwrap(),
853    ///    datastore: BTreeMap::from([(vec![1, 2], vec![254, 255])])
854    /// };
855    /// let mut buffer = Vec::new();
856    /// OperationTypeSerializer::new().serialize(&op, &mut buffer).unwrap();
857    /// let (rest, op_deserialized) = OperationTypeDeserializer::new(10000, 10000, 10000, 10, 255, 10_000).deserialize::<DeserializeError>(&buffer).unwrap();
858    /// assert_eq!(rest.len(), 0);
859    /// match op_deserialized {
860    ///    OperationType::ExecuteSC {
861    ///      data,
862    ///      max_gas,
863    ///      max_coins,
864    ///      datastore
865    ///   } => {
866    ///     assert_eq!(data, vec![0x01, 0x02, 0x03]);
867    ///     assert_eq!(max_gas, 100);
868    ///     assert_eq!(max_coins, Amount::from_str("5000000").unwrap());
869    ///     assert_eq!(datastore, BTreeMap::from([(vec![1, 2], vec![254, 255])]))
870    ///   }
871    ///   _ => panic!("Unexpected operation type"),
872    /// };
873    /// ```
874    fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
875        &self,
876        buffer: &'a [u8],
877    ) -> IResult<&'a [u8], OperationType, E> {
878        context("Failed OperationType deserialization", |buffer| {
879            let (input, id) = self.id_deserializer.deserialize(buffer)?;
880            let id = OperationTypeId::try_from(id).map_err(|_| {
881                nom::Err::Error(ParseError::from_error_kind(
882                    buffer,
883                    nom::error::ErrorKind::Eof,
884                ))
885            })?;
886            match id {
887                OperationTypeId::Transaction => context(
888                    "Failed Transaction deserialization",
889                    tuple((
890                        context("Failed recipient_address deserialization", |input| {
891                            self.address_deserializer.deserialize(input)
892                        }),
893                        context("Failed amount deserialization", |input| {
894                            self.amount_deserializer.deserialize(input)
895                        }),
896                    )),
897                )
898                .map(|(recipient_address, amount)| OperationType::Transaction {
899                    recipient_address,
900                    amount,
901                })
902                .parse(input),
903                OperationTypeId::RollBuy => context("Failed RollBuy deserialization", |input| {
904                    self.rolls_number_deserializer.deserialize(input)
905                })
906                .map(|roll_count| OperationType::RollBuy { roll_count })
907                .parse(input),
908                OperationTypeId::RollSell => context("Failed RollSell deserialization", |input| {
909                    self.rolls_number_deserializer.deserialize(input)
910                })
911                .map(|roll_count| OperationType::RollSell { roll_count })
912                .parse(input),
913                OperationTypeId::ExecuteSC => context(
914                    "Failed ExecuteSC deserialization",
915                    tuple((
916                        context("Failed max_gas deserialization", |input| {
917                            self.max_gas_deserializer.deserialize(input)
918                        }),
919                        context("Failed max_coins deserialization", |input| {
920                            self.amount_deserializer.deserialize(input)
921                        }),
922                        context("Failed data deserialization", |input| {
923                            self.data_deserializer.deserialize(input)
924                        }),
925                        context("Failed datastore deserialization", |input| {
926                            self.datastore_deserializer.deserialize(input)
927                        }),
928                    )),
929                )
930                .map(
931                    |(max_gas, max_coins, data, datastore)| OperationType::ExecuteSC {
932                        data,
933                        max_gas,
934                        max_coins,
935                        datastore,
936                    },
937                )
938                .parse(input),
939                OperationTypeId::CallSC => context(
940                    "Failed CallSC deserialization",
941                    tuple((
942                        context("Failed max_gas deserialization", |input| {
943                            self.max_gas_deserializer.deserialize(input)
944                        }),
945                        context("Failed coins deserialization", |input| {
946                            self.amount_deserializer.deserialize(input)
947                        }),
948                        context("Failed target_addr deserialization", |input| {
949                            self.address_deserializer.deserialize(input)
950                        }),
951                        context("Failed target_func deserialization", |input| {
952                            self.function_name_deserializer.deserialize(input)
953                        }),
954                        context("Failed param deserialization", |input| {
955                            self.parameter_deserializer.deserialize(input)
956                        }),
957                    )),
958                )
959                .map(
960                    |(max_gas, coins, target_addr, target_func, param)| OperationType::CallSC {
961                        target_addr,
962                        target_func,
963                        param,
964                        max_gas,
965                        coins,
966                    },
967                )
968                .parse(input),
969            }
970        })
971        .parse(buffer)
972    }
973}
974
975impl SecureShareOperation {
976    /// get the range of periods during which an operation is valid
977    /// Range: `(op.expire_period - cfg.operation_validity_period) -> op.expire_period` (included)
978    pub fn get_validity_range(&self, operation_validity_period: u64) -> RangeInclusive<u64> {
979        let start = self
980            .content
981            .expire_period
982            .saturating_sub(operation_validity_period);
983        start..=self.content.expire_period
984    }
985
986    /// Get the maximum amount of gas used by the operation.
987    ///
988    /// base_operation_gas_cost comes from the configuration and
989    /// is the cost of a basic operation (BASE_OPERATION_GAS_COST)
990    pub fn get_gas_usage(&self, base_operation_gas_cost: u64, sp_compilation_cost: u64) -> u64 {
991        match &self.content.op {
992            OperationType::ExecuteSC { max_gas, .. } => max_gas.saturating_add(sp_compilation_cost),
993            OperationType::CallSC { max_gas, .. } => *max_gas,
994            OperationType::RollBuy { .. } => 0,
995            OperationType::RollSell { .. } => 0,
996            OperationType::Transaction { .. } => 0,
997        }
998        .saturating_add(base_operation_gas_cost)
999    }
1000
1001    /// Check that the operation can ever fit in a block, gas-wise.
1002    ///
1003    /// Compares the full gas usage (see `get_gas_usage`, mandatory overheads included)
1004    /// against the block gas limit, so that every submission interface applies the same
1005    /// includability criterion as the block filling logic.
1006    ///
1007    /// On failure returns the client-facing error message, stating the highest `max_gas`
1008    /// the operation could have declared.
1009    pub fn check_gas_usage(
1010        &self,
1011        max_gas_per_block: u64,
1012        base_operation_gas_cost: u64,
1013        sp_compilation_cost: u64,
1014    ) -> Result<(), String> {
1015        // gas that the operation is charged on top of its declared max_gas
1016        let (op_name, gas_overhead) = match &self.content.op {
1017            OperationType::CallSC { .. } => ("CallSC", base_operation_gas_cost),
1018            OperationType::ExecuteSC { .. } => (
1019                "ExecuteSC",
1020                base_operation_gas_cost.saturating_add(sp_compilation_cost),
1021            ),
1022            OperationType::RollBuy { .. }
1023            | OperationType::RollSell { .. }
1024            | OperationType::Transaction { .. } => return Ok(()),
1025        };
1026        if self.get_gas_usage(base_operation_gas_cost, sp_compilation_cost) > max_gas_per_block {
1027            return Err(format!(
1028                "Upper gas limit for {} operation is {}. Your operation will never be included in a block.",
1029                op_name,
1030                max_gas_per_block.saturating_sub(gas_overhead)
1031            ));
1032        }
1033        Ok(())
1034    }
1035
1036    /// get the addresses that are involved in this operation from a ledger point of view
1037    pub fn get_ledger_involved_addresses(&self) -> PreHashSet<Address> {
1038        let mut res = PreHashSet::<Address>::default();
1039        let emitter_address = Address::from_public_key(&self.content_creator_pub_key);
1040        res.insert(emitter_address);
1041        match &self.content.op {
1042            OperationType::Transaction {
1043                recipient_address, ..
1044            } => {
1045                res.insert(*recipient_address);
1046            }
1047            OperationType::RollBuy { .. } => {}
1048            OperationType::RollSell { .. } => {}
1049            OperationType::ExecuteSC { .. } => {}
1050            OperationType::CallSC { target_addr, .. } => {
1051                res.insert(*target_addr);
1052            }
1053        }
1054        res
1055    }
1056
1057    /// Gets the maximal amount of coins that may be spent by this operation (incl. fee)
1058    pub fn get_max_spending(&self, roll_price: Amount) -> Amount {
1059        // compute the max amount of coins spent outside of the fees
1060        let max_non_fee_seq_spending = match &self.content.op {
1061            OperationType::Transaction { amount, .. } => *amount,
1062            OperationType::RollBuy { roll_count } => roll_price.saturating_mul_u64(*roll_count),
1063            OperationType::RollSell { .. } => Amount::zero(),
1064            OperationType::ExecuteSC { max_coins, .. } => *max_coins,
1065            OperationType::CallSC { coins, .. } => *coins,
1066        };
1067
1068        // add all fees and return
1069        max_non_fee_seq_spending.saturating_add(self.content.fee)
1070    }
1071
1072    /// get the addresses that are involved in this operation from a rolls point of view
1073    pub fn get_roll_involved_addresses(&self) -> Result<PreHashSet<Address>, ModelsError> {
1074        let mut res = PreHashSet::<Address>::default();
1075        match self.content.op {
1076            OperationType::Transaction { .. } => {}
1077            OperationType::RollBuy { .. } => {
1078                res.insert(Address::from_public_key(&self.content_creator_pub_key));
1079            }
1080            OperationType::RollSell { .. } => {
1081                res.insert(Address::from_public_key(&self.content_creator_pub_key));
1082            }
1083            OperationType::ExecuteSC { .. } => {}
1084            OperationType::CallSC { .. } => {}
1085        }
1086        Ok(res)
1087    }
1088}
1089
1090/// Set of operation id's prefix
1091pub type OperationPrefixIds = PreHashSet<OperationPrefixId>;
1092
1093/// Serializer for `Vec<OperationId>`
1094pub struct OperationIdsSerializer {
1095    u32_serializer: U32VarIntSerializer,
1096    op_id_serializer: OperationIdSerializer,
1097}
1098
1099impl OperationIdsSerializer {
1100    /// Creates a new `OperationIdsSerializer`
1101    pub fn new() -> Self {
1102        Self {
1103            u32_serializer: U32VarIntSerializer::new(),
1104            op_id_serializer: OperationIdSerializer::new(),
1105        }
1106    }
1107}
1108
1109impl Default for OperationIdsSerializer {
1110    fn default() -> Self {
1111        Self::new()
1112    }
1113}
1114
1115impl Serializer<Vec<OperationId>> for OperationIdsSerializer {
1116    /// ## Example:
1117    /// ```
1118    /// use massa_models::operation::{OperationId, OperationIdsSerializer};
1119    /// use massa_serialization::Serializer;
1120    /// use std::str::FromStr;
1121    ///
1122    /// let mut operations_ids = Vec::new();
1123    /// operations_ids.push(OperationId::from_str("O1xcVGtyWAyrehW1NDpnZ1wE5K95n8qVJCV9dEJSp1ypU8eJsQU").unwrap());
1124    /// operations_ids.push(OperationId::from_str("O1xcVGtyWAyrehW1NDpnZ1wE5K95n8qVJCV9dEJSp1ypU8eJsQU").unwrap());
1125    /// let mut buffer = Vec::new();
1126    /// OperationIdsSerializer::new().serialize(&operations_ids, &mut buffer).unwrap();
1127    /// ```
1128    fn serialize(
1129        &self,
1130        value: &Vec<OperationId>,
1131        buffer: &mut Vec<u8>,
1132    ) -> Result<(), SerializeError> {
1133        let list_len: u32 = value.len().try_into().map_err(|_| {
1134            SerializeError::NumberTooBig(
1135                "could not encode Vec<OperationId> list length as u32".into(),
1136            )
1137        })?;
1138        self.u32_serializer.serialize(&list_len, buffer)?;
1139        for hash in value {
1140            self.op_id_serializer.serialize(hash, buffer)?;
1141        }
1142        Ok(())
1143    }
1144}
1145
1146/// Deserializer for `Vec<OperationId>`
1147pub struct OperationIdsDeserializer {
1148    length_deserializer: U32VarIntDeserializer,
1149    op_id_deserializer: OperationIdDeserializer,
1150}
1151
1152impl OperationIdsDeserializer {
1153    /// Creates a new `OperationIdsDeserializer`
1154    pub fn new(max_operations_per_message: u32) -> Self {
1155        Self {
1156            length_deserializer: U32VarIntDeserializer::new(
1157                Included(0),
1158                Included(max_operations_per_message),
1159            ),
1160            op_id_deserializer: OperationIdDeserializer::new(),
1161        }
1162    }
1163}
1164
1165impl Deserializer<Vec<OperationId>> for OperationIdsDeserializer {
1166    /// ## Example:
1167    /// ```
1168    /// use massa_models::operation::{OperationId, OperationIdsSerializer, OperationIdsDeserializer};
1169    /// use massa_serialization::{Serializer, Deserializer, DeserializeError};
1170    /// use std::str::FromStr;
1171    ///
1172    /// let mut operations_ids = Vec::new();
1173    /// operations_ids.push(OperationId::from_str("O1xcVGtyWAyrehW1NDpnZ1wE5K95n8qVJCV9dEJSp1ypU8eJsQU").unwrap());
1174    /// operations_ids.push(OperationId::from_str("O1xcVGtyWAyrehW1NDpnZ1wE5K95n8qVJCV9dEJSp1ypU8eJsQU").unwrap());
1175    /// let mut buffer = Vec::new();
1176    /// OperationIdsSerializer::new().serialize(&operations_ids, &mut buffer).unwrap();
1177    /// let (rest, deserialized_operations_ids) = OperationIdsDeserializer::new(1000).deserialize::<DeserializeError>(&buffer).unwrap();
1178    /// assert_eq!(rest.len(), 0);
1179    /// assert_eq!(deserialized_operations_ids, operations_ids);
1180    /// ```
1181    fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
1182        &self,
1183        buffer: &'a [u8],
1184    ) -> IResult<&'a [u8], Vec<OperationId>, E> {
1185        context(
1186            "Failed Vec<OperationId> deserialization",
1187            length_count(
1188                context("Failed length deserialization", |input| {
1189                    self.length_deserializer.deserialize(input)
1190                }),
1191                context("Failed OperationId deserialization", |input| {
1192                    self.op_id_deserializer.deserialize(input)
1193                }),
1194            ),
1195        )
1196        .parse(buffer)
1197    }
1198}
1199
1200/// Deserializer for [`OperationPrefixId`]
1201#[derive(Default)]
1202pub struct OperationPrefixIdDeserializer;
1203
1204impl OperationPrefixIdDeserializer {
1205    /// Creates a deserializer for [`OperationPrefixId`]
1206    pub const fn new() -> Self {
1207        Self
1208    }
1209}
1210
1211impl Deserializer<OperationPrefixId> for OperationPrefixIdDeserializer {
1212    /// ## Example:
1213    /// ```rust
1214    /// use massa_models::operation::{OperationPrefixId, OperationPrefixIds, OperationPrefixIdsSerializer, OPERATION_ID_PREFIX_SIZE_BYTES};
1215    /// use massa_serialization::Serializer;
1216    ///
1217    /// let mut op_prefixes = OperationPrefixIds::default();
1218    /// op_prefixes.insert(OperationPrefixId::from(&[20; OPERATION_ID_PREFIX_SIZE_BYTES]));
1219    /// op_prefixes.insert(OperationPrefixId::from(&[20; OPERATION_ID_PREFIX_SIZE_BYTES]));
1220    /// let mut buffer = Vec::new();
1221    /// OperationPrefixIdsSerializer::new().serialize(&op_prefixes, &mut buffer).unwrap();
1222    /// ```
1223    fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
1224        &self,
1225        buffer: &'a [u8],
1226    ) -> IResult<&'a [u8], OperationPrefixId, E> {
1227        context(
1228            "Failed operation prefix id deserialization",
1229            |input: &'a [u8]| {
1230                if buffer.len() < OPERATION_ID_PREFIX_SIZE_BYTES {
1231                    return Err(nom::Err::Error(ParseError::from_error_kind(
1232                        input,
1233                        nom::error::ErrorKind::LengthValue,
1234                    )));
1235                }
1236                Ok((
1237                    &buffer[OPERATION_ID_PREFIX_SIZE_BYTES..],
1238                    OperationPrefixId::from(
1239                        &buffer[..OPERATION_ID_PREFIX_SIZE_BYTES]
1240                            .try_into()
1241                            .map_err(|_| {
1242                                nom::Err::Error(ParseError::from_error_kind(
1243                                    input,
1244                                    nom::error::ErrorKind::Fail,
1245                                ))
1246                            })?,
1247                    ),
1248                ))
1249            },
1250        )(buffer)
1251    }
1252}
1253
1254/// Deserializer for `OperationPrefixIds`
1255pub struct OperationPrefixIdsDeserializer {
1256    length_deserializer: U32VarIntDeserializer,
1257    pref_deserializer: OperationPrefixIdDeserializer,
1258}
1259
1260impl OperationPrefixIdsDeserializer {
1261    /// Creates a new `OperationIdsDeserializer`
1262    pub const fn new(max_operations_per_message: u32) -> Self {
1263        Self {
1264            length_deserializer: U32VarIntDeserializer::new(
1265                Included(0),
1266                Included(max_operations_per_message),
1267            ),
1268            pref_deserializer: OperationPrefixIdDeserializer::new(),
1269        }
1270    }
1271}
1272
1273impl Deserializer<OperationPrefixIds> for OperationPrefixIdsDeserializer {
1274    /// ## Example:
1275    /// ```rust
1276    /// use massa_models::{operation::{OperationPrefixId, OperationPrefixIds, OperationPrefixIdsSerializer, OperationPrefixIdsDeserializer, OPERATION_ID_PREFIX_SIZE_BYTES}};
1277    /// use massa_serialization::{Serializer, Deserializer, DeserializeError};
1278    ///
1279    /// let mut op_prefixes = OperationPrefixIds::default();
1280    /// op_prefixes.insert(OperationPrefixId::from(&[20; OPERATION_ID_PREFIX_SIZE_BYTES]));
1281    /// op_prefixes.insert(OperationPrefixId::from(&[20; OPERATION_ID_PREFIX_SIZE_BYTES]));
1282    /// let mut buffer = Vec::new();
1283    /// OperationPrefixIdsSerializer::new().serialize(&op_prefixes, &mut buffer).unwrap();
1284    /// let (rest, deserialized) = OperationPrefixIdsDeserializer::new(1000).deserialize::<DeserializeError>(&buffer).unwrap();
1285    /// assert_eq!(rest.len(), 0);
1286    /// assert_eq!(deserialized, op_prefixes);
1287    /// ```
1288    fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
1289        &self,
1290        buffer: &'a [u8],
1291    ) -> IResult<&'a [u8], OperationPrefixIds, E> {
1292        context(
1293            "Failed OperationPrefixIds deserialization",
1294            length_count(
1295                context("Failed length deserialization", |input| {
1296                    self.length_deserializer.deserialize(input)
1297                }),
1298                context("Failed OperationPrefixId deserialization", |input| {
1299                    self.pref_deserializer.deserialize(input)
1300                }),
1301            ),
1302        )
1303        .map(|hashes| hashes.into_iter().collect())
1304        .parse(buffer)
1305    }
1306}
1307
1308/// Serializer for `OperationPrefixIds`
1309#[derive(Clone)]
1310pub struct OperationPrefixIdsSerializer {
1311    u32_serializer: U32VarIntSerializer,
1312}
1313
1314impl OperationPrefixIdsSerializer {
1315    /// Creates a new `OperationIdsSerializer`
1316    pub const fn new() -> Self {
1317        Self {
1318            u32_serializer: U32VarIntSerializer::new(),
1319        }
1320    }
1321}
1322
1323impl Default for OperationPrefixIdsSerializer {
1324    fn default() -> Self {
1325        Self::new()
1326    }
1327}
1328
1329impl Serializer<OperationPrefixIds> for OperationPrefixIdsSerializer {
1330    fn serialize(
1331        &self,
1332        value: &OperationPrefixIds,
1333        buffer: &mut Vec<u8>,
1334    ) -> Result<(), SerializeError> {
1335        let list_len: u32 = value.len().try_into().map_err(|_| {
1336            SerializeError::NumberTooBig(
1337                "could not encode Set<OperationId> list length as u32".into(),
1338            )
1339        })?;
1340        self.u32_serializer.serialize(&list_len, buffer)?;
1341        for prefix in value {
1342            buffer.extend(Vec::<u8>::from(prefix));
1343        }
1344        Ok(())
1345    }
1346}
1347
1348/// Serializer for `Operations`
1349#[derive(Clone)]
1350pub struct OperationsSerializer {
1351    u32_serializer: U32VarIntSerializer,
1352    signed_op_serializer: SecureShareSerializer,
1353}
1354
1355impl OperationsSerializer {
1356    /// Creates a new `OperationsSerializer`
1357    pub const fn new() -> Self {
1358        Self {
1359            u32_serializer: U32VarIntSerializer::new(),
1360            signed_op_serializer: SecureShareSerializer::new(),
1361        }
1362    }
1363}
1364
1365impl Default for OperationsSerializer {
1366    fn default() -> Self {
1367        Self::new()
1368    }
1369}
1370
1371impl Serializer<Vec<SecureShareOperation>> for OperationsSerializer {
1372    /// ## Example:
1373    /// ```rust
1374    /// use massa_models::{operation::{SecureShareOperation, Operation, OperationType, OperationsSerializer, OperationSerializer}, secure_share::SecureShareContent, address::Address, amount::Amount};
1375    /// use massa_signature::KeyPair;
1376    /// use massa_serialization::Serializer;
1377    /// use std::str::FromStr;
1378    /// use massa_models::config::CHAINID;
1379    ///
1380    /// let keypair = KeyPair::generate(0).unwrap();
1381    /// let op = OperationType::Transaction {
1382    ///    recipient_address: Address::from_public_key(&keypair.get_public_key()),
1383    ///    amount: Amount::from_str("300").unwrap(),
1384    /// };
1385    /// let content = Operation {
1386    ///   fee: Amount::from_str("20").unwrap(),
1387    ///   op,
1388    ///   expire_period: 50,
1389    /// };
1390    /// let op_secured = Operation::new_verifiable(content, OperationSerializer::new(), &keypair, *CHAINID).unwrap();
1391    /// let operations = vec![op_secured.clone(), op_secured.clone()];
1392    /// let mut buffer = Vec::new();
1393    /// OperationsSerializer::new().serialize(&operations, &mut buffer).unwrap();
1394    /// ```
1395    fn serialize(
1396        &self,
1397        value: &Vec<SecureShareOperation>,
1398        buffer: &mut Vec<u8>,
1399    ) -> Result<(), SerializeError> {
1400        let list_len: u32 = value.len().try_into().map_err(|_| {
1401            SerializeError::NumberTooBig("could not encode Operations list length as u32".into())
1402        })?;
1403        self.u32_serializer.serialize(&list_len, buffer)?;
1404        for op in value {
1405            self.signed_op_serializer.serialize(op, buffer)?;
1406        }
1407        Ok(())
1408    }
1409}
1410
1411/// Deserializer for `Operations`
1412pub struct OperationsDeserializer {
1413    length_deserializer: U32VarIntDeserializer,
1414    signed_op_deserializer: SecureShareDeserializer<Operation, OperationDeserializer>,
1415}
1416
1417impl OperationsDeserializer {
1418    #[allow(clippy::too_many_arguments)]
1419    /// Creates a new `OperationsDeserializer`
1420    pub fn new(
1421        max_operations_per_message: u32,
1422        max_bytecode_size: u64,
1423        max_function_name_length: u16,
1424        max_parameters_size: u32,
1425        max_op_datastore_entry_count: u64,
1426        max_op_datastore_key_length: u8,
1427        max_op_datastore_value_length: u64,
1428        chain_id: u64,
1429    ) -> Self {
1430        Self {
1431            length_deserializer: U32VarIntDeserializer::new(
1432                Included(0),
1433                Included(max_operations_per_message),
1434            ),
1435            signed_op_deserializer: SecureShareDeserializer::new(
1436                OperationDeserializer::new(
1437                    max_bytecode_size,
1438                    max_function_name_length,
1439                    max_parameters_size,
1440                    max_op_datastore_entry_count,
1441                    max_op_datastore_key_length,
1442                    max_op_datastore_value_length,
1443                ),
1444                chain_id,
1445            ),
1446        }
1447    }
1448}
1449
1450impl Deserializer<Vec<SecureShareOperation>> for OperationsDeserializer {
1451    /// ## Example:
1452    /// ```rust
1453    /// use massa_models::{operation::{SecureShareOperation, Operation, OperationType, OperationsSerializer, OperationsDeserializer, OperationSerializer}, secure_share::SecureShareContent, address::Address, amount::Amount};
1454    /// use massa_signature::KeyPair;
1455    /// use massa_serialization::{Serializer, Deserializer, DeserializeError};
1456    /// use std::str::FromStr;
1457    /// use massa_models::config::CHAINID;
1458    ///
1459    /// let keypair = KeyPair::generate(0).unwrap();
1460    /// let op = OperationType::Transaction {
1461    ///    recipient_address: Address::from_public_key(&keypair.get_public_key()),
1462    ///    amount: Amount::from_str("300").unwrap(),
1463    /// };
1464    /// let content = Operation {
1465    ///   fee: Amount::from_str("20").unwrap(),
1466    ///   op,
1467    ///   expire_period: 50,
1468    /// };
1469    /// let op_secured = Operation::new_verifiable(content, OperationSerializer::new(), &keypair, *CHAINID).unwrap();
1470    /// let operations = vec![op_secured.clone(), op_secured.clone()];
1471    /// let mut buffer = Vec::new();
1472    /// OperationsSerializer::new().serialize(&operations, &mut buffer).unwrap();
1473    /// let (rest, deserialized_operations) = OperationsDeserializer::new(10000, 10000, 10000, 10000, 10, 255, 10_000, *CHAINID).deserialize::<DeserializeError>(&buffer).unwrap();
1474    /// for (operation1, operation2) in deserialized_operations.iter().zip(operations.iter()) {
1475    ///     assert_eq!(operation1.id, operation2.id);
1476    ///     assert_eq!(operation1.signature, operation2.signature);
1477    ///     assert_eq!(operation1.content_creator_pub_key, operation2.content_creator_pub_key);
1478    ///     assert_eq!(operation1.content.fee, operation2.content.fee);
1479    /// }
1480    /// ```
1481    fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
1482        &self,
1483        buffer: &'a [u8],
1484    ) -> IResult<&'a [u8], Vec<SecureShareOperation>, E> {
1485        context(
1486            "Failed Operations deserialization",
1487            length_count(
1488                context("Failed length deserialization", |input| {
1489                    self.length_deserializer.deserialize(input)
1490                }),
1491                context("Failed operation deserialization", |input| {
1492                    self.signed_op_deserializer.deserialize(input)
1493                }),
1494            ),
1495        )
1496        .parse(buffer)
1497    }
1498}
1499
1500/// Compute the hash of a list of operations(used typically in block headers)
1501pub fn compute_operations_hash(
1502    op_ids: &[OperationId],
1503    op_id_serializer: &OperationIdSerializer,
1504) -> Hash {
1505    let op_ids = op_ids
1506        .iter()
1507        .map(|op_id| {
1508            let mut serialized = Vec::new();
1509            op_id_serializer
1510                .serialize(op_id, &mut serialized)
1511                .expect("serialization of operation id should not fail");
1512            serialized
1513        })
1514        .collect::<Vec<Vec<u8>>>();
1515    massa_hash::Hash::compute_from_tuple(
1516        &op_ids
1517            .iter()
1518            .map(|data| data.as_slice())
1519            .collect::<Vec<_>>(),
1520    )
1521}
1522
1523#[cfg(test)]
1524mod tests {
1525    use crate::config::{
1526        CHAINID, MAX_BYTECODE_LENGTH, MAX_FUNCTION_NAME_LENGTH,
1527        MAX_OPERATION_DATASTORE_ENTRY_COUNT, MAX_OPERATION_DATASTORE_KEY_LENGTH,
1528        MAX_OPERATION_DATASTORE_VALUE_LENGTH, MAX_PARAMETERS_SIZE,
1529    };
1530
1531    use super::*;
1532    use massa_serialization::DeserializeError;
1533    use massa_signature::KeyPair;
1534    use serde_json::Value;
1535    use serial_test::serial;
1536    use std::collections::BTreeMap;
1537
1538    #[test]
1539    #[serial]
1540    fn test_transaction_massa_docs() {
1541        // Serialize an operation with values found in massa docs
1542        // This print the values as reported here:
1543        // https://docs.massa.net/docs/learn/operation-format-execution#example-of-legal-operation-with-valid-signature
1544        // Warning: check if the current chain id matches the chain id in the doc
1545
1546        let chain_id: u64 = 77658383;
1547        let sk = "S1CkpvD4WMjJWxR2WZcrDEkJ1kWG2kKe1e3Afe8miqmskHqovvA";
1548        let pk = "P1t4JZwHhWNLt4xYabCbukyVNxSbhYPdF6wCYuRmDuHD784juxd";
1549        let _addr = "AU12m1gXHUGxBZsDF4veeWfYaRmpztBCieHhPBaqf3fcRF2LdAuZ7";
1550        let op_fee = "0.001";
1551        let op_expiry_period = 1000;
1552
1553        let tx_dest_addr = "AU12v83xmHg2UrLM8GLsXRMrm7LQgn3DZVT6kUeFsuFyhZKLkbQtY";
1554        let tx_amount = "3.1";
1555
1556        let op_type = OperationType::Transaction {
1557            recipient_address: Address::from_str(tx_dest_addr).unwrap(),
1558            amount: Amount::from_str(tx_amount).unwrap(),
1559        };
1560
1561        let content = Operation {
1562            fee: Amount::from_str(op_fee).unwrap(),
1563            op: op_type,
1564            expire_period: op_expiry_period,
1565        };
1566
1567        let op_serializer = OperationSerializer::new();
1568        let sender_keypair = KeyPair::from_str(sk).unwrap();
1569
1570        assert_eq!(
1571            sender_keypair.get_public_key(),
1572            PublicKey::from_str(pk).unwrap()
1573        );
1574
1575        let op: SecureShare<Operation, OperationId> =
1576            Operation::new_verifiable(content, op_serializer, &sender_keypair, chain_id).unwrap();
1577
1578        println!("Chain id: {}", *CHAINID);
1579        println!("Operation id: {:?}", op.id);
1580
1581        let mut ser_op = Vec::new();
1582        SecureShareSerializer::new()
1583            .serialize(&op, &mut ser_op)
1584            .unwrap();
1585
1586        println!("Operation serialized:");
1587        println!("{:02X?}", ser_op);
1588    }
1589
1590    #[test]
1591    #[serial]
1592    fn test_transaction() {
1593        let sender_keypair = KeyPair::generate(0).unwrap();
1594        let recv_keypair = KeyPair::generate(0).unwrap();
1595
1596        let op = OperationType::Transaction {
1597            recipient_address: Address::from_public_key(&recv_keypair.get_public_key()),
1598            amount: Amount::default(),
1599        };
1600        let mut ser_type = Vec::new();
1601        OperationTypeSerializer::new()
1602            .serialize(&op, &mut ser_type)
1603            .unwrap();
1604        let (_, res_type) = OperationTypeDeserializer::new(
1605            MAX_BYTECODE_LENGTH,
1606            MAX_FUNCTION_NAME_LENGTH,
1607            MAX_PARAMETERS_SIZE,
1608            MAX_OPERATION_DATASTORE_ENTRY_COUNT,
1609            MAX_OPERATION_DATASTORE_KEY_LENGTH,
1610            MAX_OPERATION_DATASTORE_VALUE_LENGTH,
1611        )
1612        .deserialize::<DeserializeError>(&ser_type)
1613        .unwrap();
1614
1615        assert_eq!(res_type, op);
1616
1617        let content = Operation {
1618            fee: Amount::from_str("20").unwrap(),
1619            op,
1620            expire_period: 50,
1621        };
1622
1623        let mut ser_content = Vec::new();
1624        OperationSerializer::new()
1625            .serialize(&content, &mut ser_content)
1626            .unwrap();
1627        let (_, res_content) = OperationDeserializer::new(
1628            MAX_BYTECODE_LENGTH,
1629            MAX_FUNCTION_NAME_LENGTH,
1630            MAX_PARAMETERS_SIZE,
1631            MAX_OPERATION_DATASTORE_ENTRY_COUNT,
1632            MAX_OPERATION_DATASTORE_KEY_LENGTH,
1633            MAX_OPERATION_DATASTORE_VALUE_LENGTH,
1634        )
1635        .deserialize::<DeserializeError>(&ser_content)
1636        .unwrap();
1637        assert_eq!(res_content, content);
1638
1639        let op_serializer = OperationSerializer::new();
1640
1641        let op =
1642            Operation::new_verifiable(content, op_serializer, &sender_keypair, *CHAINID).unwrap();
1643
1644        let mut ser_op = Vec::new();
1645        SecureShareSerializer::new()
1646            .serialize(&op, &mut ser_op)
1647            .unwrap();
1648        let (_, res_op): (&[u8], SecureShareOperation) = SecureShareDeserializer::new(
1649            OperationDeserializer::new(
1650                MAX_BYTECODE_LENGTH,
1651                MAX_FUNCTION_NAME_LENGTH,
1652                MAX_PARAMETERS_SIZE,
1653                MAX_OPERATION_DATASTORE_ENTRY_COUNT,
1654                MAX_OPERATION_DATASTORE_KEY_LENGTH,
1655                MAX_OPERATION_DATASTORE_VALUE_LENGTH,
1656            ),
1657            *CHAINID,
1658        )
1659        .deserialize::<DeserializeError>(&ser_op)
1660        .unwrap();
1661        assert_eq!(res_op, op);
1662
1663        assert_eq!(op.get_validity_range(10), 40..=50);
1664    }
1665
1666    #[test]
1667    #[serial]
1668    fn test_executesc() {
1669        let sender_keypair = KeyPair::generate(0).unwrap();
1670
1671        let op = OperationType::ExecuteSC {
1672            max_gas: 123,
1673            max_coins: Amount::from_str("1.0").unwrap(),
1674            data: vec![23u8, 123u8, 44u8],
1675            datastore: BTreeMap::from([
1676                (vec![1, 2, 3], vec![4, 5, 6, 7, 8, 9]),
1677                (vec![22, 33, 44, 55, 66, 77], vec![11]),
1678            ]),
1679        };
1680        let mut ser_type = Vec::new();
1681        OperationTypeSerializer::new()
1682            .serialize(&op, &mut ser_type)
1683            .unwrap();
1684        let (_, res_type) = OperationTypeDeserializer::new(
1685            MAX_BYTECODE_LENGTH,
1686            MAX_FUNCTION_NAME_LENGTH,
1687            MAX_PARAMETERS_SIZE,
1688            MAX_OPERATION_DATASTORE_ENTRY_COUNT,
1689            MAX_OPERATION_DATASTORE_KEY_LENGTH,
1690            MAX_OPERATION_DATASTORE_VALUE_LENGTH,
1691        )
1692        .deserialize::<DeserializeError>(&ser_type)
1693        .unwrap();
1694        assert_eq!(res_type, op);
1695
1696        let content = Operation {
1697            fee: Amount::from_str("20").unwrap(),
1698            op,
1699            expire_period: 50,
1700        };
1701
1702        let mut ser_content = Vec::new();
1703        OperationSerializer::new()
1704            .serialize(&content, &mut ser_content)
1705            .unwrap();
1706        let (_, res_content) = OperationDeserializer::new(
1707            MAX_BYTECODE_LENGTH,
1708            MAX_FUNCTION_NAME_LENGTH,
1709            MAX_PARAMETERS_SIZE,
1710            MAX_OPERATION_DATASTORE_ENTRY_COUNT,
1711            MAX_OPERATION_DATASTORE_KEY_LENGTH,
1712            MAX_OPERATION_DATASTORE_VALUE_LENGTH,
1713        )
1714        .deserialize::<DeserializeError>(&ser_content)
1715        .unwrap();
1716        assert_eq!(res_content, content);
1717        let op_serializer = OperationSerializer::new();
1718
1719        let op =
1720            Operation::new_verifiable(content, op_serializer, &sender_keypair, *CHAINID).unwrap();
1721
1722        let mut ser_op = Vec::new();
1723        SecureShareSerializer::new()
1724            .serialize(&op, &mut ser_op)
1725            .unwrap();
1726        let (_, res_op): (&[u8], SecureShareOperation) = SecureShareDeserializer::new(
1727            OperationDeserializer::new(
1728                MAX_BYTECODE_LENGTH,
1729                MAX_FUNCTION_NAME_LENGTH,
1730                MAX_PARAMETERS_SIZE,
1731                MAX_OPERATION_DATASTORE_ENTRY_COUNT,
1732                MAX_OPERATION_DATASTORE_KEY_LENGTH,
1733                MAX_OPERATION_DATASTORE_VALUE_LENGTH,
1734            ),
1735            *CHAINID,
1736        )
1737        .deserialize::<DeserializeError>(&ser_op)
1738        .unwrap();
1739        assert_eq!(res_op, op);
1740
1741        assert_eq!(op.get_validity_range(10), 40..=50);
1742    }
1743
1744    #[test]
1745    #[serial]
1746    fn test_callsc() {
1747        let sender_keypair = KeyPair::generate(0).unwrap();
1748
1749        let target_keypair = KeyPair::generate(0).unwrap();
1750        let target_addr = Address::from_public_key(&target_keypair.get_public_key());
1751
1752        let op = OperationType::CallSC {
1753            max_gas: 123,
1754            target_addr,
1755            coins: Amount::from_str("456.789").unwrap(),
1756            target_func: "target function".to_string(),
1757            param: b"parameter".to_vec(),
1758        };
1759        let mut ser_type = Vec::new();
1760        OperationTypeSerializer::new()
1761            .serialize(&op, &mut ser_type)
1762            .unwrap();
1763        let (_, res_type) = OperationTypeDeserializer::new(
1764            MAX_BYTECODE_LENGTH,
1765            MAX_FUNCTION_NAME_LENGTH,
1766            MAX_PARAMETERS_SIZE,
1767            MAX_OPERATION_DATASTORE_ENTRY_COUNT,
1768            MAX_OPERATION_DATASTORE_KEY_LENGTH,
1769            MAX_OPERATION_DATASTORE_VALUE_LENGTH,
1770        )
1771        .deserialize::<DeserializeError>(&ser_type)
1772        .unwrap();
1773        assert_eq!(res_type, op);
1774
1775        let content = Operation {
1776            fee: Amount::from_str("20").unwrap(),
1777            op,
1778            expire_period: 50,
1779        };
1780
1781        let mut ser_content = Vec::new();
1782        OperationSerializer::new()
1783            .serialize(&content, &mut ser_content)
1784            .unwrap();
1785        let (_, res_content) = OperationDeserializer::new(
1786            MAX_BYTECODE_LENGTH,
1787            MAX_FUNCTION_NAME_LENGTH,
1788            MAX_PARAMETERS_SIZE,
1789            MAX_OPERATION_DATASTORE_ENTRY_COUNT,
1790            MAX_OPERATION_DATASTORE_KEY_LENGTH,
1791            MAX_OPERATION_DATASTORE_VALUE_LENGTH,
1792        )
1793        .deserialize::<DeserializeError>(&ser_content)
1794        .unwrap();
1795        assert_eq!(res_content, content);
1796        let op_serializer = OperationSerializer::new();
1797
1798        let op =
1799            Operation::new_verifiable(content, op_serializer, &sender_keypair, *CHAINID).unwrap();
1800
1801        let mut ser_op = Vec::new();
1802        SecureShareSerializer::new()
1803            .serialize(&op, &mut ser_op)
1804            .unwrap();
1805        let (_, res_op): (&[u8], SecureShareOperation) = SecureShareDeserializer::new(
1806            OperationDeserializer::new(
1807                MAX_BYTECODE_LENGTH,
1808                MAX_FUNCTION_NAME_LENGTH,
1809                MAX_PARAMETERS_SIZE,
1810                MAX_OPERATION_DATASTORE_ENTRY_COUNT,
1811                MAX_OPERATION_DATASTORE_KEY_LENGTH,
1812                MAX_OPERATION_DATASTORE_VALUE_LENGTH,
1813            ),
1814            *CHAINID,
1815        )
1816        .deserialize::<DeserializeError>(&ser_op)
1817        .unwrap();
1818        assert_eq!(res_op, op);
1819
1820        assert_eq!(op.get_validity_range(10), 40..=50);
1821    }
1822
1823    #[test]
1824    #[serial]
1825    fn test_transaction_serde() {
1826        let recv_keypair = KeyPair::generate(0).unwrap();
1827
1828        let op: OperationType = OperationType::Transaction {
1829            recipient_address: Address::from_public_key(&recv_keypair.get_public_key()),
1830            amount: Amount::default(),
1831        };
1832        let mut ser_type = Vec::new();
1833        OperationTypeSerializer::new()
1834            .serialize(&op, &mut ser_type)
1835            .unwrap();
1836        let (_, res_type) = OperationTypeDeserializer::new(
1837            MAX_BYTECODE_LENGTH,
1838            MAX_FUNCTION_NAME_LENGTH,
1839            MAX_PARAMETERS_SIZE,
1840            MAX_OPERATION_DATASTORE_ENTRY_COUNT,
1841            MAX_OPERATION_DATASTORE_KEY_LENGTH,
1842            MAX_OPERATION_DATASTORE_VALUE_LENGTH,
1843        )
1844        .deserialize::<DeserializeError>(&ser_type)
1845        .unwrap();
1846
1847        assert_eq!(res_type, op);
1848
1849        let orig_operation = Operation {
1850            fee: Amount::from_str("20").unwrap(),
1851            op,
1852            expire_period: 50,
1853        };
1854
1855        let serialized_operation = serde_json::to_string(&orig_operation).unwrap();
1856        let res_operation: Value = serde_json::from_str(&serialized_operation).unwrap();
1857        // check equality
1858        assert_eq!(orig_operation.fee.to_string(), res_operation["fee"]);
1859        assert_eq!(orig_operation.expire_period, res_operation["expire_period"]);
1860    }
1861
1862    #[test]
1863    #[serial]
1864    fn test_executesc_serde() {
1865        let op = OperationType::ExecuteSC {
1866            max_gas: 123,
1867            max_coins: Amount::from_str("1.0").unwrap(),
1868            data: vec![23u8, 123u8, 44u8],
1869            datastore: BTreeMap::from([
1870                (vec![1, 2, 3], vec![4, 5, 6, 7, 8, 9]),
1871                (vec![22, 33, 44, 55, 66, 77], vec![11]),
1872            ]),
1873        };
1874        let mut ser_type = Vec::new();
1875        OperationTypeSerializer::new()
1876            .serialize(&op, &mut ser_type)
1877            .unwrap();
1878        let (_, res_type) = OperationTypeDeserializer::new(
1879            MAX_BYTECODE_LENGTH,
1880            MAX_FUNCTION_NAME_LENGTH,
1881            MAX_PARAMETERS_SIZE,
1882            MAX_OPERATION_DATASTORE_ENTRY_COUNT,
1883            MAX_OPERATION_DATASTORE_KEY_LENGTH,
1884            MAX_OPERATION_DATASTORE_VALUE_LENGTH,
1885        )
1886        .deserialize::<DeserializeError>(&ser_type)
1887        .unwrap();
1888        assert_eq!(res_type, op);
1889
1890        let orig_operation = Operation {
1891            fee: Amount::from_str("20").unwrap(),
1892            op,
1893            expire_period: 50,
1894        };
1895
1896        let serialized_operation = serde_json::to_string(&orig_operation).unwrap();
1897        let res_operation: Value = serde_json::from_str(&serialized_operation).unwrap();
1898        // check equality
1899        assert_eq!(orig_operation.fee.to_string(), res_operation["fee"]);
1900        assert_eq!(orig_operation.expire_period, res_operation["expire_period"]);
1901    }
1902
1903    #[test]
1904    #[serial]
1905    fn test_callsc_serde() {
1906        let target_keypair = KeyPair::generate(0).unwrap();
1907        let target_addr = Address::from_public_key(&target_keypair.get_public_key());
1908
1909        let op = OperationType::CallSC {
1910            max_gas: 123,
1911            target_addr,
1912            coins: Amount::from_str("456.789").unwrap(),
1913            target_func: "target function".to_string(),
1914            param: b"parameter".to_vec(),
1915        };
1916        let mut ser_type = Vec::new();
1917        OperationTypeSerializer::new()
1918            .serialize(&op, &mut ser_type)
1919            .unwrap();
1920        let (_, res_type) = OperationTypeDeserializer::new(
1921            MAX_BYTECODE_LENGTH,
1922            MAX_FUNCTION_NAME_LENGTH,
1923            MAX_PARAMETERS_SIZE,
1924            MAX_OPERATION_DATASTORE_ENTRY_COUNT,
1925            MAX_OPERATION_DATASTORE_KEY_LENGTH,
1926            MAX_OPERATION_DATASTORE_VALUE_LENGTH,
1927        )
1928        .deserialize::<DeserializeError>(&ser_type)
1929        .unwrap();
1930        assert_eq!(res_type, op);
1931
1932        let orig_operation = Operation {
1933            fee: Amount::from_str("20").unwrap(),
1934            op,
1935            expire_period: 50,
1936        };
1937
1938        let serialized_operation = serde_json::to_string(&orig_operation).unwrap();
1939        let res_operation: Value = serde_json::from_str(&serialized_operation).unwrap();
1940        // check equality
1941        assert_eq!(orig_operation.fee.to_string(), res_operation["fee"]);
1942        assert_eq!(orig_operation.expire_period, res_operation["expire_period"]);
1943    }
1944}