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}