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 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
use crate::cfg_client;
use crate::prelude::*;
use std::cell::Ref;
#[derive(Copy, Clone, AnchorSerialize, AnchorDeserialize)]
pub enum OracleResponseType {
TypeSuccess,
TypeError,
TypeDisagreement,
TypeNoResponse,
}
#[zero_copy(unsafe)]
#[derive(Default)]
#[repr(packed)]
pub struct OracleMetrics {
/// Number of consecutive successful update request.
pub consecutive_success: u64,
/// Number of consecutive update request that resulted in an error.
pub consecutive_error: u64,
/// Number of consecutive update request that resulted in a disagreement with the accepted median result.
pub consecutive_disagreement: u64,
/// Number of consecutive update request that were posted on-chain late and not included in an accepted result.
pub consecutive_late_response: u64,
/// Number of consecutive update request that resulted in a failure.
pub consecutive_failure: u64,
/// Total number of successful update request.
pub total_success: u128,
/// Total number of update request that resulted in an error.
pub total_error: u128,
/// Total number of update request that resulted in a disagreement with the accepted median result.
pub total_disagreement: u128,
/// Total number of update request that were posted on-chain late and not included in an accepted result.
pub total_late_response: u128,
}
#[account(zero_copy(unsafe))]
#[repr(packed)]
pub struct OracleAccountData {
/// Name of the oracle to store on-chain.
pub name: [u8; 32],
/// Metadata of the oracle to store on-chain.
pub metadata: [u8; 128],
/// The account delegated as the authority for making account changes or withdrawing funds from a staking wallet.
pub oracle_authority: Pubkey,
/// Unix timestamp when the oracle last heartbeated
pub last_heartbeat: i64,
/// Flag dictating if an oracle is active and has heartbeated before the queue's oracle timeout parameter.
pub num_in_use: u32,
// Must be unique per oracle account and authority should be a pda
/// Stake account and reward/slashing wallet.
pub token_account: Pubkey,
/// Public key of the oracle queue who has granted it permission to use its resources.
pub queue_pubkey: Pubkey,
/// Oracle track record.
pub metrics: OracleMetrics,
/// The PDA bump to derive the pubkey.
pub bump: u8,
/// Reserved for future info.
pub _ebuf: [u8; 255],
}
impl OracleAccountData {
pub fn size() -> usize {
8 + std::mem::size_of::<OracleAccountData>()
}
/// Returns the deserialized Switchboard Oracle account
///
/// # Arguments
///
/// * `account_info` - A Solana AccountInfo referencing an existing Switchboard Oracle
///
/// # Examples
///
/// ```ignore
/// use switchboard_solana::OracleAccountData;
///
/// let oracle = OracleAccountData::new(oracle_account_info)?;
/// ```
pub fn new<'info>(
account_info: &'info AccountInfo<'info>,
) -> anchor_lang::Result<Ref<'info, Self>> {
let data = account_info.try_borrow_data()?;
if data.len() < OracleAccountData::discriminator().len() {
return Err(ErrorCode::AccountDiscriminatorNotFound.into());
}
let mut disc_bytes = [0u8; 8];
disc_bytes.copy_from_slice(&data[..8]);
if disc_bytes != OracleAccountData::discriminator() {
return Err(ErrorCode::AccountDiscriminatorMismatch.into());
}
Ok(Ref::map(data, |data| {
bytemuck::from_bytes(&data[8..std::mem::size_of::<OracleAccountData>() + 8])
}))
}
/// Returns the deserialized Switchboard Oracle account
///
/// # Arguments
///
/// * `data` - A Solana AccountInfo's data buffer
///
/// # Examples
///
/// ```ignore
/// use switchboard_solana::OracleAccountData;
///
/// let oracle = OracleAccountData::new(oracle_account_info.try_borrow_data()?)?;
/// ```
pub fn new_from_bytes(data: &[u8]) -> anchor_lang::Result<&OracleAccountData> {
if data.len() < OracleAccountData::discriminator().len() {
return Err(ErrorCode::AccountDiscriminatorNotFound.into());
}
let mut disc_bytes = [0u8; 8];
disc_bytes.copy_from_slice(&data[..8]);
if disc_bytes != OracleAccountData::discriminator() {
return Err(ErrorCode::AccountDiscriminatorMismatch.into());
}
Ok(bytemuck::from_bytes(
&data[8..std::mem::size_of::<OracleAccountData>() + 8],
))
}
cfg_client! {
pub fn fetch(
client: &solana_client::rpc_client::RpcClient,
pubkey: Pubkey,
) -> std::result::Result<Self, switchboard_common::SbError> {
crate::client::fetch_zerocopy_account(client, pubkey)
}
pub async fn fetch_async(
client: &solana_client::nonblocking::rpc_client::RpcClient,
pubkey: Pubkey,
) -> std::result::Result<Self, switchboard_common::SbError> {
crate::client::fetch_zerocopy_account_async(client, pubkey).await
}
pub fn fetch_sync<T: solana_sdk::client::SyncClient>(
client: &T,
pubkey: Pubkey,
) -> std::result::Result<Self, switchboard_common::SbError> {
crate::client::fetch_zerocopy_account_sync(client, pubkey)
}
}
}