solana_account_decoder/
parse_nonce.rs

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