ergotree_ir/serialization/
serializable.rs

1//! Serialization of Ergo types
2use crate::chain::ergo_box::RegisterValueError;
3use crate::ergo_tree::ErgoTreeHeaderError;
4use crate::mir::val_def::ValId;
5use crate::mir::{constant::TryExtractFromError, expr::InvalidArgumentError};
6use crate::types::type_unify::TypeUnificationError;
7
8use super::{
9    constant_store::ConstantStore,
10    sigma_byte_reader::{SigmaByteRead, SigmaByteReader},
11    sigma_byte_writer::{SigmaByteWrite, SigmaByteWriter},
12};
13use crate::types::smethod::MethodId;
14use bounded_vec::BoundedVec;
15use bounded_vec::BoundedVecOutOfBounds;
16use io::Cursor;
17use sigma_ser::{vlq_encode, ScorexParsingError, ScorexSerializationError};
18use std::convert::TryInto;
19use std::io;
20use thiserror::Error;
21
22/// Ways serialization might fail
23#[derive(Error, Eq, PartialEq, Debug, Clone)]
24pub enum SigmaSerializationError {
25    /// IO fail (EOF, etc.)
26    #[error("IO error: {0}")]
27    Io(String),
28    /// Serialization not yet implemented
29    #[error("serialization not yet implemented: {0}")]
30    NotImplementedYet(&'static str),
31    /// Unexpected value type
32    #[error("Unexpected value: {0:?}")]
33    UnexpectedValue(#[from] TryExtractFromError),
34    /// Serialization not supported
35    #[error("serialization not supported: {0}")]
36    NotSupported(String),
37    /// Scorex serialization error
38    #[error("Scorex serialization error: {0}")]
39    ScorexSerializationError(#[from] ScorexSerializationError),
40}
41
42impl From<io::Error> for SigmaSerializationError {
43    fn from(error: io::Error) -> Self {
44        SigmaSerializationError::Io(error.to_string())
45    }
46}
47
48/// Ways parsing might fail
49#[derive(Error, Eq, PartialEq, Debug, Clone)]
50pub enum SigmaParsingError {
51    /// Invalid op code
52    #[error("invalid op code: {0}")]
53    InvalidOpCode(u8),
54    /// Lacking support for the op
55    #[error("not implemented op error: {0}")]
56    NotImplementedOpCode(String),
57    /// Failed to parse type
58    #[error("type parsing error, invalid type code: {0}({0:#04X})")]
59    InvalidTypeCode(u8),
60    /// Failed to decode VLQ
61    #[error("vlq encode error: {0}")]
62    VlqEncode(#[from] vlq_encode::VlqEncodingError),
63    /// IO fail (EOF, etc.)
64    #[error("IO error: {0}")]
65    Io(String),
66    /// Misc fail
67    #[error("misc error: {0}")]
68    Misc(String),
69    /// Feature not yet implemented
70    #[error("parsing not yet implemented: {0}")]
71    NotImplementedYet(String),
72    /// Constant with given index not found in constant store
73    #[error("Constant with index {0} not found in constant store")]
74    ConstantForPlaceholderNotFound(u32),
75    /// Value out of bounds
76    #[error("Value out of bounds: {0}")]
77    ValueOutOfBounds(String),
78    /// Tuple items out of bounds
79    #[error("Tuple items out of bounds: {0}")]
80    TupleItemsOutOfBounds(usize),
81    /// ValDef type for a given index not found in ValDefTypeStore store
82    #[error("ValDef type for an index {0:?} not found in ValDefTypeStore store")]
83    ValDefIdNotFound(ValId),
84    /// Invalid argument on node creation
85    #[error("Invalid argument: {0:?}")]
86    InvalidArgument(#[from] InvalidArgumentError),
87    /// Unknown method ID for given type code
88    #[error("No method id {0:?} found in type companion with type id {1:?} ")]
89    UnknownMethodId(MethodId, u8),
90    /// Feature not supported
91    #[error("parsing not supported: {0}")]
92    NotSupported(&'static str),
93    /// Serialization error
94    #[error("serialization error: {0}")]
95    SerializationError(#[from] SigmaSerializationError),
96    /// Invalid item quantity for BoundedVec
97    #[error("Invalid item quantity for BoundedVec: {0}")]
98    BoundedVecOutOfBounds(#[from] BoundedVecOutOfBounds),
99    /// Scorex parsing error
100    #[error("Scorex parsing error: {0}")]
101    ScorexParsingError(#[from] ScorexParsingError),
102    /// ErgoTreeHeaderError
103    #[error("ErgoTreeHeaderError: {0}")]
104    ErgoTreeHeaderError(#[from] ErgoTreeHeaderError),
105    /// Invalid register value
106    #[error("Invalid register value: {0}")]
107    InvalidRegisterValue(#[from] RegisterValueError),
108}
109
110impl From<io::Error> for SigmaParsingError {
111    fn from(error: io::Error) -> Self {
112        SigmaParsingError::Io(error.to_string())
113    }
114}
115
116impl From<&io::Error> for SigmaParsingError {
117    fn from(error: &io::Error) -> Self {
118        SigmaParsingError::Io(error.to_string())
119    }
120}
121
122impl From<TypeUnificationError> for SigmaParsingError {
123    fn from(e: TypeUnificationError) -> Self {
124        SigmaParsingError::Misc(format!("{:?}", e))
125    }
126}
127
128/// Result type for [`SigmaSerializable::sigma_serialize`]
129pub type SigmaSerializeResult = Result<(), SigmaSerializationError>;
130
131/// Consensus-critical serialization for Ergo
132pub trait SigmaSerializable: Sized {
133    /// Write `self` to the given `writer`.
134    /// This function has a `sigma_` prefix to alert the reader that the
135    /// serialization in use is consensus-critical serialization    
136    // fn sigma_serialize<W: SigmaByteWrite>(&self, w: &mut W) -> SigmaSerializeResult;
137    fn sigma_serialize<W: SigmaByteWrite>(&self, w: &mut W) -> SigmaSerializeResult;
138
139    /// Try to read `self` from the given `reader`.
140    /// `sigma-` prefix to alert the reader that the serialization in use
141    /// is consensus-critical
142    fn sigma_parse<R: SigmaByteRead>(r: &mut R) -> Result<Self, SigmaParsingError>;
143
144    /// Serialize any SigmaSerializable value into bytes
145    fn sigma_serialize_bytes(&self) -> Result<Vec<u8>, SigmaSerializationError> {
146        let mut data = Vec::new();
147        let mut w = SigmaByteWriter::new(&mut data, None);
148        self.sigma_serialize(&mut w)?;
149        Ok(data)
150    }
151
152    /// Parse `self` from the bytes
153    fn sigma_parse_bytes(bytes: &[u8]) -> Result<Self, SigmaParsingError> {
154        let cursor = Cursor::new(bytes);
155        let mut sr = SigmaByteReader::new(cursor, ConstantStore::empty());
156        Self::sigma_parse(&mut sr)
157    }
158}
159
160impl<T: SigmaSerializable> SigmaSerializable for Vec<T> {
161    fn sigma_serialize<W: SigmaByteWrite>(&self, w: &mut W) -> SigmaSerializeResult {
162        w.put_u32(self.len() as u32)?;
163        self.iter().try_for_each(|i| i.sigma_serialize(w))
164    }
165
166    fn sigma_parse<R: SigmaByteRead>(r: &mut R) -> Result<Self, SigmaParsingError> {
167        let items_count = r.get_u32()?;
168        let mut items = Vec::with_capacity(items_count as usize);
169        for _ in 0..items_count {
170            items.push(T::sigma_parse(r)?);
171        }
172        Ok(items)
173    }
174}
175
176impl<T: SigmaSerializable, const L: usize, const U: usize> SigmaSerializable
177    for BoundedVec<T, L, U>
178{
179    fn sigma_serialize<W: SigmaByteWrite>(&self, w: &mut W) -> SigmaSerializeResult {
180        self.as_vec().sigma_serialize(w)
181    }
182
183    fn sigma_parse<R: SigmaByteRead>(r: &mut R) -> Result<Self, SigmaParsingError> {
184        Ok(Vec::<T>::sigma_parse(r)?.try_into()?)
185    }
186}
187
188/// Corresponds to `VLQ(UInt)` format from `ErgoTree` spec.
189impl SigmaSerializable for u32 {
190    fn sigma_serialize<W: SigmaByteWrite>(&self, w: &mut W) -> SigmaSerializeResult {
191        w.put_u32(*self)?;
192        Ok(())
193    }
194    fn sigma_parse<R: SigmaByteRead>(r: &mut R) -> Result<Self, SigmaParsingError> {
195        let v = r.get_u32()?;
196        Ok(v)
197    }
198}
199
200impl<T: SigmaSerializable> SigmaSerializable for Option<Box<T>> {
201    fn sigma_serialize<W: SigmaByteWrite>(&self, w: &mut W) -> SigmaSerializeResult {
202        match self {
203            Some(v) => {
204                w.put_u8(1)?;
205                v.sigma_serialize(w)
206            }
207            None => Ok(w.put_u8(0)?),
208        }
209    }
210
211    fn sigma_parse<R: SigmaByteRead>(r: &mut R) -> Result<Self, SigmaParsingError> {
212        let tag = r.get_u8()?;
213        Ok(if tag != 0 {
214            Some(T::sigma_parse(r)?.into())
215        } else {
216            None
217        })
218    }
219}
220
221/// serialization roundtrip
222#[allow(clippy::expect_used)]
223pub fn sigma_serialize_roundtrip<T: SigmaSerializable>(v: &T) -> T {
224    let mut data = Vec::new();
225    let mut w = SigmaByteWriter::new(&mut data, None);
226    v.sigma_serialize(&mut w).expect("serialization failed");
227    let cursor = Cursor::new(&mut data[..]);
228    let mut sr = SigmaByteReader::new(cursor, ConstantStore::empty());
229    T::sigma_parse(&mut sr).expect("parse failed")
230}