solana_account_decoder/
parse_nonce.rs

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