/ console / program / src / data / record / parse_plaintext.rs
parse_plaintext.rs
  1  // Copyright (c) 2025-2026 ACDC Network
  2  // This file is part of the alphavm library.
  3  //
  4  // Alpha Chain | Delta Chain Protocol
  5  // International Monetary Graphite.
  6  //
  7  // Derived from Aleo (https://aleo.org) and ProvableHQ (https://provable.com).
  8  // They built world-class ZK infrastructure. We installed the EASY button.
  9  // Their cryptography: elegant. Our modifications: bureaucracy-compatible.
 10  // Original brilliance: theirs. Robert's Rules: ours. Bugs: definitely ours.
 11  //
 12  // Original Aleo/ProvableHQ code subject to Apache 2.0 https://www.apache.org/licenses/LICENSE-2.0
 13  // All modifications and new work: CC0 1.0 Universal Public Domain Dedication.
 14  // No rights reserved. No permission required. No warranty. No refunds.
 15  //
 16  // https://creativecommons.org/publicdomain/zero/1.0/
 17  // SPDX-License-Identifier: CC0-1.0
 18  
 19  use super::*;
 20  
 21  impl<N: Network> Parser for Record<N, Plaintext<N>> {
 22      /// Parses a string as a record: `{ owner: address, identifier_0: entry_0, ..., identifier_n: entry_n, _nonce: field, _version: u8 }`.
 23      #[inline]
 24      fn parse(string: &str) -> ParserResult<'_, Self> {
 25          /// Parses a sanitized pair: `identifier: entry`.
 26          #[allow(clippy::type_complexity)]
 27          fn parse_pair<N: Network>(string: &str) -> ParserResult<'_, (Identifier<N>, Entry<N, Plaintext<N>>)> {
 28              // Parse the whitespace and comments from the string.
 29              let (string, _) = Sanitizer::parse(string)?;
 30              // Parse the identifier from the string.
 31              let (string, identifier) = Identifier::parse(string)?;
 32              // Parse the whitespace from the string.
 33              let (string, _) = Sanitizer::parse_whitespaces(string)?;
 34              // Parse the ":" from the string.
 35              let (string, _) = tag(":")(string)?;
 36              // Parse the whitespace and comments from the string.
 37              let (string, _) = Sanitizer::parse(string)?;
 38              // Parse the entry from the string.
 39              let (string, entry) = Entry::parse(string)?;
 40              // Parse the whitespace from the string.
 41              let (string, _) = Sanitizer::parse_whitespaces(string)?;
 42              // Return the identifier and entry.
 43              Ok((string, (identifier, entry)))
 44          }
 45  
 46          // Parse the whitespace and comments from the string.
 47          let (string, _) = Sanitizer::parse(string)?;
 48          // Parse the "{" from the string.
 49          let (string, _) = tag("{")(string)?;
 50  
 51          // Parse the whitespace and comments from the string.
 52          let (string, _) = Sanitizer::parse(string)?;
 53          // Parse the "owner" tag from the string.
 54          let (string, _) = tag("owner")(string)?;
 55          // Parse the whitespace from the string.
 56          let (string, _) = Sanitizer::parse_whitespaces(string)?;
 57          // Parse the ":" from the string.
 58          let (string, _) = tag(":")(string)?;
 59          // Parse the whitespace and comments from the string.
 60          let (string, _) = Sanitizer::parse(string)?;
 61          // Parse the owner from the string.
 62          let (string, owner) = alt((
 63              map(pair(Address::parse, tag(".public")), |(owner, _)| Owner::Public(owner)),
 64              map(pair(Address::parse, tag(".private")), |(owner, _)| {
 65                  Owner::Private(Plaintext::from(Literal::Address(owner)))
 66              }),
 67          ))(string)?;
 68          // Parse the "," from the string.
 69          let (string, _) = tag(",")(string)?;
 70  
 71          // Parse the entries.
 72          let (string, entries) = map_res(separated_list0(tag(","), parse_pair), |entries: Vec<_>| {
 73              // Prepare the reserved entry names.
 74              let reserved = [Identifier::from_str("owner").map_err(|e| error(e.to_string()))?];
 75              // Ensure the entries has no duplicate names.
 76              if has_duplicates(entries.iter().map(|(identifier, _)| identifier).chain(reserved.iter())) {
 77                  return Err(error("Duplicate entry type found in record"));
 78              }
 79              // Ensure the number of entries is within the maximum limit.
 80              match entries.len() <= N::MAX_DATA_ENTRIES {
 81                  true => Ok(entries),
 82                  false => Err(error(format!("Found a record that exceeds size ({})", entries.len()))),
 83              }
 84          })(string)?;
 85  
 86          // If there are entries, then parse the "," from the string.
 87          let string = match !entries.is_empty() {
 88              // Parse the "," from the string.
 89              true => tag(",")(string)?.0,
 90              false => string,
 91          };
 92  
 93          // Parse the whitespace and comments from the string.
 94          let (string, _) = Sanitizer::parse(string)?;
 95          // Parse the "_nonce" tag from the string.
 96          let (string, _) = tag("_nonce")(string)?;
 97          // Parse the ":" from the string.
 98          let (string, _) = tag(":")(string)?;
 99          // Parse the whitespace and comments from the string.
100          let (string, _) = Sanitizer::parse(string)?;
101          // Parse the nonce from the string.
102          let (string, (nonce, _)) = pair(Group::parse, tag(".public"))(string)?;
103  
104          // There may be an optional "_version" tag. Parse the "," from the string if it exists.
105          let string = match opt(tag(","))(string)? {
106              // If there is a version, then parse the "," from the string.
107              (string, Some(_)) => string,
108              // If there is no version, then keep the string as is.
109              (string, None) => string,
110          };
111  
112          // Parse the whitespace and comments from the string.
113          let (string, _) = Sanitizer::parse(string)?;
114          // Parse the optional "_version" tag from the string.
115          let (string, version) = match opt(tag("_version"))(string)? {
116              // If there is no version, then set the version to zero.
117              (string, None) => (string, U8::zero()),
118              // If there is a version, then parse the version from the string.
119              (string, Some(_)) => {
120                  // Parse the whitespace and comments from the string.
121                  let (string, _) = Sanitizer::parse(string)?;
122                  // Parse the ":" from the string.
123                  let (string, _) = tag(":")(string)?;
124                  // Parse the whitespace and comments from the string.
125                  let (string, _) = Sanitizer::parse(string)?;
126                  // Parse the version from the string.
127                  terminated(U8::parse, tag(".public"))(string)?
128              }
129          };
130  
131          // Parse the whitespace and comments from the string.
132          let (string, _) = Sanitizer::parse(string)?;
133          // Parse the '}' from the string.
134          let (string, _) = tag("}")(string)?;
135          // Output the record.
136          Ok((string, Record { owner, data: IndexMap::from_iter(entries), nonce, version }))
137      }
138  }
139  
140  impl<N: Network> FromStr for Record<N, Plaintext<N>> {
141      type Err = Error;
142  
143      /// Returns a record from a string literal.
144      fn from_str(string: &str) -> Result<Self> {
145          match Self::parse(string) {
146              Ok((remainder, object)) => {
147                  // Ensure the remainder is empty.
148                  ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
149                  // Return the object.
150                  Ok(object)
151              }
152              Err(error) => bail!("Failed to parse string. {error}"),
153          }
154      }
155  }
156  
157  impl<N: Network> Debug for Record<N, Plaintext<N>> {
158      /// Prints the record as a string.
159      fn fmt(&self, f: &mut Formatter) -> fmt::Result {
160          Display::fmt(self, f)
161      }
162  }
163  
164  impl<N: Network> Display for Record<N, Plaintext<N>> {
165      /// Prints the record as a string.
166      fn fmt(&self, f: &mut Formatter) -> fmt::Result {
167          self.fmt_internal(f, 0)
168      }
169  }
170  
171  impl<N: Network> Record<N, Plaintext<N>> {
172      /// Prints the record with the given indentation depth.
173      fn fmt_internal(&self, f: &mut Formatter, depth: usize) -> fmt::Result {
174          /// The number of spaces to indent.
175          const INDENT: usize = 2;
176  
177          // Print the opening brace.
178          write!(f, "{{")?;
179          // Print the owner with a comma.
180          write!(f, "\n{:indent$}owner: {},", "", self.owner, indent = (depth + 1) * INDENT)?;
181          // Print the data with a comma.
182          for (identifier, entry) in self.data.iter() {
183              // Print the identifier.
184              write!(f, "\n{:indent$}{identifier}: ", "", indent = (depth + 1) * INDENT)?;
185              // Print the entry.
186              match entry {
187                  // If the entry is a literal, print the entry without indentation.
188                  Entry::Constant(Plaintext::Literal(..))
189                  | Entry::Public(Plaintext::Literal(..))
190                  | Entry::Private(Plaintext::Literal(..)) => write!(f, "{entry}")?,
191                  // If the entry is a struct or an array, print the entry with indentation.
192                  Entry::Constant(Plaintext::Struct(..))
193                  | Entry::Public(Plaintext::Struct(..))
194                  | Entry::Private(Plaintext::Struct(..))
195                  | Entry::Constant(Plaintext::Array(..))
196                  | Entry::Public(Plaintext::Array(..))
197                  | Entry::Private(Plaintext::Array(..)) => entry.fmt_internal(f, depth + 1)?,
198              }
199              // Print the comma.
200              write!(f, ",")?;
201          }
202          // Print the nonce with a comma.
203          write!(f, "\n{:indent$}_nonce: {}.public,", "", self.nonce, indent = (depth + 1) * INDENT)?;
204          // Print the version without a comma.
205          write!(f, "\n{:indent$}_version: {}.public", "", self.version, indent = (depth + 1) * INDENT)?;
206          // Print the closing brace.
207          write!(f, "\n{:indent$}}}", "", indent = depth * INDENT)
208      }
209  }
210  
211  #[cfg(test)]
212  mod tests {
213      use super::*;
214      use alphavm_console_network::MainnetV0;
215  
216      type CurrentNetwork = MainnetV0;
217  
218      #[test]
219      fn test_parse_without_version() -> Result<()> {
220          // Sanity check.
221          let expected = r"{
222    owner: ax150w2lvhdzychwvzu54ys5zas7tm5s0ycdyw563pms83g9u0vucgqe5fs5w.private,
223    _nonce: 0group.public,
224    _version: 0u8.public
225  }";
226          let given =
227              "{ owner: ax150w2lvhdzychwvzu54ys5zas7tm5s0ycdyw563pms83g9u0vucgqe5fs5w.private, _nonce: 0group.public }";
228          let (remainder, candidate) = Record::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse(given)?;
229          println!("\nExpected: {expected}\n\nFound: {candidate}\n");
230          assert_eq!(expected, candidate.to_string());
231          assert_eq!("", remainder);
232          Ok(())
233      }
234  
235      #[test]
236      fn test_parse_with_version() -> Result<()> {
237          // Sanity check.
238          let expected = r"{
239    owner: ax150w2lvhdzychwvzu54ys5zas7tm5s0ycdyw563pms83g9u0vucgqe5fs5w.private,
240    _nonce: 0group.public,
241    _version: 0u8.public
242  }";
243          let given = "{ owner: ax150w2lvhdzychwvzu54ys5zas7tm5s0ycdyw563pms83g9u0vucgqe5fs5w.private, _nonce: 0group.public, _version: 0u8.public }";
244          let (remainder, candidate) = Record::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse(given)?;
245          println!("\nExpected: {expected}\n\nFound: {candidate}\n");
246          assert_eq!(expected, candidate.to_string());
247          assert_eq!("", remainder);
248  
249          // Sanity check.
250          let expected = r"{
251    owner: ax150w2lvhdzychwvzu54ys5zas7tm5s0ycdyw563pms83g9u0vucgqe5fs5w.private,
252    _nonce: 0group.public,
253    _version: 1u8.public
254  }";
255          let given = "{ owner: ax150w2lvhdzychwvzu54ys5zas7tm5s0ycdyw563pms83g9u0vucgqe5fs5w.private, _nonce: 0group.public, _version: 1u8.public }";
256          let (remainder, candidate) = Record::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse(given)?;
257          println!("\nExpected: {expected}\n\nFound: {candidate}\n");
258          assert_eq!(expected, candidate.to_string());
259          assert_eq!("", remainder);
260          Ok(())
261      }
262  
263      #[test]
264      fn test_parse_without_data_entries() -> Result<()> {
265          // Sanity check.
266          let expected = r"{
267    owner: ax150w2lvhdzychwvzu54ys5zas7tm5s0ycdyw563pms83g9u0vucgqe5fs5w.private,
268    _nonce: 0group.public,
269    _version: 0u8.public
270  }";
271          let given =
272              "{ owner: ax150w2lvhdzychwvzu54ys5zas7tm5s0ycdyw563pms83g9u0vucgqe5fs5w.private, _nonce: 0group.public }";
273          let (remainder, candidate) = Record::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse(given)?;
274          println!("\nExpected: {expected}\n\nFound: {candidate}\n");
275          assert_eq!(expected, candidate.to_string());
276          assert_eq!("", remainder);
277          Ok(())
278      }
279  
280      #[test]
281      fn test_parse_with_literal_entry() -> Result<()> {
282          let expected = r"{
283    owner: ax150w2lvhdzychwvzu54ys5zas7tm5s0ycdyw563pms83g9u0vucgqe5fs5w.public,
284    foo: 5u8.constant,
285    _nonce: 0group.public,
286    _version: 0u8.public
287  }";
288          let given = "{ owner: ax150w2lvhdzychwvzu54ys5zas7tm5s0ycdyw563pms83g9u0vucgqe5fs5w.public, foo: 5u8.constant, _nonce: 0group.public }";
289          let (remainder, candidate) = Record::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse(given)?;
290          println!("\nExpected: {expected}\n\nFound: {candidate}\n");
291          assert_eq!(expected, candidate.to_string());
292          assert_eq!("", remainder);
293          Ok(())
294      }
295  
296      #[test]
297      fn test_parse_with_struct_entry() -> Result<()> {
298          let expected = r"{
299    owner: ax150w2lvhdzychwvzu54ys5zas7tm5s0ycdyw563pms83g9u0vucgqe5fs5w.public,
300    foo: 5u8.public,
301    bar: {
302      baz: 6u8.constant,
303      qux: 7u8.constant
304    },
305    quux: 8u8.private,
306    corge: {
307      grault: 9u8.constant,
308      garply: {
309        waldo: 10u8.constant,
310        fred: 11u8.constant
311      }
312    },
313    xyzzy: {
314      thud: 12u8.public
315    },
316    _nonce: 2293253577170800572742339369209137467208538700597121244293392265726446806023group.public,
317    _version: 0u8.public
318  }";
319          let (remainder, candidate) = Record::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse(expected)?;
320          println!("\nExpected: {expected}\n\nFound: {candidate}\n");
321          assert_eq!(expected, candidate.to_string());
322          assert_eq!("", remainder);
323  
324          let expected = r"{
325    owner: ax150w2lvhdzychwvzu54ys5zas7tm5s0ycdyw563pms83g9u0vucgqe5fs5w.private,
326    foo: {
327      bar: 0u128.private
328    },
329    baz: {
330      quine: {
331        flop: 0u64.private
332      },
333      slice: 0u16.private,
334      flag: true.private,
335      square: {
336        first: 0u128.private,
337        second: 1u128.private,
338        third: 2u128.private,
339        fourth: 3u128.private
340      }
341    },
342    _nonce: 0group.public,
343    _version: 0u8.public
344  }";
345          let (remainder, candidate) = Record::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse(expected)?;
346          println!("\nExpected: {expected}\n\nFound: {candidate}\n");
347          assert_eq!(expected, candidate.to_string());
348          assert_eq!("", remainder);
349  
350          let expected = r"{
351    owner: ax150w2lvhdzychwvzu54ys5zas7tm5s0ycdyw563pms83g9u0vucgqe5fs5w.private,
352    c: {
353      c: {
354        a: 0u8.private,
355        b: 1u8.private
356      },
357      d: {
358        a: 0u8.private,
359        b: 1u8.private
360      }
361    },
362    d: {
363      c: {
364        a: 0u8.private,
365        b: 1u8.private
366      },
367      d: {
368        a: 0u8.private,
369        b: 1u8.private
370      }
371    },
372    _nonce: 8102307625287186026775464343238779600702564007094834161216556016558567413871group.public,
373    _version: 0u8.public
374  }";
375          let (remainder, candidate) = Record::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse(expected)?;
376          println!("\nExpected: {expected}\n\nFound: {candidate}\n");
377          assert_eq!(expected, candidate.to_string());
378          assert_eq!("", remainder);
379  
380          Ok(())
381      }
382  
383      #[test]
384      fn test_parse_with_array_entry() -> Result<()> {
385          let expected = r"{
386    owner: ax150w2lvhdzychwvzu54ys5zas7tm5s0ycdyw563pms83g9u0vucgqe5fs5w.public,
387    foo: 5u8.public,
388    bar: [
389      6u8.private,
390      7u8.private,
391      8u8.private
392    ],
393    _nonce: 0group.public,
394    _version: 0u8.public
395  }";
396          let (remainder, candidate) = Record::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse(expected)?;
397          println!("\nExpected: {expected}\n\nFound: {candidate}\n");
398          assert_eq!(expected, candidate.to_string());
399          assert_eq!("", remainder);
400          Ok(())
401      }
402  
403      #[test]
404      fn test_parse_fails() -> Result<()> {
405          // Missing owner.
406          let expected = "{ foo: 5u8.private, _nonce: 0group.public }";
407          assert!(Plaintext::<CurrentNetwork>::parse(expected).is_err());
408  
409          // Missing nonce.
410          let expected =
411              "{ owner: ax150w2lvhdzychwvzu54ys5zas7tm5s0ycdyw563pms83g9u0vucgqe5fs5w.public, foo: 5u8.private }";
412          assert!(Plaintext::<CurrentNetwork>::parse(expected).is_err());
413  
414          // Entry 'd' contains members with different visibility.
415          let expected = r"{
416      owner: ax150w2lvhdzychwvzu54ys5zas7tm5s0ycdyw563pms83g9u0vucgqe5fs5w.private,
417      a: true.private,
418      b: 123456789field.private,
419      c: 0group.private,
420      d: {
421          e: true.private,
422          f: 123456789field.public,
423          g: 0group.private
424      },
425      _nonce: 0group.public,
426      _version: 0u8.public
427  }";
428          assert!(Plaintext::<CurrentNetwork>::parse(expected).is_err());
429          Ok(())
430      }
431  }