1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
use crate::prelude::*;

#[account]
#[derive(Default)]
pub struct BufferRelayerAccountData {
    /// Name of the buffer account to store on-chain.
    pub name: [u8; 32],
    /// Public key of the OracleQueueAccountData that is currently assigned to fulfill buffer relayer update request.
    pub queue_pubkey: Pubkey,
    /// Token account to reward oracles for completing update request.
    pub escrow: Pubkey,
    /// The account delegated as the authority for making account changes.
    pub authority: Pubkey,
    /// Public key of the JobAccountData that defines how the buffer relayer is updated.
    pub job_pubkey: Pubkey,
    /// Used to protect against malicious RPC nodes providing incorrect task definitions to oracles before fulfillment
    pub job_hash: [u8; 32],
    /// Minimum delay between update request.
    pub min_update_delay_seconds: u32,
    /// Whether buffer relayer config is locked for further changes.
    pub is_locked: bool,
    /// The current buffer relayer update round that is yet to be confirmed.
    pub current_round: BufferRelayerRound,
    /// The latest confirmed buffer relayer update round.
    pub latest_confirmed_round: BufferRelayerRound,
    /// The buffer holding the latest confirmed result.
    pub result: Vec<u8>,
}

#[derive(Default, Clone, AnchorSerialize, AnchorDeserialize)]
pub struct BufferRelayerRound {
    /// Number of successful responses.
    pub num_success: u32,
    /// Number of error responses.
    pub num_error: u32,
    /// Slot when the buffer relayer round was opened.
    pub round_open_slot: u64,
    /// Timestamp when the buffer relayer round was opened.
    pub round_open_timestamp: i64,
    /// The public key of the oracle fulfilling the buffer relayer update request.
    pub oracle_pubkey: Pubkey,
}

impl BufferRelayerAccountData {
    /// Returns the deserialized Switchboard Buffer Relayer account
    ///
    /// # Arguments
    ///
    /// * `switchboard_buffer` - A Solana AccountInfo referencing an existing Switchboard BufferRelayer
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use switchboard_solana::BufferRelayerAccountData;
    ///
    /// let buffer_account = BufferRelayerAccountData::new(buffer_account_info)?;
    /// ```
    pub fn new(
        switchboard_buffer: &AccountInfo,
    ) -> anchor_lang::Result<Box<BufferRelayerAccountData>> {
        let data = switchboard_buffer.try_borrow_data()?;

        let mut disc_bytes = [0u8; 8];
        disc_bytes.copy_from_slice(&data[..8]);
        if disc_bytes != BufferRelayerAccountData::discriminator() {
            return Err(SwitchboardError::AccountDiscriminatorMismatch.into());
        }

        let mut v_mut = &data[8..];
        Ok(Box::new(BufferRelayerAccountData::deserialize(&mut v_mut)?))
    }

    pub fn get_result(&self) -> &Vec<u8> {
        &self.result
    }

    /// Check whether the buffer relayer has been updated in the last max_staleness seconds
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use switchboard_solana::BufferRelayerAccountData;
    ///
    /// let buffer = BufferRelayerAccountData::new(buffer_account_info)?;
    /// buffer.check_staleness(clock::Clock::get().unwrap().unix_timestamp, 300)?;
    /// ```
    pub fn check_staleness(
        &self,
        unix_timestamp: i64,
        max_staleness: i64,
    ) -> anchor_lang::Result<()> {
        let staleness = unix_timestamp - self.latest_confirmed_round.round_open_timestamp;
        if staleness > max_staleness {
            msg!("Feed has not been updated in {} seconds!", staleness);
            return Err(SwitchboardError::StaleFeed.into());
        }
        Ok(())
    }
}