refactor init/add oracle/remove oracle
This commit is contained in:
parent
d45b362dc6
commit
c3c5028ff1
|
@ -0,0 +1,77 @@
|
|||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
|
||||
use solana_program::{
|
||||
program_error::ProgramError,
|
||||
program_pack::IsInitialized,
|
||||
account_info::AccountInfo,
|
||||
entrypoint::ProgramResult,
|
||||
sysvar::rent::Rent,
|
||||
msg,
|
||||
};
|
||||
|
||||
|
||||
pub trait BorshState: BorshDeserialize + BorshSerialize {
|
||||
fn load(account: &AccountInfo) -> Result<Self, ProgramError> {
|
||||
let data = (*account.data).borrow();
|
||||
Self::try_from_slice(&data).map_err(|_| ProgramError::InvalidAccountData)
|
||||
}
|
||||
|
||||
fn save(&self, account: &AccountInfo) -> ProgramResult {
|
||||
let data = self.try_to_vec().map_err(|_| ProgramError::InvalidAccountData)?;
|
||||
|
||||
// FIXME: looks like there is association precedence issue that prevents
|
||||
// RefMut from being automatically dereferenced.
|
||||
//
|
||||
// let dst = &mut account.data.borrow_mut();
|
||||
//
|
||||
// Why does it work in an SPL token program though?
|
||||
//
|
||||
// Account::pack(source_account, &mut source_account_info.data.borrow_mut())?;
|
||||
let mut dst = (*account.data).borrow_mut();
|
||||
if dst.len() != data.len() {
|
||||
return Err(ProgramError::InvalidAccountData);
|
||||
}
|
||||
dst.copy_from_slice(&data);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn save_exempt(&self, account: &AccountInfo, rent: &Rent) -> ProgramResult {
|
||||
let data = self.try_to_vec().map_err(|_| ProgramError::InvalidAccountData)?;
|
||||
|
||||
if !rent.is_exempt(account.lamports(), data.len()) {
|
||||
// FIXME: return a custom error
|
||||
return Err(ProgramError::InvalidAccountData);
|
||||
}
|
||||
|
||||
let mut dst = (*account.data).borrow_mut();
|
||||
if dst.len() != data.len() {
|
||||
// FIXME: return a custom error
|
||||
return Err(ProgramError::InvalidAccountData);
|
||||
}
|
||||
dst.copy_from_slice(&data);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait InitBorshState: BorshState + IsInitialized {
|
||||
// type Self = IsInitialized
|
||||
fn load_initialized(account: &AccountInfo) -> Result<Self, ProgramError> {
|
||||
let object = Self::load(account)?;
|
||||
if !object.is_initialized() {
|
||||
return Err(ProgramError::UninitializedAccount);
|
||||
}
|
||||
|
||||
Ok(object)
|
||||
}
|
||||
|
||||
fn init_uninitialized(account: &AccountInfo) -> Result<Self, ProgramError> {
|
||||
let object = Self::load(account)?;
|
||||
if object.is_initialized() {
|
||||
return Err(ProgramError::AccountAlreadyInitialized);
|
||||
}
|
||||
|
||||
Ok(object)
|
||||
}
|
||||
}
|
|
@ -1,17 +1,8 @@
|
|||
//! Instruction types
|
||||
|
||||
// use crate::error::Error;
|
||||
#![allow(dead_code)]
|
||||
|
||||
use solana_program::{
|
||||
instruction::{AccountMeta, Instruction as SolInstruction},
|
||||
program_error::ProgramError,
|
||||
program_pack::{Pack, Sealed},
|
||||
pubkey::Pubkey,
|
||||
sysvar,
|
||||
};
|
||||
use crate::state::{AggregatorConfig};
|
||||
|
||||
// use std::convert::TryInto;
|
||||
use borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
|
||||
|
||||
/// Maximum number of oracles
|
||||
|
@ -24,47 +15,17 @@ pub const PAYMENT_AMOUNT: u64 = 10;
|
|||
#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, BorshSchema, PartialEq)]
|
||||
pub enum Instruction {
|
||||
/// Initializes a new Aggregator
|
||||
///
|
||||
/// Accounts expected by this instruction:
|
||||
///
|
||||
/// 0. `[]` Rent sysvar
|
||||
/// 1. `[writable]` The aggregator.
|
||||
/// 2. `[signer]` The aggregator's authority.
|
||||
Initialize {
|
||||
/// The interval(seconds) of an oracle's each submission
|
||||
submit_interval: u32,
|
||||
/// min submission value
|
||||
min_submission_value: u64,
|
||||
/// max submission value
|
||||
max_submission_value: u64,
|
||||
/// submission decimals
|
||||
submission_decimals: u8,
|
||||
/// A short description of what is being reported
|
||||
description: [u8; 32],
|
||||
config: AggregatorConfig,
|
||||
},
|
||||
|
||||
/// Add an oracle
|
||||
///
|
||||
/// Accounts expected by this instruction:
|
||||
/// 0. `[writable]` The oracle
|
||||
/// 1. `[]` The oracle owner
|
||||
/// 2. `[]` Clock sysvar
|
||||
/// 3. `[writable]` The aggregator
|
||||
/// 4. `[signer]` The aggregator owner
|
||||
AddOracle {
|
||||
/// Is usually the oracle name
|
||||
description: [u8; 32],
|
||||
},
|
||||
|
||||
/// Remove an oracle
|
||||
///
|
||||
/// Accounts expected by this instruction:
|
||||
/// 0. `[writable]` The aggregator.
|
||||
/// 1. `[signer]` The aggregator onwer.
|
||||
RemoveOracle {
|
||||
/// the oracle pubkey
|
||||
pubkey: [u8; 32],
|
||||
},
|
||||
RemoveOracle,
|
||||
|
||||
/// Called by oracles when they have witnessed a need to update
|
||||
///
|
||||
|
@ -94,158 +55,3 @@ pub enum Instruction {
|
|||
seed: [u8; 32],
|
||||
},
|
||||
}
|
||||
|
||||
// impl Sealed for Instruction {}
|
||||
// impl Pack for Instruction {
|
||||
// const LEN: usize = 54;
|
||||
|
||||
// fn pack_into_slice(&self, dst: &mut [u8]) {
|
||||
// let data = self.pack_into_vec();
|
||||
// dst[..data.len()].copy_from_slice(&data);
|
||||
// }
|
||||
|
||||
// fn unpack_from_slice(src: &[u8]) -> Result<Self, ProgramError> {
|
||||
// let mut mut_src: &[u8] = src;
|
||||
// Self::deserialize(&mut mut_src).map_err(|_| ProgramError::InvalidInstructionData)
|
||||
// }
|
||||
// }
|
||||
|
||||
impl Instruction {
|
||||
fn pack_into_vec(&self) -> Vec<u8> {
|
||||
self.try_to_vec().expect("try_to_vec")
|
||||
}
|
||||
}
|
||||
|
||||
// /// Creates a `add_oracle` instruction
|
||||
// pub fn add_oracle(
|
||||
// program_id: &Pubkey,
|
||||
// oracle_pubkey: &Pubkey,
|
||||
// oracle_owner_pubkey: &Pubkey,
|
||||
// aggregator_pubkey: &Pubkey,
|
||||
// aggregator_owner_pubkey: &Pubkey,
|
||||
// description: [u8; 32],
|
||||
// ) -> SolInstruction {
|
||||
// let accounts = vec![
|
||||
// AccountMeta::new(*oracle_pubkey, false),
|
||||
// AccountMeta::new(*oracle_owner_pubkey, false),
|
||||
// AccountMeta::new_readonly(sysvar::clock::id(), false),
|
||||
// AccountMeta::new(*aggregator_pubkey, false),
|
||||
// AccountMeta::new_readonly(*aggregator_owner_pubkey, true),
|
||||
// ];
|
||||
|
||||
// SolInstruction {
|
||||
// program_id: *program_id,
|
||||
// accounts,
|
||||
// data: Instruction::AddOracle { description }.pack_into_vec(),
|
||||
// }
|
||||
// }
|
||||
|
||||
// /// Creates a `remove_oracle` instruction
|
||||
// pub fn remove_oracle(
|
||||
// program_id: &Pubkey,
|
||||
// aggregator_pubkey: &Pubkey,
|
||||
// aggregator_owner_pubkey: &Pubkey,
|
||||
// pubkey: &Pubkey,
|
||||
// ) -> SolInstruction {
|
||||
// let accounts = vec![
|
||||
// AccountMeta::new(*aggregator_pubkey, false),
|
||||
// AccountMeta::new_readonly(*aggregator_owner_pubkey, true),
|
||||
// ];
|
||||
|
||||
// SolInstruction {
|
||||
// program_id: *program_id,
|
||||
// accounts,
|
||||
// data: Instruction::RemoveOracle {
|
||||
// pubkey: pubkey.to_bytes(),
|
||||
// }
|
||||
// .pack_into_vec(),
|
||||
// }
|
||||
// }
|
||||
|
||||
// /// Creates a `submit` instruction
|
||||
// pub fn submit(
|
||||
// program_id: &Pubkey,
|
||||
// aggregator_pubkey: &Pubkey,
|
||||
// oracle_pubkey: &Pubkey,
|
||||
// oracle_owner_pubkey: &Pubkey,
|
||||
// submission: u64,
|
||||
// ) -> SolInstruction {
|
||||
// let accounts = vec![
|
||||
// AccountMeta::new(*aggregator_pubkey, false),
|
||||
// AccountMeta::new_readonly(sysvar::clock::id(), false),
|
||||
// AccountMeta::new(*oracle_pubkey, false),
|
||||
// AccountMeta::new_readonly(*oracle_owner_pubkey, true),
|
||||
// ];
|
||||
|
||||
// SolInstruction {
|
||||
// program_id: *program_id,
|
||||
// accounts,
|
||||
// data: Instruction::Submit { submission }.pack_into_vec(),
|
||||
// }
|
||||
// }
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use solana_program::{
|
||||
entrypoint::ProgramResult,
|
||||
};
|
||||
use crate::borsh_utils;
|
||||
use hex;
|
||||
|
||||
// #[test]
|
||||
// fn test_get_packed_len() {
|
||||
// assert_eq!(
|
||||
// Instruction::get_packed_len(),
|
||||
// borsh_utils::get_packed_len::<Instruction>()
|
||||
// )
|
||||
// }
|
||||
|
||||
#[test]
|
||||
fn test_serialize_bytes() -> ProgramResult {
|
||||
// let test_instruction = Instruction::Initialize {
|
||||
// submit_interval: 0x11221122,
|
||||
// min_submission_value: 0xaabbaabbaabbaabb,
|
||||
// max_submission_value: 0xccddccddccddccdd,
|
||||
// submission_decimals: 6,
|
||||
// description: [0xff; 32],
|
||||
// };
|
||||
|
||||
// let bytes = test_instruction.try_to_vec()?;
|
||||
|
||||
// assert_eq!(
|
||||
// "0022112211bbaabbaabbaabbaaddccddccddccddcc06ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
// hex::encode(bytes),
|
||||
// );
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn state_deserialize_invalid() -> ProgramResult {
|
||||
// assert_eq!(
|
||||
// Instruction::unpack_from_slice(&hex::decode("0022112211bbaabbaabbaabbaaddccddccddccddcc06ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")?),
|
||||
// Ok(Instruction::Initialize {
|
||||
// submit_interval: 0x11221122,
|
||||
// min_submission_value: 0xaabbaabbaabbaabb,
|
||||
// max_submission_value: 0xccddccddccddccdd,
|
||||
// submission_decimals: 6,
|
||||
// description: [0xff; 32],
|
||||
// }),
|
||||
// );
|
||||
|
||||
// assert_eq!(
|
||||
// Instruction::unpack_from_slice(&[
|
||||
// 4,
|
||||
// 15, 39, 0, 0, 0, 0, 0, 0,
|
||||
// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
|
||||
// ]),
|
||||
// Ok(Instruction::Withdraw {
|
||||
// amount: 9999u64,
|
||||
// seed: [1u8; 32],
|
||||
// }),
|
||||
// );
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ pub mod error;
|
|||
pub mod instruction;
|
||||
pub mod processor;
|
||||
pub mod state;
|
||||
pub mod borsh_state;
|
||||
|
||||
#[cfg(not(feature = "no-entrypoint"))]
|
||||
pub mod entrypoint;
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
//! Program state processor
|
||||
|
||||
use crate::{
|
||||
error::Error,
|
||||
instruction::{Instruction, PAYMENT_AMOUNT},
|
||||
state::{Aggregator, Oracle, BorshState},
|
||||
};
|
||||
use crate::{error::Error, instruction::{Instruction, PAYMENT_AMOUNT}, state::{Aggregator, AggregatorConfig, Oracle}};
|
||||
|
||||
use solana_program::{
|
||||
account_info::{next_account_info, AccountInfo},
|
||||
|
@ -18,6 +14,8 @@ use solana_program::{
|
|||
sysvar::{rent::Rent, Sysvar},
|
||||
};
|
||||
|
||||
use crate::borsh_state::{InitBorshState, BorshState};
|
||||
|
||||
use borsh::BorshDeserialize;
|
||||
|
||||
struct Accounts<'a, 'b>(&'a [AccountInfo<'b>]);
|
||||
|
@ -39,35 +37,83 @@ struct InitializeContext<'a> {
|
|||
aggregator: &'a AccountInfo<'a>,
|
||||
owner: &'a AccountInfo<'a>,
|
||||
|
||||
submit_interval: u32,
|
||||
min_submission_value: u64,
|
||||
max_submission_value: u64,
|
||||
submission_decimals: u8,
|
||||
description: [u8; 32],
|
||||
config: AggregatorConfig,
|
||||
}
|
||||
|
||||
impl <'a>InitializeContext<'a> {
|
||||
fn process(&self) -> ProgramResult {
|
||||
|
||||
if !self.owner.is_signer {
|
||||
return Err(ProgramError::MissingRequiredSignature);
|
||||
}
|
||||
|
||||
let mut aggregator = Aggregator::load(self.aggregator)?;
|
||||
let mut aggregator = Aggregator::init_uninitialized(self.aggregator)?;
|
||||
aggregator.is_initialized = true;
|
||||
aggregator.config = self.config.clone();
|
||||
aggregator.owner = self.owner.key.to_bytes();
|
||||
aggregator.save_exempt(self.aggregator, &self.rent)?;
|
||||
|
||||
if aggregator.is_initialized {
|
||||
return Err(Error::AlreadyInUse)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct AddOracleContext<'a> {
|
||||
rent: Rent,
|
||||
aggregator: &'a AccountInfo<'a>,
|
||||
aggregator_owner: &'a AccountInfo<'a>, // signed
|
||||
oracle: &'a AccountInfo<'a>,
|
||||
oracle_owner: &'a AccountInfo<'a>,
|
||||
|
||||
description: [u8; 32],
|
||||
}
|
||||
|
||||
impl <'a>AddOracleContext<'a> {
|
||||
fn process(&self) -> ProgramResult {
|
||||
// Note: there can in fact be more oracles than max_submissions
|
||||
if !self.aggregator_owner.is_signer {
|
||||
return Err(ProgramError::MissingRequiredSignature);
|
||||
}
|
||||
|
||||
aggregator.submit_interval = self.submit_interval;
|
||||
aggregator.min_submission_value = self.min_submission_value;
|
||||
aggregator.max_submission_value = self.max_submission_value;
|
||||
aggregator.submission_decimals = self.submission_decimals;
|
||||
aggregator.description = self.description;
|
||||
aggregator.is_initialized = true;
|
||||
aggregator.owner = self.owner.key.to_bytes();
|
||||
let aggregator = Aggregator::load_initialized(self.aggregator)?;
|
||||
if aggregator.owner != self.aggregator_owner.key.to_bytes() {
|
||||
return Err(Error::OwnerMismatch)?;
|
||||
}
|
||||
|
||||
aggregator.save_exempt(self.aggregator, &self.rent)?;
|
||||
let mut oracle = Oracle::init_uninitialized(self.oracle)?;
|
||||
oracle.is_initialized = true;
|
||||
oracle.description = self.description;
|
||||
oracle.owner = self.oracle_owner.key.to_bytes();
|
||||
oracle.aggregator = self.aggregator.key.to_bytes();
|
||||
oracle.save_exempt(self.oracle, &self.rent)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct RemoveOracleContext<'a> {
|
||||
aggregator: &'a AccountInfo<'a>,
|
||||
aggregator_owner: &'a AccountInfo<'a>, // signed
|
||||
oracle: &'a AccountInfo<'a>,
|
||||
}
|
||||
|
||||
impl <'a>RemoveOracleContext<'a> {
|
||||
fn process(&self) -> ProgramResult {
|
||||
if !self.aggregator_owner.is_signer {
|
||||
return Err(ProgramError::MissingRequiredSignature);
|
||||
}
|
||||
|
||||
let aggregator = Aggregator::load_initialized(self.aggregator)?;
|
||||
if aggregator.owner != self.aggregator_owner.key.to_bytes() {
|
||||
return Err(Error::OwnerMismatch)?;
|
||||
}
|
||||
|
||||
let oracle = Oracle::load_initialized(self.oracle)?;
|
||||
if oracle.aggregator != self.aggregator.key.to_bytes() {
|
||||
return Err(Error::OwnerMismatch)?;
|
||||
}
|
||||
|
||||
// Zero out the oracle account memory. This allows reuse or reclaim.
|
||||
// Note: will wipe out withdrawable balance on this oracle. Too bad.
|
||||
Oracle::default().save(self.oracle)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -83,36 +129,36 @@ impl Processor {
|
|||
|
||||
match instruction {
|
||||
Instruction::Initialize {
|
||||
submit_interval,
|
||||
min_submission_value,
|
||||
max_submission_value,
|
||||
submission_decimals,
|
||||
description,
|
||||
config,
|
||||
} => {
|
||||
InitializeContext {
|
||||
rent: accounts.get_rent(0)?,
|
||||
aggregator: accounts.get(1)?,
|
||||
owner: accounts.get(2)?,
|
||||
config,
|
||||
}.process()
|
||||
},
|
||||
Instruction::AddOracle { description } => {
|
||||
AddOracleContext {
|
||||
rent: accounts.get_rent(0)?,
|
||||
aggregator: accounts.get(1)?,
|
||||
aggregator_owner: accounts.get(2)?,
|
||||
oracle: accounts.get(3)?,
|
||||
oracle_owner: accounts.get(4)?,
|
||||
|
||||
submit_interval,
|
||||
min_submission_value,
|
||||
max_submission_value,
|
||||
submission_decimals,
|
||||
description,
|
||||
}.process()
|
||||
}
|
||||
},
|
||||
Instruction::RemoveOracle => {
|
||||
RemoveOracleContext {
|
||||
aggregator: accounts.get(0)?,
|
||||
aggregator_owner: accounts.get(1)?,
|
||||
oracle: accounts.get(2)?,
|
||||
}.process()
|
||||
},
|
||||
_ => {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Instruction::AddOracle { description } => {
|
||||
// msg!("Instruction: AddOracle");
|
||||
// Self::process_add_oracle(accounts, description)
|
||||
// }
|
||||
// Instruction::RemoveOracle { pubkey } => {
|
||||
// msg!("Instruction: RemoveOracle");
|
||||
// Self::process_remove_oracle(accounts, pubkey)
|
||||
// }
|
||||
// Instruction::Submit { submission } => {
|
||||
// msg!("Instruction: Submit");
|
||||
// Self::process_submit(accounts, submission)
|
||||
|
@ -124,150 +170,6 @@ impl Processor {
|
|||
}
|
||||
}
|
||||
|
||||
// Processes an [Initialize](enum.Instruction.html) instruction.
|
||||
|
||||
// pub fn process_initialize(
|
||||
// _program_id: &Pubkey,
|
||||
// accounts: &[AccountInfo],
|
||||
// submit_interval: u32,
|
||||
// min_submission_value: u64,
|
||||
// max_submission_value: u64,
|
||||
// submission_decimals: u8,
|
||||
// description: [u8; 32],
|
||||
// ) -> ProgramResult {
|
||||
// let account_info_iter = &mut accounts.iter();
|
||||
|
||||
// let rent_info = next_account_info(account_info_iter)?;
|
||||
// let aggregator_info = next_account_info(account_info_iter)?;
|
||||
// let owner_info = next_account_info(account_info_iter)?;
|
||||
|
||||
// // check signer
|
||||
// if !owner_info.is_signer {
|
||||
// return Err(ProgramError::MissingRequiredSignature);
|
||||
// }
|
||||
|
||||
// let rent = &Rent::from_account_info(rent_info)?;
|
||||
|
||||
// let mut aggregator = Aggregator::unpack_unchecked(&aggregator_info.data.borrow())?;
|
||||
// if aggregator.is_initialized {
|
||||
// return Err(Error::AlreadyInUse.into());
|
||||
// }
|
||||
|
||||
// if !rent.is_exempt(aggregator_info.lamports(), aggregator_info.data_len()) {
|
||||
// return Err(Error::NotRentExempt.into());
|
||||
// }
|
||||
|
||||
// aggregator.submit_interval = submit_interval;
|
||||
// aggregator.min_submission_value = min_submission_value;
|
||||
// aggregator.max_submission_value = max_submission_value;
|
||||
// aggregator.submission_decimals = submission_decimals;
|
||||
// aggregator.description = description;
|
||||
// aggregator.is_initialized = true;
|
||||
// aggregator.owner = owner_info.key.to_bytes();
|
||||
|
||||
// Aggregator::pack(aggregator, &mut aggregator_info.data.borrow_mut())?;
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
// /// Processes an [AddOracle](enum.Instruction.html) instruction.
|
||||
// pub fn process_add_oracle(accounts: &[AccountInfo], description: [u8; 32]) -> ProgramResult {
|
||||
// let account_info_iter = &mut accounts.iter();
|
||||
// let oracle_info = next_account_info(account_info_iter)?;
|
||||
// let oracle_owner_info = next_account_info(account_info_iter)?;
|
||||
// let clock_sysvar_info = next_account_info(account_info_iter)?;
|
||||
// let aggregator_info = next_account_info(account_info_iter)?;
|
||||
// let aggregator_owner_info = next_account_info(account_info_iter)?;
|
||||
|
||||
// if !aggregator_owner_info.is_signer {
|
||||
// return Err(ProgramError::MissingRequiredSignature);
|
||||
// }
|
||||
|
||||
// let mut aggregator = Aggregator::unpack_unchecked(&aggregator_info.data.borrow())?;
|
||||
|
||||
// if !aggregator.is_initialized {
|
||||
// return Err(Error::NotFoundAggregator.into());
|
||||
// }
|
||||
|
||||
// if &Pubkey::new_from_array(aggregator.owner) != aggregator_owner_info.key {
|
||||
// return Err(Error::OwnerMismatch.into());
|
||||
// }
|
||||
|
||||
// let mut oracle = Oracle::unpack_unchecked(&oracle_info.data.borrow())?;
|
||||
// if oracle.is_initialized {
|
||||
// return Err(Error::AlreadyInUse.into());
|
||||
// }
|
||||
|
||||
// // sys clock
|
||||
// let clock = &Clock::from_account_info(clock_sysvar_info)?;
|
||||
|
||||
// let mut inserted = false;
|
||||
// for s in aggregator.submissions.iter_mut() {
|
||||
// if Pubkey::new_from_array(s.oracle) == Pubkey::default() {
|
||||
// inserted = true;
|
||||
// s.oracle = oracle_info.key.to_bytes();
|
||||
// break;
|
||||
// } else if &Pubkey::new_from_array(s.oracle) == oracle_info.key {
|
||||
// return Err(Error::OracleExist.into());
|
||||
// }
|
||||
// }
|
||||
|
||||
// if !inserted {
|
||||
// return Err(Error::MaxOralcesReached.into());
|
||||
// }
|
||||
|
||||
// Aggregator::pack(aggregator, &mut aggregator_info.data.borrow_mut())?;
|
||||
|
||||
// oracle.next_submit_time = clock.unix_timestamp;
|
||||
// oracle.description = description;
|
||||
// oracle.is_initialized = true;
|
||||
// oracle.withdrawable = 0;
|
||||
// oracle.aggregator = aggregator_info.key.to_bytes();
|
||||
// oracle.owner = oracle_owner_info.key.to_bytes();
|
||||
|
||||
// Oracle::pack(oracle, &mut oracle_info.data.borrow_mut())?;
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
// /// Processes an [RemoveOracle](enum.Instruction.html) instruction.
|
||||
// pub fn process_remove_oracle(accounts: &[AccountInfo], pubkey: [u8; 32]) -> ProgramResult {
|
||||
// let account_info_iter = &mut accounts.iter();
|
||||
// let aggregator_info = next_account_info(account_info_iter)?;
|
||||
// let owner_info = next_account_info(account_info_iter)?;
|
||||
|
||||
// if !owner_info.is_signer {
|
||||
// return Err(ProgramError::MissingRequiredSignature);
|
||||
// }
|
||||
|
||||
// let mut aggregator = Aggregator::unpack_unchecked(&aggregator_info.data.borrow())?;
|
||||
|
||||
// if !aggregator.is_initialized {
|
||||
// return Err(Error::NotFoundAggregator.into());
|
||||
// }
|
||||
|
||||
// if &Pubkey::new_from_array(aggregator.owner) != owner_info.key {
|
||||
// return Err(Error::OwnerMismatch.into());
|
||||
// }
|
||||
|
||||
// let mut found = false;
|
||||
// for s in aggregator.submissions.iter_mut() {
|
||||
// if s.oracle != Pubkey::default().to_bytes() && s.oracle == pubkey {
|
||||
// found = true;
|
||||
// s.oracle = Pubkey::default().to_bytes();
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// if !found {
|
||||
// return Err(Error::NotFoundOracle.into());
|
||||
// }
|
||||
|
||||
// Aggregator::pack(aggregator, &mut aggregator_info.data.borrow_mut())?;
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
// /// Processes an [Submit](enum.Instruction.html) instruction.
|
||||
// pub fn process_submit(accounts: &[AccountInfo], submission: u64) -> ProgramResult {
|
||||
// let account_info_iter = &mut accounts.iter();
|
||||
|
@ -408,379 +310,165 @@ mod tests {
|
|||
use super::*;
|
||||
|
||||
use borsh::BorshSerialize;
|
||||
// use crate::{instruction::*, state::Submission};
|
||||
use crate::borsh_utils;
|
||||
use crate::instruction;
|
||||
use solana_program::{instruction::Instruction, sysvar};
|
||||
use solana_program::{sysvar};
|
||||
|
||||
use solana_sdk::account::{
|
||||
create_account, Account,
|
||||
// create_is_signer_account_infos
|
||||
};
|
||||
// use solana_program::account_info::
|
||||
|
||||
// pub fn create_is_signer_account_infos<'a>(
|
||||
// mut accounts: Vec<(Pubkey, Account, bool)>,
|
||||
// ) -> Vec<AccountInfo<'a>> {
|
||||
pub fn create_is_signer_account_infos<'a>(
|
||||
accounts: &'a mut [(Pubkey, Account, bool)],
|
||||
) -> Vec<AccountInfo<'a>> {
|
||||
accounts
|
||||
.iter_mut()
|
||||
.map(|(key, account, is_signer)| {
|
||||
AccountInfo::new(
|
||||
key,
|
||||
*is_signer,
|
||||
false,
|
||||
&mut account.lamports,
|
||||
&mut account.data,
|
||||
&account.owner,
|
||||
account.executable,
|
||||
account.rent_epoch,
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
||||
fn process(
|
||||
// instruction: Instruction,
|
||||
// accounts: Vec<&mut SolanaAccount>,
|
||||
fn process<'a>(
|
||||
program_id: &Pubkey,
|
||||
input: &[u8],
|
||||
mut accounts: Vec<(Pubkey, Account, bool)>,
|
||||
ix: instruction::Instruction,
|
||||
accounts: &'a [AccountInfo<'a>],
|
||||
) -> ProgramResult {
|
||||
// let mut meta = accounts
|
||||
// .iter_mut()
|
||||
// .map(|(pubkey, account, signer)| (&pubkey, *signer, account))
|
||||
// .collect::<Vec<_>>();
|
||||
|
||||
// let account_infos = create_is_signer_account_infos(meta.as_mut_slice());
|
||||
let account_infos = create_is_signer_account_infos(&mut accounts);
|
||||
Processor::process(&program_id, &account_infos, input)
|
||||
let input = ix.try_to_vec().map_err(|_| ProgramError::InvalidAccountData)?;
|
||||
Processor::process(&program_id, accounts, &input)
|
||||
}
|
||||
|
||||
fn rent_sysvar() -> Account {
|
||||
create_account(&Rent::default(), 42)
|
||||
fn rent_sysvar() -> TSysAccount {
|
||||
TSysAccount(sysvar::rent::id(), create_account(&Rent::default(), 42))
|
||||
}
|
||||
|
||||
fn clock_sysvar() -> Account {
|
||||
create_account(&Clock::default(), 42)
|
||||
}
|
||||
|
||||
fn aggregator_minimum_balance() -> u64 {
|
||||
Rent::default().minimum_balance(borsh_utils::get_packed_len::<Aggregator>())
|
||||
fn rent_exempt_balance(space: usize) -> u64 {
|
||||
Rent::default().minimum_balance(space)
|
||||
}
|
||||
|
||||
// fn oracle_minimum_balance() -> u64 {
|
||||
// Rent::default().minimum_balance(Oracle::get_packed_len())
|
||||
// }
|
||||
struct TAccount {
|
||||
is_signer: bool,
|
||||
pubkey: Pubkey,
|
||||
account: Account,
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn test_pack_unpack() {
|
||||
// let check = Submission {
|
||||
// time: 1,
|
||||
// value: 1,
|
||||
// oracle: [1; 32],
|
||||
// };
|
||||
impl TAccount {
|
||||
fn new(program_id: &Pubkey, is_signer: bool) -> TAccount {
|
||||
TAccount {
|
||||
is_signer,
|
||||
pubkey: Pubkey::new_unique(),
|
||||
account: Account::new(0, 0, &program_id)
|
||||
}
|
||||
}
|
||||
|
||||
// let mut packed = vec![0; Submission::get_packed_len() + 1];
|
||||
fn new_rent_exempt(program_id: &Pubkey, space: usize, is_signer: bool) -> TAccount {
|
||||
TAccount {
|
||||
is_signer,
|
||||
pubkey: Pubkey::new_unique(),
|
||||
account: Account::new(rent_exempt_balance(space), space, &program_id)
|
||||
}
|
||||
}
|
||||
|
||||
// assert_eq!(
|
||||
// Err(ProgramError::InvalidAccountData),
|
||||
// Submission::pack(check, &mut packed)
|
||||
// );
|
||||
// }
|
||||
fn info(&mut self) -> AccountInfo {
|
||||
AccountInfo::new(
|
||||
&self.pubkey,
|
||||
self.is_signer,
|
||||
false,
|
||||
&mut self.account.lamports,
|
||||
&mut self.account.data,
|
||||
&self.account.owner,
|
||||
self.account.executable,
|
||||
self.account.rent_epoch,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
use crate::borsh_utils;
|
||||
impl<'a> Into<AccountInfo<'a>> for &'a mut TAccount {
|
||||
fn into(self) -> AccountInfo<'a> {
|
||||
self.info()
|
||||
}
|
||||
}
|
||||
|
||||
struct TSysAccount (Pubkey, Account);
|
||||
impl<'a> Into<AccountInfo<'a>> for &'a mut TSysAccount {
|
||||
fn into(self) -> AccountInfo<'a> {
|
||||
AccountInfo::new(
|
||||
&self.0,
|
||||
false,
|
||||
false,
|
||||
&mut self.1.lamports,
|
||||
&mut self.1.data,
|
||||
&self.1.owner,
|
||||
self.1.executable,
|
||||
self.1.rent_epoch,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_aggregator(program_id: &Pubkey) -> Result<(TAccount, TAccount), ProgramError> {
|
||||
let mut rent_sysvar = rent_sysvar();
|
||||
let mut aggregator = TAccount::new_rent_exempt(&program_id, borsh_utils::get_packed_len::<Aggregator>(), false);
|
||||
let mut aggregator_owner = TAccount::new(&program_id, true);
|
||||
|
||||
process(
|
||||
&program_id,
|
||||
instruction::Instruction::Initialize {
|
||||
config: AggregatorConfig{
|
||||
submit_interval: 10,
|
||||
min_submission_value: 0,
|
||||
max_submission_value: 100,
|
||||
submission_decimals: 8,
|
||||
description: [0u8; 32],
|
||||
}
|
||||
},
|
||||
vec![
|
||||
(&mut rent_sysvar).into(),
|
||||
(&mut aggregator).into(),
|
||||
(&mut aggregator_owner).into(),
|
||||
].as_slice(),
|
||||
)?;
|
||||
|
||||
Ok((aggregator, aggregator_owner))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_intialize() -> ProgramResult {
|
||||
let program_id = Pubkey::new_unique();
|
||||
let aggregator_key = Pubkey::new_unique();
|
||||
let owner_key = Pubkey::new_unique();
|
||||
setup_aggregator(&program_id)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
let inx = instruction::Instruction::Initialize {
|
||||
submit_interval: 10,
|
||||
min_submission_value: 0,
|
||||
max_submission_value: 100,
|
||||
submission_decimals: 8,
|
||||
description: [0u8; 32],
|
||||
};
|
||||
#[test]
|
||||
fn test_add_and_remove_oracle() -> ProgramResult {
|
||||
let program_id = Pubkey::new_unique();
|
||||
|
||||
let data = inx.try_to_vec().map_err(|_| ProgramError::InvalidAccountData)?;
|
||||
let (mut aggregator, mut aggregator_owner) = setup_aggregator(&program_id)?;
|
||||
|
||||
let rent_sysvar = rent_sysvar();
|
||||
let aggregator_account = Account::new(aggregator_minimum_balance(), borsh_utils::get_packed_len::<Aggregator>(), &program_id);
|
||||
let owner_account = Account::default();
|
||||
|
||||
// Ok(())
|
||||
|
||||
// aggregator is not rent exempt
|
||||
// assert_eq!(
|
||||
// Err(Error::NotRentExempt.into()),
|
||||
// do_process_instruction(
|
||||
// initialize(
|
||||
// &program_id,
|
||||
// &aggregator_key,
|
||||
// &owner_key,
|
||||
// 6,
|
||||
// 1,
|
||||
// 9999,
|
||||
// 6,
|
||||
// [1; 32]
|
||||
// ),
|
||||
// vec![
|
||||
// &mut rent_sysvar,
|
||||
// &mut aggregator_account,
|
||||
// &mut owner_account,
|
||||
// ]
|
||||
// )
|
||||
// );
|
||||
|
||||
// aggregator_account.lamports = aggregator_minimum_balance();
|
||||
|
||||
// initialize will be successful
|
||||
let mut rent_sysvar = rent_sysvar();
|
||||
let mut oracle = TAccount::new_rent_exempt(&program_id, borsh_utils::get_packed_len::<Oracle>(), false);
|
||||
let mut oracle_owner = TAccount::new(&program_id, true);
|
||||
|
||||
process(
|
||||
&program_id,
|
||||
&data,
|
||||
instruction::Instruction::AddOracle {
|
||||
description: [0xab; 32],
|
||||
},
|
||||
vec![
|
||||
(sysvar::rent::id(), rent_sysvar, false),
|
||||
(aggregator_key, aggregator_account, false),
|
||||
(owner_key, owner_account, true),
|
||||
],
|
||||
(&mut rent_sysvar).into(),
|
||||
(&mut aggregator).into(),
|
||||
(&mut aggregator_owner).into(),
|
||||
(&mut oracle).into(),
|
||||
(&mut oracle_owner).into(),
|
||||
].as_slice(),
|
||||
)?;
|
||||
|
||||
process(
|
||||
&program_id,
|
||||
instruction::Instruction::RemoveOracle {},
|
||||
vec![
|
||||
(&mut aggregator).into(),
|
||||
(&mut aggregator_owner).into(),
|
||||
(&mut oracle).into(),
|
||||
].as_slice(),
|
||||
)?;
|
||||
|
||||
// println!("{}", hex::encode(oracle.account.data));
|
||||
Ok(())
|
||||
// .unwrap();
|
||||
|
||||
// // duplicate initialize will get failed
|
||||
// assert_eq!(
|
||||
// Err(Error::AlreadyInUse.into()),
|
||||
// do_process_instruction(
|
||||
// initialize(
|
||||
// &program_id,
|
||||
// &aggregator_key,
|
||||
// &owner_key,
|
||||
// 6,
|
||||
// 1,
|
||||
// 9999,
|
||||
// 6,
|
||||
// [1; 32]
|
||||
// ),
|
||||
// vec![
|
||||
// &mut rent_sysvar,
|
||||
// &mut aggregator_account,
|
||||
// &mut owner_account,
|
||||
// ]
|
||||
// )
|
||||
// );
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn test_add_oracle() {
|
||||
// let program_id = Pubkey::new_unique();
|
||||
|
||||
// let oracle_key = Pubkey::new_unique();
|
||||
// let oracle_owner_key = Pubkey::new_unique();
|
||||
// let aggregator_key = Pubkey::new_unique();
|
||||
// let aggregator_owner_key = Pubkey::new_unique();
|
||||
|
||||
// let mut rent_sysvar = rent_sysvar();
|
||||
// let mut clock_sysvar = clock_sysvar();
|
||||
|
||||
// let mut oracle_account = SolanaAccount::new(
|
||||
// oracle_minimum_balance(),
|
||||
// Oracle::get_packed_len(),
|
||||
// &program_id,
|
||||
// );
|
||||
// let mut aggregator_account = SolanaAccount::new(
|
||||
// aggregator_minimum_balance(),
|
||||
// Aggregator::get_packed_len(),
|
||||
// &program_id,
|
||||
// );
|
||||
|
||||
// let mut oracle_owner_account = SolanaAccount::default();
|
||||
// let mut aggregator_owner_account = SolanaAccount::default();
|
||||
|
||||
// // add oracle to unexist aggregator
|
||||
// assert_eq!(
|
||||
// Err(Error::NotFoundAggregator.into()),
|
||||
// do_process_instruction(
|
||||
// add_oracle(
|
||||
// &program_id,
|
||||
// &oracle_key,
|
||||
// &oracle_owner_key,
|
||||
// &aggregator_key,
|
||||
// &aggregator_owner_key,
|
||||
// [1; 32]
|
||||
// ),
|
||||
// vec![
|
||||
// &mut oracle_account,
|
||||
// &mut oracle_owner_account,
|
||||
// &mut clock_sysvar,
|
||||
// &mut aggregator_account,
|
||||
// &mut aggregator_owner_account,
|
||||
// ]
|
||||
// )
|
||||
// );
|
||||
|
||||
// // initialize aggregator
|
||||
// do_process_instruction(
|
||||
// initialize(
|
||||
// &program_id,
|
||||
// &aggregator_key,
|
||||
// &aggregator_owner_key,
|
||||
// 6,
|
||||
// 1,
|
||||
// 9999,
|
||||
// 6,
|
||||
// [1; 32],
|
||||
// ),
|
||||
// vec![
|
||||
// &mut rent_sysvar,
|
||||
// &mut aggregator_account,
|
||||
// &mut aggregator_owner_account,
|
||||
// ],
|
||||
// )
|
||||
// .unwrap();
|
||||
|
||||
// // will be successful
|
||||
// do_process_instruction(
|
||||
// add_oracle(
|
||||
// &program_id,
|
||||
// &oracle_key,
|
||||
// &oracle_owner_key,
|
||||
// &aggregator_key,
|
||||
// &aggregator_owner_key,
|
||||
// [1; 32],
|
||||
// ),
|
||||
// vec![
|
||||
// &mut oracle_account,
|
||||
// &mut oracle_owner_account,
|
||||
// &mut clock_sysvar,
|
||||
// &mut aggregator_account,
|
||||
// &mut aggregator_owner_account,
|
||||
// ],
|
||||
// )
|
||||
// .unwrap();
|
||||
|
||||
// // duplicate oracle
|
||||
// assert_eq!(
|
||||
// Err(Error::AlreadyInUse.into()),
|
||||
// do_process_instruction(
|
||||
// add_oracle(
|
||||
// &program_id,
|
||||
// &oracle_key,
|
||||
// &oracle_owner_key,
|
||||
// &aggregator_key,
|
||||
// &aggregator_owner_key,
|
||||
// [1; 32]
|
||||
// ),
|
||||
// vec![
|
||||
// &mut oracle_account,
|
||||
// &mut oracle_owner_account,
|
||||
// &mut clock_sysvar,
|
||||
// &mut aggregator_account,
|
||||
// &mut aggregator_owner_account,
|
||||
// ]
|
||||
// )
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn test_remove_oracle() {
|
||||
// let program_id = Pubkey::new_unique();
|
||||
|
||||
// let oracle_key = Pubkey::new_unique();
|
||||
// let oracle_owner_key = Pubkey::new_unique();
|
||||
// let aggregator_key = Pubkey::new_unique();
|
||||
// let aggregator_owner_key = Pubkey::new_unique();
|
||||
|
||||
// let mut rent_sysvar = rent_sysvar();
|
||||
// let mut clock_sysvar = clock_sysvar();
|
||||
|
||||
// let mut oracle_account = SolanaAccount::new(
|
||||
// oracle_minimum_balance(),
|
||||
// Oracle::get_packed_len(),
|
||||
// &program_id,
|
||||
// );
|
||||
// let mut aggregator_account = SolanaAccount::new(
|
||||
// aggregator_minimum_balance(),
|
||||
// Aggregator::get_packed_len(),
|
||||
// &program_id,
|
||||
// );
|
||||
|
||||
// let mut oracle_owner_account = SolanaAccount::default();
|
||||
// let mut aggregator_owner_account = SolanaAccount::default();
|
||||
|
||||
// // initialize aggregator
|
||||
// do_process_instruction(
|
||||
// initialize(
|
||||
// &program_id,
|
||||
// &aggregator_key,
|
||||
// &aggregator_owner_key,
|
||||
// 6,
|
||||
// 1,
|
||||
// 9999,
|
||||
// 6,
|
||||
// [1; 32],
|
||||
// ),
|
||||
// vec![
|
||||
// &mut rent_sysvar,
|
||||
// &mut aggregator_account,
|
||||
// &mut aggregator_owner_account,
|
||||
// ],
|
||||
// )
|
||||
// .unwrap();
|
||||
|
||||
// // add oracle
|
||||
// do_process_instruction(
|
||||
// add_oracle(
|
||||
// &program_id,
|
||||
// &oracle_key,
|
||||
// &oracle_owner_key,
|
||||
// &aggregator_key,
|
||||
// &aggregator_owner_key,
|
||||
// [1; 32],
|
||||
// ),
|
||||
// vec![
|
||||
// &mut oracle_account,
|
||||
// &mut oracle_owner_account,
|
||||
// &mut clock_sysvar,
|
||||
// &mut aggregator_account,
|
||||
// &mut aggregator_owner_account,
|
||||
// ],
|
||||
// )
|
||||
// .unwrap();
|
||||
|
||||
// // remove an unexist oracle
|
||||
// assert_eq!(
|
||||
// Err(Error::NotFoundOracle.into()),
|
||||
// do_process_instruction(
|
||||
// remove_oracle(
|
||||
// &program_id,
|
||||
// &aggregator_key,
|
||||
// &aggregator_owner_key,
|
||||
// &Pubkey::default()
|
||||
// ),
|
||||
// vec![&mut aggregator_account, &mut aggregator_owner_account,]
|
||||
// )
|
||||
// );
|
||||
|
||||
// // will be successful
|
||||
// do_process_instruction(
|
||||
// remove_oracle(
|
||||
// &program_id,
|
||||
// &aggregator_key,
|
||||
// &aggregator_owner_key,
|
||||
// &oracle_key,
|
||||
// ),
|
||||
// vec![&mut aggregator_account, &mut aggregator_owner_account],
|
||||
// )
|
||||
// .unwrap();
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn test_submit() {
|
||||
// let program_id = Pubkey::new_unique();
|
||||
|
|
|
@ -2,66 +2,15 @@
|
|||
use borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
|
||||
|
||||
use crate::instruction::MAX_ORACLES;
|
||||
use crate::borsh_state::{InitBorshState, BorshState};
|
||||
|
||||
use solana_program::{
|
||||
clock::UnixTimestamp,
|
||||
program_error::ProgramError,
|
||||
program_pack::{IsInitialized, Pack, Sealed},
|
||||
account_info::AccountInfo,
|
||||
entrypoint::ProgramResult,
|
||||
sysvar::rent::Rent,
|
||||
msg,
|
||||
program_pack::IsInitialized,
|
||||
};
|
||||
|
||||
pub trait BorshState: BorshDeserialize + BorshSerialize {
|
||||
fn load(account: &AccountInfo) -> Result<Self, ProgramError> {
|
||||
let data = (*account.data).borrow();
|
||||
Self::try_from_slice(&data).map_err(|_| ProgramError::InvalidAccountData)
|
||||
}
|
||||
|
||||
fn save(&self, account: &AccountInfo) -> ProgramResult {
|
||||
let data = self.try_to_vec().map_err(|_| ProgramError::InvalidAccountData)?;
|
||||
|
||||
// FIXME: looks like there is association precedence issue that prevents
|
||||
// RefMut from being automatically dereferenced.
|
||||
//
|
||||
// let dst = &mut account.data.borrow_mut();
|
||||
//
|
||||
// Why does it work in an SPL token program though?
|
||||
//
|
||||
// Account::pack(source_account, &mut source_account_info.data.borrow_mut())?;
|
||||
let mut dst = (*account.data).borrow_mut();
|
||||
if dst.len() != data.len() {
|
||||
return Err(ProgramError::InvalidAccountData);
|
||||
}
|
||||
dst.copy_from_slice(&data);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn save_exempt(&self, account: &AccountInfo, rent: &Rent) -> ProgramResult {
|
||||
let data = self.try_to_vec().map_err(|_| ProgramError::InvalidAccountData)?;
|
||||
|
||||
if !rent.is_exempt(account.lamports(), data.len()) {
|
||||
// FIXME: return a custom error
|
||||
return Err(ProgramError::InvalidAccountData);
|
||||
}
|
||||
|
||||
let mut dst = (*account.data).borrow_mut();
|
||||
if dst.len() != data.len() {
|
||||
// FIXME: return a custom error
|
||||
return Err(ProgramError::InvalidAccountData);
|
||||
}
|
||||
dst.copy_from_slice(&data);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Aggregator data.
|
||||
#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, BorshSchema, Default, PartialEq)]
|
||||
pub struct Aggregator {
|
||||
#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, BorshSchema, Default, PartialEq)]
|
||||
pub struct AggregatorConfig {
|
||||
/// The interval(seconds) of an oracle's each submission
|
||||
pub submit_interval: u32,
|
||||
/// min submission value
|
||||
|
@ -72,15 +21,45 @@ pub struct Aggregator {
|
|||
pub submission_decimals: u8,
|
||||
/// description
|
||||
pub description: [u8; 32],
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, BorshSchema, Default, PartialEq)]
|
||||
pub struct Round {
|
||||
pub id: u64,
|
||||
pub started_at: u64,
|
||||
pub updated_at: u64,
|
||||
pub submissions: [Submission; MAX_ORACLES],
|
||||
}
|
||||
#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, BorshSchema, Default, PartialEq)]
|
||||
pub struct Answer {
|
||||
pub round_id: u64,
|
||||
pub created_at: u64,
|
||||
pub updated_at: u64,
|
||||
pub submissions: [Submission; MAX_ORACLES],
|
||||
}
|
||||
|
||||
/// Aggregator data.
|
||||
#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, BorshSchema, Default, PartialEq)]
|
||||
pub struct Aggregator {
|
||||
pub config: AggregatorConfig,
|
||||
/// is initialized
|
||||
pub is_initialized: bool,
|
||||
/// authority
|
||||
pub owner: [u8; 32],
|
||||
/// submissions
|
||||
pub submissions: [Submission; MAX_ORACLES],
|
||||
/// current round accepting oracle submissions
|
||||
pub current_round: Round,
|
||||
/// the latest answer resolved
|
||||
pub answer: Answer,
|
||||
}
|
||||
|
||||
impl IsInitialized for Aggregator {
|
||||
fn is_initialized(&self) -> bool {
|
||||
self.is_initialized
|
||||
}
|
||||
}
|
||||
|
||||
impl BorshState for Aggregator {}
|
||||
impl InitBorshState for Aggregator {}
|
||||
|
||||
/// Submission data.
|
||||
#[derive(Clone, Copy, Debug, BorshSerialize, BorshDeserialize, BorshSchema, Default, PartialEq)]
|
||||
|
@ -97,8 +76,6 @@ pub struct Submission {
|
|||
/// Oracle data.
|
||||
#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, BorshSchema, Default, PartialEq)]
|
||||
pub struct Oracle {
|
||||
/// submit time
|
||||
pub next_submit_time: UnixTimestamp,
|
||||
/// is usually the oracle name
|
||||
pub description: [u8; 32],
|
||||
/// is initialized
|
||||
|
@ -110,82 +87,10 @@ pub struct Oracle {
|
|||
/// owner
|
||||
pub owner: [u8; 32],
|
||||
}
|
||||
|
||||
impl BorshState for Oracle {}
|
||||
impl IsInitialized for Oracle {
|
||||
fn is_initialized(&self) -> bool {
|
||||
self.is_initialized
|
||||
}
|
||||
fn is_initialized(&self) -> bool {
|
||||
self.is_initialized
|
||||
}
|
||||
}
|
||||
|
||||
// impl Sealed for Oracle {}
|
||||
// impl Pack for Oracle {
|
||||
// const LEN: usize = 113;
|
||||
|
||||
// fn pack_into_slice(&self, dst: &mut [u8]) {
|
||||
// let data = self.try_to_vec().unwrap();
|
||||
// dst[..data.len()].copy_from_slice(&data);
|
||||
// }
|
||||
|
||||
// fn unpack_from_slice(src: &[u8]) -> Result<Self, ProgramError> {
|
||||
// let mut mut_src: &[u8] = src;
|
||||
// Self::deserialize(&mut mut_src).map_err(|_| ProgramError::InvalidAccountData)
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// impl Sealed for Submission {}
|
||||
// impl Pack for Submission {
|
||||
// const LEN: usize = 48;
|
||||
|
||||
// fn pack_into_slice(&self, dst: &mut [u8]) {
|
||||
// let data = self.try_to_vec().unwrap();
|
||||
// dst[..data.len()].copy_from_slice(&data);
|
||||
// }
|
||||
|
||||
// fn unpack_from_slice(src: &[u8]) -> Result<Self, ProgramError> {
|
||||
// let mut mut_src: &[u8] = src;
|
||||
// Self::deserialize(&mut mut_src).map_err(|_| ProgramError::InvalidAccountData)
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[cfg(test)]
|
||||
// mod tests {
|
||||
// use super::*;
|
||||
// use crate::borsh_utils;
|
||||
|
||||
// #[test]
|
||||
// fn test_get_packed_len() {
|
||||
// assert_eq!(
|
||||
// Aggregator::get_packed_len(),
|
||||
// borsh_utils::get_packed_len::<Aggregator>()
|
||||
// );
|
||||
|
||||
// assert_eq!(
|
||||
// Oracle::get_packed_len(),
|
||||
// borsh_utils::get_packed_len::<Oracle>()
|
||||
// );
|
||||
|
||||
// assert_eq!(
|
||||
// Submission::get_packed_len(),
|
||||
// borsh_utils::get_packed_len::<Submission>()
|
||||
// );
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn test_serialize_bytes() {
|
||||
// assert_eq!(
|
||||
// Submission {
|
||||
// time: 0,
|
||||
// value: 1,
|
||||
// oracle: [1; 32]
|
||||
// }
|
||||
// .try_to_vec()
|
||||
// .unwrap(),
|
||||
// vec![
|
||||
// 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
|
||||
// ]
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
impl InitBorshState for Oracle {}
|
Loading…
Reference in New Issue