Skip to main content

sof_types/
pubkey.rs

1use std::fmt;
2
3use serde::{Deserialize, Serialize};
4
5use crate::base58::DecodeBase58Error;
6
7/// Length in bytes of one validator identity / account key.
8pub const PUBKEY_BYTES: usize = 32;
9
10/// Stable SOF-owned 32-byte validator identity / account key wrapper.
11#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
12pub struct PubkeyBytes([u8; PUBKEY_BYTES]);
13
14impl PubkeyBytes {
15    /// Creates one wrapper from raw bytes.
16    #[must_use]
17    pub const fn new(bytes: [u8; PUBKEY_BYTES]) -> Self {
18        Self(bytes)
19    }
20
21    /// Returns the inner fixed-width byte array by value.
22    #[must_use]
23    pub const fn into_array(self) -> [u8; PUBKEY_BYTES] {
24        self.0
25    }
26
27    /// Returns the inner fixed-width byte array by reference.
28    #[must_use]
29    pub const fn as_array(&self) -> &[u8; PUBKEY_BYTES] {
30        &self.0
31    }
32
33    /// Decodes one base58-encoded pubkey string.
34    ///
35    /// # Errors
36    ///
37    /// Returns [`DecodeBase58Error`] when the string is not valid base58 or has the wrong width.
38    pub fn from_base58(value: &str) -> Result<Self, DecodeBase58Error> {
39        let decoded =
40            bs58::decode(value)
41                .into_vec()
42                .map_err(|error| DecodeBase58Error::InvalidBase58 {
43                    message: error.to_string(),
44                })?;
45        let bytes: [u8; PUBKEY_BYTES] =
46            decoded
47                .try_into()
48                .map_err(|decoded: Vec<u8>| DecodeBase58Error::WrongLength {
49                    expected: PUBKEY_BYTES,
50                    actual: decoded.len(),
51                })?;
52        Ok(Self(bytes))
53    }
54
55    /// Encodes this pubkey as a base58 string.
56    #[must_use]
57    pub fn to_base58(self) -> String {
58        bs58::encode(self.0).into_string()
59    }
60}
61
62impl From<[u8; PUBKEY_BYTES]> for PubkeyBytes {
63    fn from(value: [u8; PUBKEY_BYTES]) -> Self {
64        Self::new(value)
65    }
66}
67
68impl From<PubkeyBytes> for [u8; PUBKEY_BYTES] {
69    fn from(value: PubkeyBytes) -> Self {
70        value.into_array()
71    }
72}
73
74impl fmt::Display for PubkeyBytes {
75    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76        f.write_str(&self.to_base58())
77    }
78}
79
80#[cfg(feature = "solana-compat")]
81impl PubkeyBytes {
82    /// Converts one Solana pubkey into the SOF-owned wrapper.
83    #[must_use]
84    pub const fn from_solana(value: solana_pubkey::Pubkey) -> Self {
85        Self::new(value.to_bytes())
86    }
87
88    /// Converts this SOF-owned wrapper into one Solana pubkey.
89    #[must_use]
90    pub const fn to_solana(self) -> solana_pubkey::Pubkey {
91        solana_pubkey::Pubkey::new_from_array(self.into_array())
92    }
93}
94
95#[cfg(feature = "solana-compat")]
96impl From<solana_pubkey::Pubkey> for PubkeyBytes {
97    fn from(value: solana_pubkey::Pubkey) -> Self {
98        Self::from_solana(value)
99    }
100}
101
102#[cfg(feature = "solana-compat")]
103impl From<PubkeyBytes> for solana_pubkey::Pubkey {
104    fn from(value: PubkeyBytes) -> Self {
105        value.to_solana()
106    }
107}