penumbra_sdk_stake/
governance_key.rs

1use penumbra_sdk_proto::{
2    // TODO: why is the governance key part of this crate?
3    core::keys::v1 as pb,
4    serializers::bech32str::{self, validator_governance_key::BECH32_PREFIX},
5    DomainType,
6};
7use serde::{Deserialize, Serialize};
8
9use decaf377_rdsa::{SpendAuth, VerificationKey};
10
11/// The root of a validator's governance identity (which may be distinct from its main identity, to
12/// allow cold storage of validator keys).
13///
14/// This key is a [`SpendAuth`] [`VerificationKey`]; currently, the wallet software reuses an
15/// account's spend authorization key as the identity key and also as the governance key, but there
16/// is no real requirement that it must be generated that way.
17///
18/// Using a [`SpendAuth`] key means that validators can reuse code and processes designed for
19/// custodying funds to protect their identity.
20#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
21#[serde(try_from = "pb::GovernanceKey", into = "pb::GovernanceKey")]
22pub struct GovernanceKey(pub VerificationKey<SpendAuth>);
23
24impl std::str::FromStr for GovernanceKey {
25    type Err = anyhow::Error;
26    fn from_str(s: &str) -> Result<Self, Self::Err> {
27        pb::GovernanceKey {
28            gk: bech32str::decode(s, BECH32_PREFIX, bech32str::Bech32m)?,
29        }
30        .try_into()
31    }
32}
33
34impl std::fmt::Display for GovernanceKey {
35    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36        f.write_str(&bech32str::encode(
37            &self.0.to_bytes(),
38            BECH32_PREFIX,
39            bech32str::Bech32m,
40        ))
41    }
42}
43
44impl std::fmt::Debug for GovernanceKey {
45    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46        <GovernanceKey as std::fmt::Display>::fmt(self, f)
47    }
48}
49
50impl DomainType for GovernanceKey {
51    type Proto = pb::GovernanceKey;
52}
53
54impl From<GovernanceKey> for pb::GovernanceKey {
55    fn from(gk: GovernanceKey) -> Self {
56        pb::GovernanceKey {
57            gk: gk.0.to_bytes().to_vec(),
58        }
59    }
60}
61
62impl TryFrom<pb::GovernanceKey> for GovernanceKey {
63    type Error = anyhow::Error;
64    fn try_from(gk: pb::GovernanceKey) -> Result<Self, Self::Error> {
65        Ok(Self(gk.gk.as_slice().try_into()?))
66    }
67}