massa_ledger_exports/
ledger_entry.rs

1// Copyright (c) 2022 MASSA LABS <info@massa.net>
2
3//! This file defines the structure representing an entry in the `FinalLedger`
4
5use crate::ledger_changes::LedgerEntryUpdate;
6use massa_models::amount::{Amount, AmountDeserializer, AmountSerializer};
7use massa_models::bytecode::{Bytecode, BytecodeDeserializer, BytecodeSerializer};
8use massa_models::datastore::{Datastore, DatastoreDeserializer, DatastoreSerializer};
9use massa_models::types::{Applicable, SetOrDelete};
10use massa_serialization::{Deserializer, SerializeError, Serializer};
11use nom::error::{context, ContextError, ParseError};
12use nom::sequence::tuple;
13use nom::{IResult, Parser};
14use serde::{Deserialize, Serialize};
15use serde_with::serde_as;
16use std::ops::Bound::Included;
17
18/// Structure defining an entry associated to an address in the `FinalLedger`
19#[serde_as]
20#[derive(Default, Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
21pub struct LedgerEntry {
22    /// The balance of that entry.
23    pub balance: Amount,
24
25    /// Executable bytecode
26    pub bytecode: Bytecode,
27
28    /// A key-value store associating a hash to arbitrary bytes
29    #[serde_as(as = "Vec<(_, _)>")]
30    pub datastore: Datastore,
31}
32
33/// Serializer for `LedgerEntry`
34pub struct LedgerEntrySerializer {
35    amount_serializer: AmountSerializer,
36    bytecode_serializer: BytecodeSerializer,
37    datastore_serializer: DatastoreSerializer,
38}
39
40impl LedgerEntrySerializer {
41    /// Creates a new `LedgerEntrySerializer`
42    pub fn new() -> Self {
43        Self {
44            amount_serializer: AmountSerializer::new(),
45            bytecode_serializer: BytecodeSerializer::new(),
46            datastore_serializer: DatastoreSerializer::new(),
47        }
48    }
49}
50
51impl Default for LedgerEntrySerializer {
52    fn default() -> Self {
53        Self::new()
54    }
55}
56
57impl Serializer<LedgerEntry> for LedgerEntrySerializer {
58    /// ## Example
59    /// ```
60    /// use massa_serialization::Serializer;
61    /// use std::collections::BTreeMap;
62    /// use std::str::FromStr;
63    /// use massa_models::{amount::Amount, bytecode::Bytecode};
64    /// use massa_ledger_exports::{LedgerEntry, LedgerEntrySerializer};
65    ///
66    /// let key = "hello world".as_bytes().to_vec();
67    /// let mut datastore = BTreeMap::new();
68    /// datastore.insert(key, vec![1, 2, 3]);
69    /// let balance = Amount::from_str("1").unwrap();
70    /// let bytecode = Bytecode(vec![1, 2, 3]);
71    /// let ledger_entry = LedgerEntry {
72    ///    balance,
73    ///    bytecode,
74    ///    datastore,
75    /// };
76    /// let mut serialized = Vec::new();
77    /// let serializer = LedgerEntrySerializer::new();
78    /// serializer.serialize(&ledger_entry, &mut serialized).unwrap();
79    /// ```
80    fn serialize(&self, value: &LedgerEntry, buffer: &mut Vec<u8>) -> Result<(), SerializeError> {
81        self.amount_serializer.serialize(&value.balance, buffer)?;
82        self.bytecode_serializer
83            .serialize(&value.bytecode, buffer)?;
84        self.datastore_serializer
85            .serialize(&value.datastore, buffer)?;
86        Ok(())
87    }
88}
89
90/// Deserializer for `LedgerEntry`
91pub struct LedgerEntryDeserializer {
92    pub amount_deserializer: AmountDeserializer,
93    bytecode_deserializer: BytecodeDeserializer,
94    datastore_deserializer: DatastoreDeserializer,
95}
96
97impl LedgerEntryDeserializer {
98    /// Creates a new `LedgerEntryDeserializer`
99    pub fn new(
100        max_datastore_entry_count: u64,
101        max_datastore_key_length: u8,
102        max_datastore_value_length: u64,
103        max_bytecode_size: u64,
104    ) -> Self {
105        Self {
106            amount_deserializer: AmountDeserializer::new(
107                Included(Amount::MIN),
108                Included(Amount::MAX),
109            ),
110            bytecode_deserializer: BytecodeDeserializer::new(max_bytecode_size),
111            datastore_deserializer: DatastoreDeserializer::new(
112                max_datastore_entry_count,
113                max_datastore_key_length,
114                max_datastore_value_length,
115            ),
116        }
117    }
118}
119
120impl Deserializer<LedgerEntry> for LedgerEntryDeserializer {
121    /// ## Example
122    /// ```
123    /// use massa_serialization::{Deserializer, Serializer, DeserializeError};
124    /// use std::collections::BTreeMap;
125    /// use std::str::FromStr;
126    /// use massa_models::{amount::Amount, bytecode::Bytecode};
127    /// use massa_ledger_exports::{LedgerEntry, LedgerEntrySerializer, LedgerEntryDeserializer};
128    ///
129    /// let key = "hello world".as_bytes().to_vec();
130    /// let mut datastore = BTreeMap::new();
131    /// datastore.insert(key, vec![1, 2, 3]);
132    /// let balance = Amount::from_str("1").unwrap();
133    /// let bytecode = Bytecode(vec![1, 2, 3]);
134    /// let ledger_entry = LedgerEntry {
135    ///    balance,
136    ///    bytecode,
137    ///    datastore,
138    /// };
139    /// let mut serialized = Vec::new();
140    /// let serializer = LedgerEntrySerializer::new();
141    /// let deserializer = LedgerEntryDeserializer::new(10000, 255, 10000, 10000);
142    /// serializer.serialize(&ledger_entry, &mut serialized).unwrap();
143    /// let (rest, ledger_entry_deser) = deserializer.deserialize::<DeserializeError>(&serialized).unwrap();
144    /// assert!(rest.is_empty());
145    /// assert_eq!(ledger_entry, ledger_entry_deser);
146    /// ```
147    fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
148        &self,
149        buffer: &'a [u8],
150    ) -> IResult<&'a [u8], LedgerEntry, E> {
151        context(
152            "Failed LedgerEntry deserialization",
153            tuple((
154                context("Failed balance deserialization", |input| {
155                    self.amount_deserializer.deserialize(input)
156                }),
157                context("Failed bytecode deserialization", |input| {
158                    self.bytecode_deserializer.deserialize(input)
159                }),
160                context("Failed datastore deserialization", |input| {
161                    self.datastore_deserializer.deserialize(input)
162                }),
163            )),
164        )
165        .map(|(balance, bytecode, datastore)| LedgerEntry {
166            balance,
167            bytecode,
168            datastore,
169        })
170        .parse(buffer)
171    }
172}
173
174/// A `LedgerEntryUpdate` can be applied to a `LedgerEntry`
175impl Applicable<LedgerEntryUpdate> for LedgerEntry {
176    fn apply(&mut self, update: LedgerEntryUpdate) {
177        // apply updates to the balance
178        update.balance.apply_to(&mut self.balance);
179
180        // apply updates to the executable bytecode
181        update.bytecode.apply_to(&mut self.bytecode);
182
183        // iterate over all datastore updates
184        for (key, value_update) in update.datastore {
185            match value_update {
186                // this update sets a new value to a datastore entry
187                SetOrDelete::Set(v) => {
188                    // insert the new value in the datastore,
189                    // replacing any existing value
190                    self.datastore.insert(key, v);
191                }
192
193                // this update deletes a datastore entry
194                SetOrDelete::Delete => {
195                    // remove that entry from the datastore if it exists
196                    self.datastore.remove(&key);
197                }
198            }
199        }
200    }
201}