penumbra_stake/undelegate_claim/
action.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
use penumbra_asset::balance;
use penumbra_proto::{penumbra::core::component::stake::v1 as pb, DomainType};
use penumbra_txhash::{EffectHash, EffectingData};
use serde::{Deserialize, Serialize};

use crate::{IdentityKey, Penalty, UndelegateClaimProof};

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(try_from = "pb::UndelegateClaimBody", into = "pb::UndelegateClaimBody")]
pub struct UndelegateClaimBody {
    /// The identity key of the validator to undelegate from.
    pub validator_identity: IdentityKey,
    /// The penalty applied to undelegation, in bps^2.
    pub penalty: Penalty,
    /// The action's contribution to the transaction's value balance.
    pub balance_commitment: balance::Commitment,
    /// The height at which unbonding started.
    pub unbonding_start_height: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(try_from = "pb::UndelegateClaim", into = "pb::UndelegateClaim")]
pub struct UndelegateClaim {
    pub body: UndelegateClaimBody,
    pub proof: UndelegateClaimProof,
}

impl EffectingData for UndelegateClaimBody {
    fn effect_hash(&self) -> EffectHash {
        EffectHash::from_proto_effecting_data(&self.to_proto())
    }
}
impl EffectingData for UndelegateClaim {
    fn effect_hash(&self) -> EffectHash {
        // The effecting data is in the body of the undelegate claim, so we can
        // just use hash the proto-encoding of the body.
        self.body.effect_hash()
    }
}

impl DomainType for UndelegateClaimBody {
    type Proto = pb::UndelegateClaimBody;
}

impl From<UndelegateClaimBody> for pb::UndelegateClaimBody {
    #[allow(deprecated)]
    fn from(d: UndelegateClaimBody) -> Self {
        pb::UndelegateClaimBody {
            validator_identity: Some(d.validator_identity.into()),
            start_epoch_index: 0,
            penalty: Some(d.penalty.into()),
            balance_commitment: Some(d.balance_commitment.into()),
            unbonding_start_height: d.unbonding_start_height,
        }
    }
}

impl TryFrom<pb::UndelegateClaimBody> for UndelegateClaimBody {
    type Error = anyhow::Error;
    fn try_from(d: pb::UndelegateClaimBody) -> Result<Self, Self::Error> {
        Ok(Self {
            validator_identity: d
                .validator_identity
                .ok_or_else(|| anyhow::anyhow!("missing validator identity"))?
                .try_into()?,
            penalty: d
                .penalty
                .ok_or_else(|| anyhow::anyhow!("missing penalty"))?
                .try_into()?,
            balance_commitment: d
                .balance_commitment
                .ok_or_else(|| anyhow::anyhow!("missing balance_commitment"))?
                .try_into()?,
            unbonding_start_height: d.unbonding_start_height,
        })
    }
}

impl DomainType for UndelegateClaim {
    type Proto = pb::UndelegateClaim;
}

impl From<UndelegateClaim> for pb::UndelegateClaim {
    fn from(d: UndelegateClaim) -> Self {
        pb::UndelegateClaim {
            body: Some(d.body.into()),
            proof: d.proof.encode_to_vec(),
        }
    }
}

impl TryFrom<pb::UndelegateClaim> for UndelegateClaim {
    type Error = anyhow::Error;
    fn try_from(d: pb::UndelegateClaim) -> Result<Self, Self::Error> {
        Ok(Self {
            body: d
                .body
                .ok_or_else(|| anyhow::anyhow!("missing body"))?
                .try_into()?,
            proof: UndelegateClaimProof::decode(d.proof.as_slice())?,
        })
    }
}