solana_account_decoder/
parse_nonce.rs

1use {
2    crate::{parse_account_data::ParseAccountError, UiFeeCalculator},
3    solana_sdk::{
4        instruction::InstructionError,
5        nonce::{state::Versions, State},
6    },
7};
8
9pub fn parse_nonce(data: &[u8]) -> Result<UiNonceState, ParseAccountError> {
10    let nonce_versions: Versions = bincode::deserialize(data)
11        .map_err(|_| ParseAccountError::from(InstructionError::InvalidAccountData))?;
12    match nonce_versions.state() {
13        // This prevents parsing an allocated System-owned account with empty data of any non-zero
14        // length as `uninitialized` nonce. An empty account of the wrong length can never be
15        // initialized as a nonce account, and an empty account of the correct length may not be an
16        // uninitialized nonce account, since it can be assigned to another program.
17        State::Uninitialized => Err(ParseAccountError::from(
18            InstructionError::InvalidAccountData,
19        )),
20        State::Initialized(data) => Ok(UiNonceState::Initialized(UiNonceData {
21            authority: data.authority.to_string(),
22            blockhash: data.blockhash().to_string(),
23            fee_calculator: data.fee_calculator.into(),
24        })),
25    }
26}
27
28/// A duplicate representation of NonceState for pretty JSON serialization
29#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
30#[serde(rename_all = "camelCase", tag = "type", content = "info")]
31pub enum UiNonceState {
32    Uninitialized,
33    Initialized(UiNonceData),
34}
35
36#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
37#[serde(rename_all = "camelCase")]
38pub struct UiNonceData {
39    pub authority: String,
40    pub blockhash: String,
41    pub fee_calculator: UiFeeCalculator,
42}
43
44#[cfg(test)]
45mod test {
46    use {
47        super::*,
48        solana_sdk::{
49            hash::Hash,
50            nonce::{
51                state::{Data, Versions},
52                State,
53            },
54            pubkey::Pubkey,
55        },
56    };
57
58    #[test]
59    fn test_parse_nonce() {
60        let nonce_data = Versions::new(State::Initialized(Data::default()));
61        let nonce_account_data = bincode::serialize(&nonce_data).unwrap();
62        assert_eq!(
63            parse_nonce(&nonce_account_data).unwrap(),
64            UiNonceState::Initialized(UiNonceData {
65                authority: Pubkey::default().to_string(),
66                blockhash: Hash::default().to_string(),
67                fee_calculator: UiFeeCalculator {
68                    lamports_per_signature: 0.to_string(),
69                },
70            }),
71        );
72
73        let bad_data = vec![0; 4];
74        assert!(parse_nonce(&bad_data).is_err());
75    }
76}