casper_types/system/auction/
unbond.rs

1use alloc::{string::String, vec::Vec};
2use core::fmt::{self, Display, Formatter};
3#[cfg(feature = "datasize")]
4use datasize::DataSize;
5#[cfg(feature = "json-schema")]
6use schemars::JsonSchema;
7
8use super::{BidAddr, DelegatorKind, UnbondingPurse, WithdrawPurse};
9use crate::{
10    bytesrepr::{self, FromBytes, ToBytes, U8_SERIALIZED_LENGTH},
11    checksummed_hex, CLType, CLTyped, EraId, PublicKey, URef, URefAddr, U512,
12};
13use serde::{de::Error as SerdeError, Deserialize, Deserializer, Serialize, Serializer};
14use serde_helpers::{HumanReadableUnbondKind, NonHumanReadableUnbondKind};
15
16/// UnbondKindTag variants.
17#[allow(clippy::large_enum_variant)]
18#[repr(u8)]
19#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)]
20pub enum UnbondKindTag {
21    /// Validator bid.
22    Validator = 0,
23    /// Validator bid.
24    DelegatedAccount = 1,
25    /// Delegator bid.
26    DelegatedPurse = 2,
27}
28
29/// Unbond variants.
30#[derive(Debug, PartialEq, Eq, Clone, Ord, PartialOrd)]
31#[cfg_attr(feature = "datasize", derive(DataSize))]
32#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
33pub enum UnbondKind {
34    Validator(PublicKey),
35    DelegatedPublicKey(PublicKey),
36    DelegatedPurse(#[cfg_attr(feature = "json-schema", schemars(with = "String"))] URefAddr),
37}
38
39impl UnbondKind {
40    /// Returns UnbondKindTag.
41    pub fn tag(&self) -> UnbondKindTag {
42        match self {
43            UnbondKind::Validator(_) => UnbondKindTag::Validator,
44            UnbondKind::DelegatedPublicKey(_) => UnbondKindTag::DelegatedAccount,
45            UnbondKind::DelegatedPurse(_) => UnbondKindTag::DelegatedPurse,
46        }
47    }
48
49    /// Returns PublicKey, if any.
50    pub fn maybe_public_key(&self) -> Option<PublicKey> {
51        match self {
52            UnbondKind::Validator(pk) | UnbondKind::DelegatedPublicKey(pk) => Some(pk.clone()),
53            UnbondKind::DelegatedPurse(_) => None,
54        }
55    }
56
57    /// Is this a validator unbond?
58    pub fn is_validator(&self) -> bool {
59        match self {
60            UnbondKind::Validator(_) => true,
61            UnbondKind::DelegatedPublicKey(_) | UnbondKind::DelegatedPurse(_) => false,
62        }
63    }
64
65    /// Is this a delegator unbond?
66    pub fn is_delegator(&self) -> bool {
67        !self.is_validator()
68    }
69
70    /// The correct bid addr for this instance.
71    pub fn bid_addr(&self, validator_public_key: &PublicKey) -> BidAddr {
72        match self {
73            UnbondKind::Validator(pk) => BidAddr::UnbondAccount {
74                validator: validator_public_key.to_account_hash(),
75                unbonder: pk.to_account_hash(),
76            },
77            UnbondKind::DelegatedPublicKey(pk) => BidAddr::DelegatedAccount {
78                delegator: pk.to_account_hash(),
79                validator: validator_public_key.to_account_hash(),
80            },
81            UnbondKind::DelegatedPurse(addr) => BidAddr::DelegatedPurse {
82                validator: validator_public_key.to_account_hash(),
83                delegator: *addr,
84            },
85        }
86    }
87}
88
89impl ToBytes for UnbondKind {
90    fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
91        let mut result = bytesrepr::allocate_buffer(self)?;
92        let (tag, mut serialized_data) = match self {
93            UnbondKind::Validator(pk) => (UnbondKindTag::Validator, pk.to_bytes()?),
94            UnbondKind::DelegatedPublicKey(pk) => (UnbondKindTag::DelegatedAccount, pk.to_bytes()?),
95            UnbondKind::DelegatedPurse(addr) => (UnbondKindTag::DelegatedPurse, addr.to_bytes()?),
96        };
97        result.push(tag as u8);
98        result.append(&mut serialized_data);
99        Ok(result)
100    }
101
102    fn serialized_length(&self) -> usize {
103        U8_SERIALIZED_LENGTH
104            + match self {
105                UnbondKind::Validator(pk) => pk.serialized_length(),
106                UnbondKind::DelegatedPublicKey(pk) => pk.serialized_length(),
107                UnbondKind::DelegatedPurse(addr) => addr.serialized_length(),
108            }
109    }
110
111    fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
112        writer.push(self.tag() as u8);
113        match self {
114            UnbondKind::Validator(pk) => pk.write_bytes(writer)?,
115            UnbondKind::DelegatedPublicKey(pk) => pk.write_bytes(writer)?,
116            UnbondKind::DelegatedPurse(addr) => addr.write_bytes(writer)?,
117        };
118        Ok(())
119    }
120}
121
122impl FromBytes for UnbondKind {
123    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
124        let (tag, remainder): (u8, &[u8]) = FromBytes::from_bytes(bytes)?;
125        match tag {
126            tag if tag == UnbondKindTag::Validator as u8 => PublicKey::from_bytes(remainder)
127                .map(|(pk, remainder)| (UnbondKind::Validator(pk), remainder)),
128            tag if tag == UnbondKindTag::DelegatedAccount as u8 => PublicKey::from_bytes(remainder)
129                .map(|(pk, remainder)| (UnbondKind::DelegatedPublicKey(pk), remainder)),
130            tag if tag == UnbondKindTag::DelegatedPurse as u8 => URefAddr::from_bytes(remainder)
131                .map(|(delegator_bid, remainder)| {
132                    (UnbondKind::DelegatedPurse(delegator_bid), remainder)
133                }),
134            _ => Err(bytesrepr::Error::Formatting),
135        }
136    }
137}
138
139impl From<DelegatorKind> for UnbondKind {
140    fn from(value: DelegatorKind) -> Self {
141        match value {
142            DelegatorKind::PublicKey(pk) => UnbondKind::DelegatedPublicKey(pk),
143            DelegatorKind::Purse(addr) => UnbondKind::DelegatedPurse(addr),
144        }
145    }
146}
147
148impl Serialize for UnbondKind {
149    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
150        if serializer.is_human_readable() {
151            HumanReadableUnbondKind::from(self).serialize(serializer)
152        } else {
153            NonHumanReadableUnbondKind::from(self).serialize(serializer)
154        }
155    }
156}
157
158#[derive(Debug)]
159enum UnbondKindError {
160    DeserializationError(String),
161}
162
163impl Display for UnbondKindError {
164    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
165        match self {
166            UnbondKindError::DeserializationError(msg) => {
167                write!(f, "Error when deserializing UnbondKind: {}", msg)
168            }
169        }
170    }
171}
172
173impl TryFrom<HumanReadableUnbondKind> for UnbondKind {
174    type Error = UnbondKindError;
175
176    fn try_from(value: HumanReadableUnbondKind) -> Result<Self, Self::Error> {
177        match value {
178            HumanReadableUnbondKind::Validator(public_key) => Ok(UnbondKind::Validator(public_key)),
179            HumanReadableUnbondKind::DelegatedPublicKey(public_key) => {
180                Ok(UnbondKind::DelegatedPublicKey(public_key))
181            }
182            HumanReadableUnbondKind::DelegatedPurse(encoded) => {
183                let decoded = checksummed_hex::decode(encoded).map_err(|e| {
184                    UnbondKindError::DeserializationError(format!(
185                        "Failed to decode encoded URefAddr: {}",
186                        e
187                    ))
188                })?;
189                let uref_addr = URefAddr::try_from(decoded.as_ref()).map_err(|e| {
190                    UnbondKindError::DeserializationError(format!(
191                        "Failed to build uref address: {}",
192                        e
193                    ))
194                })?;
195                Ok(UnbondKind::DelegatedPurse(uref_addr))
196            }
197        }
198    }
199}
200
201impl From<NonHumanReadableUnbondKind> for UnbondKind {
202    fn from(value: NonHumanReadableUnbondKind) -> Self {
203        match value {
204            NonHumanReadableUnbondKind::Validator(public_key) => UnbondKind::Validator(public_key),
205            NonHumanReadableUnbondKind::DelegatedPublicKey(public_key) => {
206                UnbondKind::DelegatedPublicKey(public_key)
207            }
208            NonHumanReadableUnbondKind::DelegatedPurse(uref_addr) => {
209                UnbondKind::DelegatedPurse(uref_addr)
210            }
211        }
212    }
213}
214
215impl<'de> Deserialize<'de> for UnbondKind {
216    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
217        if deserializer.is_human_readable() {
218            let human_readable = HumanReadableUnbondKind::deserialize(deserializer)?;
219            UnbondKind::try_from(human_readable)
220                .map_err(|error| SerdeError::custom(format!("{:?}", error)))
221        } else {
222            let non_human_readable = NonHumanReadableUnbondKind::deserialize(deserializer)?;
223            Ok(UnbondKind::from(non_human_readable))
224        }
225    }
226}
227
228#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone)]
229#[cfg_attr(feature = "datasize", derive(DataSize))]
230#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
231#[serde(deny_unknown_fields)]
232pub struct Unbond {
233    /// Validators public key.
234    validator_public_key: PublicKey,
235    /// Unbond kind.
236    unbond_kind: UnbondKind,
237    /// Unbond amounts per era.
238    eras: Vec<UnbondEra>,
239}
240
241impl Unbond {
242    /// Creates [`Unbond`] instance for an unbonding request.
243    pub const fn new(
244        validator_public_key: PublicKey,
245        unbond_kind: UnbondKind,
246        eras: Vec<UnbondEra>,
247    ) -> Self {
248        Self {
249            validator_public_key,
250            unbond_kind,
251            eras,
252        }
253    }
254
255    /// Creates [`Unbond`] instance for an unbonding request.
256    pub fn new_validator_unbond(validator_public_key: PublicKey, eras: Vec<UnbondEra>) -> Self {
257        Self {
258            validator_public_key: validator_public_key.clone(),
259            unbond_kind: UnbondKind::Validator(validator_public_key),
260            eras,
261        }
262    }
263
264    /// Creates [`Unbond`] instance for an unbonding request.
265    pub const fn new_delegated_account_unbond(
266        validator_public_key: PublicKey,
267        delegator_public_key: PublicKey,
268        eras: Vec<UnbondEra>,
269    ) -> Self {
270        Self {
271            validator_public_key,
272            unbond_kind: UnbondKind::DelegatedPublicKey(delegator_public_key),
273            eras,
274        }
275    }
276
277    /// Creates [`Unbond`] instance for an unbonding request.
278    pub const fn new_delegated_purse_unbond(
279        validator_public_key: PublicKey,
280        delegator_purse_addr: URefAddr,
281        eras: Vec<UnbondEra>,
282    ) -> Self {
283        Self {
284            validator_public_key,
285            unbond_kind: UnbondKind::DelegatedPurse(delegator_purse_addr),
286            eras,
287        }
288    }
289
290    /// Checks if given request is made by a validator by checking if public key of unbonder is same
291    /// as a key owned by validator.
292    pub fn is_validator(&self) -> bool {
293        match self.unbond_kind.maybe_public_key() {
294            Some(pk) => pk == self.validator_public_key,
295            None => false,
296        }
297    }
298
299    /// Returns public key of validator.
300    pub fn validator_public_key(&self) -> &PublicKey {
301        &self.validator_public_key
302    }
303
304    /// Returns unbond kind.
305    pub fn unbond_kind(&self) -> &UnbondKind {
306        &self.unbond_kind
307    }
308
309    /// Returns eras unbond items.
310    pub fn eras(&self) -> &Vec<UnbondEra> {
311        &self.eras
312    }
313
314    /// Returns eras unbond items.
315    pub fn eras_mut(&mut self) -> &mut Vec<UnbondEra> {
316        &mut self.eras
317    }
318
319    /// Takes eras unbond items.
320    pub fn take_eras(mut self) -> Vec<UnbondEra> {
321        let eras = self.eras;
322        self.eras = vec![];
323        eras
324    }
325
326    /// Splits instance into eras that are not expired, and eras that are expired (if any).
327    pub fn expired(self, era_id: EraId, unbonding_delay: u64) -> (Unbond, Option<Vec<UnbondEra>>) {
328        let mut retained = vec![];
329        let mut expired = vec![];
330        for era in self.eras {
331            let threshold = era
332                .era_of_creation()
333                .value()
334                .saturating_add(unbonding_delay);
335            if era_id.value() >= threshold {
336                expired.push(era);
337            } else {
338                retained.push(era)
339            }
340        }
341        let ret = Unbond::new(self.validator_public_key, self.unbond_kind, retained);
342        if !expired.is_empty() {
343            (ret, Some(expired))
344        } else {
345            (ret, None)
346        }
347    }
348
349    /// Returns the unbond era with the highest era of creation.
350    pub fn target_unbond_era(&self) -> Option<UnbondEra> {
351        self.eras()
352            .iter()
353            .max_by(|x, y| x.era_of_creation().cmp(&y.era_of_creation()))
354            .cloned()
355    }
356
357    /// Returns a mutable reference to the unbond era with the highest era of creation.
358    pub fn target_unbond_era_mut(&mut self) -> Option<&mut UnbondEra> {
359        self.eras_mut()
360            .iter_mut()
361            .max_by(|x, y| x.era_of_creation().cmp(&y.era_of_creation()))
362    }
363}
364
365impl ToBytes for Unbond {
366    fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
367        let mut result = bytesrepr::allocate_buffer(self)?;
368        result.extend(&self.validator_public_key.to_bytes()?);
369        result.extend(&self.unbond_kind.to_bytes()?);
370        result.extend(&self.eras.to_bytes()?);
371        Ok(result)
372    }
373    fn serialized_length(&self) -> usize {
374        self.validator_public_key.serialized_length()
375            + self.unbond_kind.serialized_length()
376            + self.eras.serialized_length()
377    }
378
379    fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
380        self.validator_public_key.write_bytes(writer)?;
381        self.unbond_kind.write_bytes(writer)?;
382        self.eras.write_bytes(writer)?;
383        Ok(())
384    }
385}
386
387impl FromBytes for Unbond {
388    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
389        let (validator_public_key, remainder) = FromBytes::from_bytes(bytes)?;
390        let (unbond_kind, remainder) = FromBytes::from_bytes(remainder)?;
391        let (eras, remainder) = FromBytes::from_bytes(remainder)?;
392
393        Ok((
394            Unbond {
395                validator_public_key,
396                unbond_kind,
397                eras,
398            },
399            remainder,
400        ))
401    }
402}
403
404impl CLTyped for Unbond {
405    fn cl_type() -> CLType {
406        CLType::Any
407    }
408}
409
410impl Default for Unbond {
411    fn default() -> Self {
412        Self {
413            unbond_kind: UnbondKind::Validator(PublicKey::System),
414            validator_public_key: PublicKey::System,
415            eras: vec![],
416        }
417    }
418}
419
420impl From<UnbondingPurse> for Unbond {
421    fn from(unbonding_purse: UnbondingPurse) -> Self {
422        let unbond_kind =
423            if unbonding_purse.validator_public_key() == unbonding_purse.unbonder_public_key() {
424                UnbondKind::Validator(unbonding_purse.validator_public_key().clone())
425            } else {
426                UnbondKind::DelegatedPublicKey(unbonding_purse.unbonder_public_key().clone())
427            };
428        Unbond::new(
429            unbonding_purse.validator_public_key().clone(),
430            unbond_kind,
431            vec![UnbondEra::new(
432                *unbonding_purse.bonding_purse(),
433                unbonding_purse.era_of_creation(),
434                *unbonding_purse.amount(),
435                None,
436            )],
437        )
438    }
439}
440
441impl From<WithdrawPurse> for Unbond {
442    fn from(withdraw_purse: WithdrawPurse) -> Self {
443        let unbond_kind =
444            if withdraw_purse.validator_public_key == withdraw_purse.unbonder_public_key {
445                UnbondKind::Validator(withdraw_purse.validator_public_key.clone())
446            } else {
447                UnbondKind::DelegatedPublicKey(withdraw_purse.unbonder_public_key.clone())
448            };
449        Unbond::new(
450            withdraw_purse.validator_public_key,
451            unbond_kind,
452            vec![UnbondEra::new(
453                withdraw_purse.bonding_purse,
454                withdraw_purse.era_of_creation,
455                withdraw_purse.amount,
456                None,
457            )],
458        )
459    }
460}
461
462/// Unbond amounts per era.
463#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone, Default)]
464#[cfg_attr(feature = "datasize", derive(DataSize))]
465#[cfg_attr(feature = "json-schema", derive(JsonSchema))]
466#[serde(deny_unknown_fields)]
467pub struct UnbondEra {
468    /// Bonding Purse
469    bonding_purse: URef,
470    /// Era in which this unbonding request was created.
471    era_of_creation: EraId,
472    /// Unbonding Amount.
473    amount: U512,
474    /// The validator public key to re-delegate to.
475    new_validator: Option<PublicKey>,
476}
477
478impl UnbondEra {
479    /// Creates [`UnbondEra`] instance for an unbonding request.
480    pub const fn new(
481        bonding_purse: URef,
482        era_of_creation: EraId,
483        amount: U512,
484        new_validator: Option<PublicKey>,
485    ) -> Self {
486        Self {
487            bonding_purse,
488            era_of_creation,
489            amount,
490            new_validator,
491        }
492    }
493
494    /// Returns bonding purse used to make this unbonding request.
495    pub fn bonding_purse(&self) -> &URef {
496        &self.bonding_purse
497    }
498
499    /// Returns era which was used to create this unbonding request.
500    pub fn era_of_creation(&self) -> EraId {
501        self.era_of_creation
502    }
503
504    /// Returns unbonding amount.
505    pub fn amount(&self) -> &U512 {
506        &self.amount
507    }
508
509    /// Returns the public key for the new validator.
510    pub fn new_validator(&self) -> &Option<PublicKey> {
511        &self.new_validator
512    }
513
514    /// Sets amount to provided value.
515    pub fn with_amount(&mut self, amount: U512) {
516        self.amount = amount;
517    }
518}
519
520impl ToBytes for UnbondEra {
521    fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
522        let mut result = bytesrepr::allocate_buffer(self)?;
523        result.extend(&self.bonding_purse.to_bytes()?);
524        result.extend(&self.era_of_creation.to_bytes()?);
525        result.extend(&self.amount.to_bytes()?);
526        result.extend(&self.new_validator.to_bytes()?);
527        Ok(result)
528    }
529    fn serialized_length(&self) -> usize {
530        self.bonding_purse.serialized_length()
531            + self.era_of_creation.serialized_length()
532            + self.amount.serialized_length()
533            + self.new_validator.serialized_length()
534    }
535
536    fn write_bytes(&self, writer: &mut Vec<u8>) -> Result<(), bytesrepr::Error> {
537        self.bonding_purse.write_bytes(writer)?;
538        self.era_of_creation.write_bytes(writer)?;
539        self.amount.write_bytes(writer)?;
540        self.new_validator.write_bytes(writer)?;
541        Ok(())
542    }
543}
544
545impl FromBytes for UnbondEra {
546    fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
547        let (bonding_purse, remainder) = FromBytes::from_bytes(bytes)?;
548        let (era_of_creation, remainder) = FromBytes::from_bytes(remainder)?;
549        let (amount, remainder) = FromBytes::from_bytes(remainder)?;
550        let (new_validator, remainder) = Option::<PublicKey>::from_bytes(remainder)?;
551
552        Ok((
553            UnbondEra {
554                bonding_purse,
555                era_of_creation,
556                amount,
557                new_validator,
558            },
559            remainder,
560        ))
561    }
562}
563
564impl CLTyped for UnbondEra {
565    fn cl_type() -> CLType {
566        CLType::Any
567    }
568}
569
570mod serde_helpers {
571    use super::UnbondKind;
572    use crate::{PublicKey, URefAddr};
573    use alloc::string::String;
574    use serde::{Deserialize, Serialize};
575
576    #[derive(Serialize, Deserialize)]
577    pub(super) enum HumanReadableUnbondKind {
578        Validator(PublicKey),
579        DelegatedPublicKey(PublicKey),
580        DelegatedPurse(String),
581    }
582
583    #[derive(Serialize, Deserialize)]
584    pub(super) enum NonHumanReadableUnbondKind {
585        Validator(PublicKey),
586        DelegatedPublicKey(PublicKey),
587        DelegatedPurse(URefAddr),
588    }
589
590    impl From<&UnbondKind> for HumanReadableUnbondKind {
591        fn from(unbond_source: &UnbondKind) -> Self {
592            match unbond_source {
593                UnbondKind::Validator(public_key) => {
594                    HumanReadableUnbondKind::Validator(public_key.clone())
595                }
596                UnbondKind::DelegatedPublicKey(public_key) => {
597                    HumanReadableUnbondKind::DelegatedPublicKey(public_key.clone())
598                }
599                UnbondKind::DelegatedPurse(uref_addr) => {
600                    HumanReadableUnbondKind::DelegatedPurse(base16::encode_lower(uref_addr))
601                }
602            }
603        }
604    }
605
606    impl From<&UnbondKind> for NonHumanReadableUnbondKind {
607        fn from(unbond_kind: &UnbondKind) -> Self {
608            match unbond_kind {
609                UnbondKind::Validator(public_key) => {
610                    NonHumanReadableUnbondKind::Validator(public_key.clone())
611                }
612                UnbondKind::DelegatedPublicKey(public_key) => {
613                    NonHumanReadableUnbondKind::DelegatedPublicKey(public_key.clone())
614                }
615                UnbondKind::DelegatedPurse(uref_addr) => {
616                    NonHumanReadableUnbondKind::DelegatedPurse(*uref_addr)
617                }
618            }
619        }
620    }
621}
622
623#[cfg(test)]
624mod tests {
625    use rand::Rng;
626
627    use crate::{
628        bytesrepr,
629        system::auction::{
630            unbond::{Unbond, UnbondKind},
631            UnbondEra,
632        },
633        testing::TestRng,
634        AccessRights, EraId, PublicKey, SecretKey, URef, U512,
635    };
636
637    const BONDING_PURSE: URef = URef::new([14; 32], AccessRights::READ_ADD_WRITE);
638    const ERA_OF_WITHDRAWAL: EraId = EraId::MAX;
639
640    fn validator_public_key() -> PublicKey {
641        let secret_key = SecretKey::ed25519_from_bytes([42; SecretKey::ED25519_LENGTH]).unwrap();
642        PublicKey::from(&secret_key)
643    }
644
645    fn delegated_account_unbond_kind() -> UnbondKind {
646        let secret_key = SecretKey::ed25519_from_bytes([43; SecretKey::ED25519_LENGTH]).unwrap();
647        UnbondKind::DelegatedPublicKey(PublicKey::from(&secret_key))
648    }
649
650    fn amount() -> U512 {
651        U512::max_value() - 1
652    }
653
654    #[test]
655    fn serialization_roundtrip_for_unbond() {
656        let unbond_era = UnbondEra {
657            bonding_purse: BONDING_PURSE,
658            era_of_creation: ERA_OF_WITHDRAWAL,
659            amount: amount(),
660            new_validator: None,
661        };
662
663        let unbond = Unbond {
664            validator_public_key: validator_public_key(),
665            unbond_kind: delegated_account_unbond_kind(),
666            eras: vec![unbond_era],
667        };
668
669        bytesrepr::test_serialization_roundtrip(&unbond);
670    }
671
672    #[test]
673    fn should_be_validator_condition_for_unbond() {
674        let validator_pk = validator_public_key();
675        let validator_unbond = Unbond::new(
676            validator_pk.clone(),
677            UnbondKind::Validator(validator_pk),
678            vec![],
679        );
680        assert!(validator_unbond.is_validator());
681    }
682
683    #[test]
684    fn should_be_delegator_condition_for_unbond() {
685        let delegator_unbond = Unbond::new(
686            validator_public_key(),
687            delegated_account_unbond_kind(),
688            vec![],
689        );
690        assert!(!delegator_unbond.is_validator());
691    }
692
693    #[test]
694    fn purse_serialized_as_string() {
695        let delegator_kind_payload = UnbondKind::DelegatedPurse([1; 32]);
696        let serialized = serde_json::to_string(&delegator_kind_payload).unwrap();
697        assert_eq!(
698            serialized,
699            "{\"DelegatedPurse\":\"0101010101010101010101010101010101010101010101010101010101010101\"}"
700        );
701    }
702
703    #[test]
704    fn given_broken_address_purse_deserialziation_fails() {
705        let failing =
706            "{\"DelegatedPurse\":\"Z101010101010101010101010101010101010101010101010101010101010101\"}";
707        let ret = serde_json::from_str::<UnbondKind>(failing);
708        assert!(ret.is_err());
709        let failing =
710            "{\"DelegatedPurse\":\"01010101010101010101010101010101010101010101010101010101\"}";
711        let ret = serde_json::from_str::<UnbondKind>(failing);
712        assert!(ret.is_err());
713    }
714
715    #[test]
716    fn json_roundtrip() {
717        let rng = &mut TestRng::new();
718
719        let entity = UnbondKind::Validator(PublicKey::random(rng));
720        let json_string = serde_json::to_string_pretty(&entity).unwrap();
721        let decoded: UnbondKind = serde_json::from_str(&json_string).unwrap();
722        assert_eq!(decoded, entity);
723
724        let entity = UnbondKind::DelegatedPublicKey(PublicKey::random(rng));
725        let json_string = serde_json::to_string_pretty(&entity).unwrap();
726        let decoded: UnbondKind = serde_json::from_str(&json_string).unwrap();
727        assert_eq!(decoded, entity);
728
729        let entity = UnbondKind::DelegatedPurse(rng.gen());
730        let json_string = serde_json::to_string_pretty(&entity).unwrap();
731        let decoded: UnbondKind = serde_json::from_str(&json_string).unwrap();
732        assert_eq!(decoded, entity);
733    }
734}