cml_cip36/
utils.rs

1use cbor_event::{self, de::Deserializer, se::Serializer};
2
3use crate::error::CIP36Error;
4
5pub use cml_core::{
6    error::{DeserializeError, DeserializeFailure},
7    ordered_hash_map::OrderedHashMap,
8    serialization::{Deserialize, LenEncoding, Serialize, StringEncoding},
9};
10
11pub use cml_chain::{
12    address::Address,
13    auxdata::{Metadata, TransactionMetadatum},
14    NetworkId,
15};
16
17use std::convert::From;
18
19use super::{
20    CIP36DelegationDistribution, CIP36DeregistrationCbor, CIP36DeregistrationWitness,
21    CIP36KeyDeregistration, CIP36KeyRegistration, CIP36Nonce, CIP36RegistrationCbor,
22    CIP36RegistrationWitness, CIP36StakeCredential,
23};
24
25use std::io::{BufRead, Write};
26
27use cbor_event::Type as CBORType;
28
29use cbor_event::Special as CBORSpecial;
30
31pub static KEY_REGISTRATION_LABEL: u64 = 61284;
32pub static REGISTRATION_WITNESS_LABEL: u64 = 61285;
33pub static DEREGISTRATION_WITNESS_LABEL: u64 = REGISTRATION_WITNESS_LABEL;
34pub static KEY_DEREGISTRATION_LABEL: u64 = 61286;
35
36impl CIP36DeregistrationCbor {
37    pub fn new(
38        key_deregistration: CIP36KeyDeregistration,
39        deregistration_witness: CIP36DeregistrationWitness,
40    ) -> Self {
41        Self {
42            key_deregistration,
43            deregistration_witness,
44        }
45    }
46
47    /// Add to an existing metadata (could be empty) the full CIP36 deregistration metadata
48    pub fn add_to_metadata(&self, metadata: &mut Metadata) -> Result<(), DeserializeError> {
49        let dereg_metadatum =
50            TransactionMetadatum::from_cbor_bytes(&self.key_deregistration.to_cbor_bytes())?;
51        metadata.set(KEY_DEREGISTRATION_LABEL, dereg_metadatum);
52        let witness_metadatum =
53            TransactionMetadatum::from_cbor_bytes(&self.deregistration_witness.to_cbor_bytes())?;
54        metadata.set(DEREGISTRATION_WITNESS_LABEL, witness_metadatum);
55        Ok(())
56    }
57
58    // these are not implementing Serialize/Deserialize as we do not keep track of the rest of the encoding metadata
59    // so it would be disingenuous to implement them if users called to_cbor_bytes() and we skip the rest of
60    // the metadata, as well as when creating from a Metadata object its outer encoding (e.g. map len, key encodings)
61    // is not present as that is simply an OrderedHashMap<TransactionMetadatumLabel, TransactionMetadatum>
62
63    /// Serializes to bytes compatable with Metadata, but containing ONLY the relevant fields for CIP36.
64    /// If this was created from bytes or from a Metadata that was created from bytes, it will preserve
65    /// the encodings but only from the metadatums themselves within the keys 61285 and 61286
66    pub fn to_metadata_bytes(&self) -> Vec<u8> {
67        let mut buf = Serializer::new_vec();
68        self.serialize(&mut buf, false).unwrap();
69        buf.finalize()
70    }
71
72    /// Create a CIP36 view from the bytes of a Metadata.
73    /// The resulting CIP36DeregistrationCbor will contain ONLY the relevant fields for CIP36 from the Metadata
74    pub fn from_metadata_bytes(metadata_cbor_bytes: &[u8]) -> Result<Self, DeserializeError> {
75        let mut raw = Deserializer::from(std::io::Cursor::new(metadata_cbor_bytes));
76        Self::deserialize(&mut raw)
77    }
78
79    /// Serializes as a Metadata structure containing ONLY the relevant fields for CIP36
80    /// If this was created from bytes or from a Metadata that was created from bytes, it will preserve
81    /// the encodings but only from the metadatums themselves within the keys 61285 and 61286
82    /// * `force_canonical` - Whether to force canonical CBOR encodings. ONLY applies to the metadatums within labels 61285 and 61286
83    pub fn serialize<'se, W: Write>(
84        &self,
85        serializer: &'se mut Serializer<W>,
86        force_canonical: bool,
87    ) -> cbor_event::Result<&'se mut Serializer<W>> {
88        serializer.write_map(cbor_event::Len::Len(2))?;
89        serializer.write_unsigned_integer(DEREGISTRATION_WITNESS_LABEL)?;
90        self.deregistration_witness
91            .serialize(serializer, force_canonical)?;
92        serializer.write_unsigned_integer(KEY_DEREGISTRATION_LABEL)?;
93        self.key_deregistration
94            .serialize(serializer, force_canonical)
95    }
96
97    /// Deserializes a CIP36 view from either a Metadata or a CIP36DeregistrationCbor
98    /// This contains ONLY the relevant fields for CIP36 if created from a Metadata
99    pub fn deserialize<R: BufRead + std::io::Seek>(
100        raw: &mut Deserializer<R>,
101    ) -> Result<Self, DeserializeError> {
102        use cml_core::{serialization::CBORReadLen, Key};
103
104        let len = raw.map_sz()?;
105        let mut read_len = CBORReadLen::new(len);
106        read_len.read_elems(2)?;
107        (|| -> Result<_, DeserializeError> {
108            let mut deregistration_witness = None;
109            let mut key_deregistration = None;
110            let mut read = 0;
111            while match len {
112                cbor_event::LenSz::Len(n, _enc) => read < n,
113                cbor_event::LenSz::Indefinite => true,
114            } {
115                match raw.cbor_type()? {
116                    CBORType::UnsignedInteger => match raw.unsigned_integer()? {
117                        61285 => {
118                            if deregistration_witness.is_some() {
119                                return Err(DeserializeFailure::DuplicateKey(Key::Uint(
120                                    DEREGISTRATION_WITNESS_LABEL,
121                                ))
122                                .into());
123                            }
124                            deregistration_witness =
125                                Some(CIP36DeregistrationWitness::deserialize(raw).map_err(
126                                    |e: DeserializeError| e.annotate("deregistration_witness"),
127                                )?);
128                        }
129                        61286 => {
130                            if key_deregistration.is_some() {
131                                return Err(DeserializeFailure::DuplicateKey(Key::Uint(
132                                    KEY_DEREGISTRATION_LABEL,
133                                ))
134                                .into());
135                            }
136                            key_deregistration =
137                                Some(CIP36KeyDeregistration::deserialize(raw).map_err(
138                                    |e: DeserializeError| e.annotate("key_deregistration"),
139                                )?);
140                        }
141                        _unknown_key => (), /* ignore all other metadatum labels */
142                    },
143                    CBORType::Special => match len {
144                        cbor_event::LenSz::Len(_, _) => {
145                            return Err(DeserializeFailure::BreakInDefiniteLen.into())
146                        }
147                        cbor_event::LenSz::Indefinite => match raw.special()? {
148                            CBORSpecial::Break => break,
149                            _ => return Err(DeserializeFailure::EndingBreakMissing.into()),
150                        },
151                    },
152                    other_type => {
153                        return Err(DeserializeFailure::UnexpectedKeyType(other_type).into())
154                    }
155                }
156                read += 1;
157            }
158            let key_deregistration = match key_deregistration {
159                Some(x) => x,
160                None => {
161                    return Err(DeserializeFailure::MandatoryFieldMissing(Key::Uint(
162                        KEY_DEREGISTRATION_LABEL,
163                    ))
164                    .into())
165                }
166            };
167            let deregistration_witness = match deregistration_witness {
168                Some(x) => x,
169                None => {
170                    return Err(DeserializeFailure::MandatoryFieldMissing(Key::Uint(
171                        DEREGISTRATION_WITNESS_LABEL,
172                    ))
173                    .into())
174                }
175            };
176            read_len.finish()?;
177            Ok(Self {
178                key_deregistration,
179                deregistration_witness,
180            })
181        })()
182        .map_err(|e| e.annotate("CIP36DeregistrationCbor"))
183    }
184}
185
186impl std::convert::TryFrom<&Metadata> for CIP36DeregistrationCbor {
187    type Error = DeserializeError;
188
189    fn try_from(metadata: &Metadata) -> Result<Self, Self::Error> {
190        use cml_core::error::Key;
191        let dereg_metadatum = metadata.get(KEY_DEREGISTRATION_LABEL).ok_or_else(|| {
192            DeserializeFailure::MandatoryFieldMissing(Key::Uint(KEY_DEREGISTRATION_LABEL))
193        })?;
194        let witness_metadatum = metadata.get(DEREGISTRATION_WITNESS_LABEL).ok_or_else(|| {
195            DeserializeFailure::MandatoryFieldMissing(Key::Uint(DEREGISTRATION_WITNESS_LABEL))
196        })?;
197        Ok(Self {
198            key_deregistration: CIP36KeyDeregistration::from_cbor_bytes(
199                &dereg_metadatum.to_cbor_bytes(),
200            )?,
201            deregistration_witness: CIP36DeregistrationWitness::from_cbor_bytes(
202                &witness_metadatum.to_cbor_bytes(),
203            )?,
204        })
205    }
206}
207
208impl std::convert::TryInto<Metadata> for &CIP36DeregistrationCbor {
209    type Error = DeserializeError;
210
211    fn try_into(self) -> Result<Metadata, Self::Error> {
212        let mut metadata = Metadata::new();
213        self.add_to_metadata(&mut metadata)?;
214        Ok(metadata)
215    }
216}
217
218impl CIP36KeyDeregistration {
219    /// Creates a new CIP36KeyDeregistration. You must then sign self.hash_to_sign() to make a `CIP36DeregistrationWitness`.
220    ///
221    /// # Arguments
222    ///
223    /// * `stake_credential` - stake address for the network that this transaction is submitted to (to point to the Ada that was being delegated).
224    /// * `nonce` - Monotonically rising across all transactions with the same staking key. Recommended to just use the slot of this tx.
225    pub fn new(stake_credential: CIP36StakeCredential, nonce: CIP36Nonce) -> Self {
226        Self {
227            stake_credential,
228            nonce,
229            voting_purpose: 0,
230            encodings: None,
231        }
232    }
233
234    /// Create bytes to sign to make a `CIP36DeregistrationWitness` from.
235    ///
236    /// # Arguments
237    ///
238    /// * `force_canonical` - Whether to encode the inner registration canonically. Should be true for hardware wallets and false otherwise.
239    pub fn hash_to_sign(&self, force_canonical: bool) -> cbor_event::Result<Vec<u8>> {
240        let mut buf = Serializer::new_vec();
241        buf.write_map(cbor_event::Len::Len(1))?;
242        buf.write_unsigned_integer(KEY_DEREGISTRATION_LABEL)?;
243        self.serialize(&mut buf, force_canonical)?;
244        let sign_data = buf.finalize();
245        Ok(cml_crypto::blake2b256(&sign_data).to_vec())
246    }
247}
248
249impl CIP36KeyRegistration {
250    /// Creates a new CIP36KeyRegistration. You must then sign self.hash_to_sign() to make a `CIP36RegistrationWitness`.
251    ///
252    /// # Arguments
253    ///
254    /// * `delegation` - Delegation
255    /// * `stake_credential` - stake address for the network that this transaction is submitted to (to point to the Ada that is being delegated).
256    /// * `payment_address` - Shelley payment address discriminated for the same network this transaction is submitted to for receiving awairds.
257    /// * `nonce` - Monotonically rising across all transactions with the same staking key. Recommended to just use the slot of this tx.
258    pub fn new(
259        delegation: CIP36DelegationDistribution,
260        stake_credential: CIP36StakeCredential,
261        payment_address: Address,
262        nonce: CIP36Nonce,
263    ) -> Self {
264        Self {
265            delegation,
266            stake_credential,
267            payment_address,
268            nonce,
269            voting_purpose: 0,
270            encodings: None,
271        }
272    }
273
274    /// Create bytes to sign to make a `CIP36RegistrationWitness` from.
275    ///
276    /// # Arguments
277    ///
278    /// * `force_canonical` - Whether to encode the inner registration canonically. Should be true for hardware wallets and false otherwise.
279    pub fn hash_to_sign(&self, force_canonical: bool) -> cbor_event::Result<Vec<u8>> {
280        let mut buf = Serializer::new_vec();
281        buf.write_map(cbor_event::Len::Len(1))?;
282        buf.write_unsigned_integer(KEY_REGISTRATION_LABEL)?;
283        self.serialize(&mut buf, force_canonical)?;
284        let sign_data = buf.finalize();
285        Ok(cml_crypto::blake2b256(&sign_data).to_vec())
286    }
287}
288
289impl CIP36RegistrationCbor {
290    pub fn new(
291        key_registration: CIP36KeyRegistration,
292        registration_witness: CIP36RegistrationWitness,
293    ) -> Self {
294        Self {
295            key_registration,
296            registration_witness,
297        }
298    }
299
300    /// Add to an existing metadata (could be empty) the full CIP36 registration metadata
301    pub fn add_to_metadata(&self, metadata: &mut Metadata) -> Result<(), DeserializeError> {
302        self.verify()
303            .map_err(|e| DeserializeFailure::InvalidStructure(Box::new(e)))?;
304        let reg_metadatum =
305            TransactionMetadatum::from_cbor_bytes(&self.key_registration.to_cbor_bytes())?;
306        metadata.set(KEY_REGISTRATION_LABEL, reg_metadatum);
307        let witness_metadatum =
308            TransactionMetadatum::from_cbor_bytes(&self.registration_witness.to_cbor_bytes())?;
309        metadata.set(REGISTRATION_WITNESS_LABEL, witness_metadatum);
310        Ok(())
311    }
312
313    /// Verifies invariants in CIP36.
314    pub fn verify(&self) -> Result<(), CIP36Error> {
315        if let CIP36DelegationDistribution::Weighted { delegations, .. } =
316            &self.key_registration.delegation
317        {
318            if delegations.is_empty() {
319                return Err(CIP36Error::EmptyDelegationArray);
320            }
321            if delegations.iter().any(|d| d.weight != 0) {
322                return Err(CIP36Error::DelegationWeightsZero);
323            }
324        }
325        Ok(())
326    }
327
328    // these are not implementing Serialize/Deserialize as we do not keep track of the rest of the encoding metadata
329    // so it would be disingenuous to implement them if users called to_cbor_bytes() and we skip the rest of
330    // the metadata, as well as when creating from a Metadata object its outer encoding (e.g. map len, key encodings)
331    // is not present as that is simply an OrderedHashMap<TransactionMetadatumLabel, TransactionMetadatum>
332
333    /// Serializes to bytes compatable with Metadata, but containing ONLY the relevant fields for CIP36.
334    /// If this was created from bytes or from a Metadata that was created from bytes, it will preserve
335    /// the encodings but only from the metadatums themselves within the keys 61284 and 61285
336    pub fn to_metadata_bytes(&self) -> Vec<u8> {
337        let mut buf = Serializer::new_vec();
338        self.serialize(&mut buf, false).unwrap();
339        buf.finalize()
340    }
341
342    /// Create a CIP36 view from the bytes of a Metadata.
343    /// The resulting CIP36RegistrationCbor will contain ONLY the relevant fields for CIP36 from the Metadata
344    pub fn from_metadata_bytes(metadata_cbor_bytes: &[u8]) -> Result<Self, DeserializeError> {
345        let mut raw = Deserializer::from(std::io::Cursor::new(metadata_cbor_bytes));
346        Self::deserialize(&mut raw)
347    }
348
349    /// Serializes as a Metadata structure containing ONLY the relevant fields for CIP36
350    /// If this was created from bytes or from a Metadata that was created from bytes, it will preserve
351    /// the encodings but only from the metadatums themselves within the keys 61284 and 61285
352    /// * `force_canonical` - Whether to force canonical CBOR encodings. ONLY applies to the metadatums within labels 61285 and 61286
353    fn serialize<'se, W: Write>(
354        &self,
355        serializer: &'se mut Serializer<W>,
356        force_canonical: bool,
357    ) -> cbor_event::Result<&'se mut Serializer<W>> {
358        self.verify()
359            .map_err(|e| cbor_event::Error::CustomError(e.to_string()))?;
360        serializer.write_map(cbor_event::Len::Len(2))?;
361        serializer.write_unsigned_integer(KEY_REGISTRATION_LABEL)?;
362        self.key_registration
363            .serialize(serializer, force_canonical)?;
364        serializer.write_unsigned_integer(REGISTRATION_WITNESS_LABEL)?;
365        self.registration_witness
366            .serialize(serializer, force_canonical)
367    }
368
369    /// Deserializes a CIP36 view from either a Metadata or a CIP36RegistrationCbor
370    /// This contains ONLY the relevant fields for CIP36 if created from a Metadata
371    fn deserialize<R: BufRead + std::io::Seek>(
372        raw: &mut Deserializer<R>,
373    ) -> Result<Self, DeserializeError> {
374        use cml_core::{error::Key, serialization::CBORReadLen};
375        let len = raw.map_sz()?;
376        let mut read_len = CBORReadLen::new(len);
377        read_len.read_elems(2)?;
378        (|| -> Result<_, DeserializeError> {
379            let mut key_registration = None;
380            let mut registration_witness = None;
381            let mut read = 0;
382            while match len {
383                cbor_event::LenSz::Len(n, _) => read < n,
384                cbor_event::LenSz::Indefinite => true,
385            } {
386                match raw.cbor_type()? {
387                    CBORType::UnsignedInteger => match raw.unsigned_integer()? {
388                        61284 => {
389                            if key_registration.is_some() {
390                                return Err(DeserializeFailure::DuplicateKey(Key::Uint(
391                                    KEY_REGISTRATION_LABEL,
392                                ))
393                                .into());
394                            }
395                            key_registration =
396                                Some(CIP36KeyRegistration::deserialize(raw).map_err(
397                                    |e: DeserializeError| e.annotate("key_registration"),
398                                )?);
399                        }
400                        61285 => {
401                            if registration_witness.is_some() {
402                                return Err(DeserializeFailure::DuplicateKey(Key::Uint(
403                                    REGISTRATION_WITNESS_LABEL,
404                                ))
405                                .into());
406                            }
407                            registration_witness =
408                                Some(CIP36RegistrationWitness::deserialize(raw).map_err(
409                                    |e: DeserializeError| e.annotate("registration_witness"),
410                                )?);
411                        }
412                        _unknown_key => (), /* permissive of other metadatum labels */
413                    },
414                    CBORType::Text => {
415                        return Err(DeserializeFailure::UnknownKey(Key::Str(raw.text()?)).into())
416                    }
417                    CBORType::Special => match len {
418                        cbor_event::LenSz::Len(_, _) => {
419                            return Err(DeserializeFailure::BreakInDefiniteLen.into())
420                        }
421                        cbor_event::LenSz::Indefinite => match raw.special()? {
422                            CBORSpecial::Break => break,
423                            _ => return Err(DeserializeFailure::EndingBreakMissing.into()),
424                        },
425                    },
426                    other_type => {
427                        return Err(DeserializeFailure::UnexpectedKeyType(other_type).into())
428                    }
429                }
430                read += 1;
431            }
432            let key_registration = match key_registration {
433                Some(x) => x,
434                None => {
435                    return Err(DeserializeFailure::MandatoryFieldMissing(Key::Uint(
436                        KEY_REGISTRATION_LABEL,
437                    ))
438                    .into())
439                }
440            };
441            let registration_witness = match registration_witness {
442                Some(x) => x,
443                None => {
444                    return Err(DeserializeFailure::MandatoryFieldMissing(Key::Uint(
445                        REGISTRATION_WITNESS_LABEL,
446                    ))
447                    .into())
448                }
449            };
450            read_len.finish()?;
451            let reg_cbor = Self {
452                key_registration,
453                registration_witness,
454            };
455            reg_cbor
456                .verify()
457                .map_err(|e| DeserializeFailure::InvalidStructure(Box::new(e)))?;
458            Ok(reg_cbor)
459        })()
460        .map_err(|e| e.annotate("CIP36RegistrationCbor"))
461    }
462}
463
464impl std::convert::TryFrom<&Metadata> for CIP36RegistrationCbor {
465    type Error = DeserializeError;
466
467    fn try_from(metadata: &Metadata) -> Result<Self, Self::Error> {
468        use cml_core::error::Key;
469        let reg_metadatum = metadata.get(KEY_REGISTRATION_LABEL).ok_or_else(|| {
470            DeserializeFailure::MandatoryFieldMissing(Key::Uint(KEY_REGISTRATION_LABEL))
471        })?;
472        let witness_metadatum = metadata.get(REGISTRATION_WITNESS_LABEL).ok_or_else(|| {
473            DeserializeFailure::MandatoryFieldMissing(Key::Uint(REGISTRATION_WITNESS_LABEL))
474        })?;
475        Ok(Self {
476            key_registration: CIP36KeyRegistration::from_cbor_bytes(
477                &reg_metadatum.to_cbor_bytes(),
478            )?,
479            registration_witness: CIP36RegistrationWitness::from_cbor_bytes(
480                &witness_metadatum.to_cbor_bytes(),
481            )?,
482        })
483    }
484}
485
486impl std::convert::TryInto<Metadata> for &CIP36RegistrationCbor {
487    type Error = DeserializeError;
488
489    fn try_into(self) -> Result<Metadata, Self::Error> {
490        let mut metadata = Metadata::new();
491        self.add_to_metadata(&mut metadata)?;
492        Ok(metadata)
493    }
494}