Skip to content

Commit

Permalink
refactor(target_chains/solana): parse data before passing to instruct…
Browse files Browse the repository at this point in the history
…ion handlers, remove clones, fix feature
  • Loading branch information
Riateche committed Sep 6, 2024
1 parent 2e90868 commit 9e1ce6a
Show file tree
Hide file tree
Showing 12 changed files with 246 additions and 121 deletions.
7 changes: 5 additions & 2 deletions target_chains/solana/programs/pyth-price-publisher/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@ edition = "2021"
[lib]
crate-type = ["cdylib", "lib"]

[features]
solana-program = ["dep:solana-program", "cc", "jobserver"]

[dependencies]
bytemuck = { version = "1.13.0", features = ["derive"] }
solana-program = { version = "=1.14.17", optional = true }
thiserror = "1.0.40"

# Select older packages which are compatible with solana's Rust toolchain
cc = "=1.0.67"
jobserver = "=0.1.20"
cc = { version = "=1.0.67", optional = true }
jobserver = { version = "=0.1.20", optional = true }

[dev-dependencies]
solana-program-test = "=1.14.17"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use bytemuck::from_bytes;
use std::mem::size_of;
use {
bytemuck::from_bytes,
std::mem::size_of,
};

pub mod buffer;
pub mod config;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
use {
super::errors::{ExtendError, PublisherPriceError, ReadAccountError},
bytemuck::{cast_slice, from_bytes, from_bytes_mut, Pod, Zeroable},
super::errors::{
ExtendError,
PublisherPriceError,
ReadAccountError,
},
bytemuck::{
cast_slice,
from_bytes,
from_bytes_mut,
Pod,
Zeroable,
},
std::mem::size_of,
};

Expand All @@ -18,12 +28,12 @@ const FORMAT: u32 = 2848712303;
#[repr(C, packed)]
pub struct BufferHeader {
/// Account magic to avoid account confusion.
pub format: u32,
pub format: u32,
/// The publisher this buffer is associated with.
pub publisher: [u8; 32],
pub publisher: [u8; 32],
/// The slot corresponding to all prices currently stored in the account.
/// Determined by the clock value when `SubmitPrices` is called.
pub slot: u64,
pub slot: u64,
/// The number of prices currently stored in the account.
pub num_prices: u32,
}
Expand All @@ -45,8 +55,8 @@ pub struct BufferedPrice {
// 4 high bits: trading status
// 28 low bits: feed index
pub trading_status_and_feed_index: u32,
pub price: i64,
pub confidence: u64,
pub price: i64,
pub confidence: u64,
}

impl BufferedPrice {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
use bytemuck::{from_bytes, from_bytes_mut, Pod, Zeroable};
use std::mem::size_of;

use super::errors::ReadAccountError;
use {
super::errors::ReadAccountError,
bytemuck::{
from_bytes,
from_bytes_mut,
Pod,
Zeroable,
},
std::mem::size_of,
};

/// Account Magic to avoid Account Confusiong
const FORMAT: u32 = 1505352794;
Expand All @@ -15,7 +21,7 @@ pub fn format_matches(data: &[u8]) -> bool {
#[repr(C, packed)]
pub struct Config {
/// Account magic to avoid account confusion.
pub format: u32,
pub format: u32,
/// The signature of the authority account will be required to execute
/// `InitializePublisher` instruction.
pub authority: [u8; 32],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ pub enum ExtendError {

#[cfg(feature = "solana-program")]
mod convert {
use super::*;
use solana_program::program_error::ProgramError;
use {
super::*,
solana_program::program_error::ProgramError,
};

impl From<ReadAccountError> for ProgramError {
fn from(value: ReadAccountError) -> Self {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
use bytemuck::{from_bytes, from_bytes_mut, Pod, Zeroable};
use std::mem::size_of;

use super::errors::ReadAccountError;
use {
super::errors::ReadAccountError,
bytemuck::{
from_bytes,
from_bytes_mut,
Pod,
Zeroable,
},
std::mem::size_of,
};

/// Account Magic to avoid Account Confusiong
const FORMAT: u32 = 2258188348;
Expand All @@ -15,10 +21,10 @@ pub fn format_matches(data: &[u8]) -> bool {
#[repr(C, packed)]
pub struct PublisherConfig {
/// Account magic to avoid account confusion.
pub format: u32,
pub format: u32,
/// The publisher this config is associated with.
/// Always matches the pubkey used to derive the PDA pubkey.
pub publisher: [u8; 32],
pub publisher: [u8; 32],
/// The publisher's buffer account.
pub buffer_account: [u8; 32],
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use bytemuck::{Pod, Zeroable};
use bytemuck::{
Pod,
Zeroable,
};

/// Seed used to derive the config account.
pub const CONFIG_SEED: &str = "CONFIG";
Expand Down Expand Up @@ -27,13 +30,20 @@ pub enum Instruction {

#[cfg(feature = "solana-program")]
impl Instruction {
pub fn parse(input: &[u8]) -> Result<Instruction, solana_program::program_error::ProgramError> {
match input.first() {
Some(0) => Ok(Instruction::Initialize),
Some(1) => Ok(Instruction::SubmitPrices),
Some(2) => Ok(Instruction::InitializePublisher),
_ => Err(solana_program::program_error::ProgramError::InvalidInstructionData),
pub fn parse(
input: &[u8],
) -> Result<(Instruction, &[u8]), solana_program::program_error::ProgramError> {
if input.is_empty() {
return Err(solana_program::program_error::ProgramError::InvalidInstructionData);
}
let payload = &input[1..];
let instruction = match input[0] {
0 => Instruction::Initialize,
1 => Instruction::SubmitPrices,
2 => Instruction::InitializePublisher,
_ => return Err(solana_program::program_error::ProgramError::InvalidInstructionData),
};
Ok((instruction, payload))
}
}

Expand All @@ -44,18 +54,18 @@ pub struct InitializeArgs {
pub config_bump: u8,
/// The signature of the authority account will be required to execute
/// `InitializePublisher` instruction.
pub authority: [u8; 32],
pub authority: [u8; 32],
}

#[derive(Debug, Clone, Copy, Zeroable, Pod)]
#[repr(C, packed)]
pub struct InitializePublisherArgs {
/// PDA bump of the config account.
pub config_bump: u8,
pub config_bump: u8,
/// PDA bump of the publisher config account.
pub publisher_config_bump: u8,
/// The publisher to be initialized.
pub publisher: [u8; 32],
pub publisher: [u8; 32],
}

#[derive(Debug, Clone, Copy, Zeroable, Pod)]
Expand Down
52 changes: 40 additions & 12 deletions target_chains/solana/programs/pyth-price-publisher/src/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,26 @@ mod initialize;
mod initialize_publisher;
mod submit_prices;

use crate::instruction::Instruction;
use solana_program::{
account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError,
pubkey::Pubkey,
};
use {
initialize::initialize, initialize_publisher::initialize_publisher,
crate::{
ensure,
instruction::{
InitializeArgs,
InitializePublisherArgs,
Instruction,
SubmitPricesArgsHeader,
},
},
bytemuck::try_from_bytes,
initialize::initialize,
initialize_publisher::initialize_publisher,
solana_program::{
account_info::AccountInfo,
entrypoint::ProgramResult,
program_error::ProgramError,
pubkey::Pubkey,
},
std::mem::size_of,
submit_prices::submit_prices,
};

Expand All @@ -18,12 +31,27 @@ pub fn process_instruction(
accounts: &[AccountInfo],
data: &[u8],
) -> ProgramResult {
match Instruction::parse(data) {
Ok(Instruction::Initialize) => initialize(program_id, accounts, &data[1..]),
Ok(Instruction::SubmitPrices) => submit_prices(program_id, accounts, &data[1..]),
Ok(Instruction::InitializePublisher) => {
initialize_publisher(program_id, accounts, &data[1..])
let (instruction, payload) = Instruction::parse(data)?;
match instruction {
Instruction::Initialize => {
let args: &InitializeArgs =
try_from_bytes(payload).map_err(|_| ProgramError::InvalidInstructionData)?;
initialize(program_id, accounts, args)
}
Instruction::SubmitPrices => {
ensure!(
ProgramError::InvalidInstructionData,
payload.len() >= size_of::<SubmitPricesArgsHeader>()
);
let (args_data, prices_data) = payload.split_at(size_of::<SubmitPricesArgsHeader>());
let args: &SubmitPricesArgsHeader =
try_from_bytes(args_data).map_err(|_| ProgramError::InvalidInstructionData)?;
submit_prices(program_id, accounts, args, prices_data)
}
Instruction::InitializePublisher => {
let args: &InitializePublisherArgs =
try_from_bytes(payload).map_err(|_| ProgramError::InvalidInstructionData)?;
initialize_publisher(program_id, accounts, args)
}
_ => Err(ProgramError::InvalidInstructionData),
}
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,34 @@
use {
crate::{
accounts,
instruction::{InitializeArgs, CONFIG_SEED},
validate::{validate_config, validate_payer, validate_system},
instruction::{
InitializeArgs,
CONFIG_SEED,
},
validate::{
validate_config,
validate_payer,
validate_system,
},
},
bytemuck::try_from_bytes,
solana_program::{
account_info::AccountInfo, entrypoint::ProgramResult, program::invoke_signed,
program_error::ProgramError, pubkey::Pubkey, rent::Rent, system_instruction,
account_info::AccountInfo,
entrypoint::ProgramResult,
program::invoke_signed,
pubkey::Pubkey,
rent::Rent,
system_instruction,
sysvar::Sysvar,
},
};

// Creates a config account that stores the authority pubkey.
// The authority is allowed to modify publisher configs.
pub fn initialize(program_id: &Pubkey, accounts: &[AccountInfo], data: &[u8]) -> ProgramResult {
let args: &InitializeArgs =
try_from_bytes(data).map_err(|_| ProgramError::InvalidInstructionData)?;

pub fn initialize(
program_id: &Pubkey,
accounts: &[AccountInfo],
args: &InitializeArgs,
) -> ProgramResult {
let mut accounts = accounts.iter();
let payer = validate_payer(accounts.next())?;
let config = validate_config(accounts.next(), args.config_bump, program_id, true)?;
Expand Down Expand Up @@ -47,14 +58,23 @@ pub fn initialize(program_id: &Pubkey, accounts: &[AccountInfo], data: &[u8]) ->
#[cfg(test)]
mod tests {
use {
crate::{accounts, instruction::CONFIG_SEED},
crate::{
accounts,
instruction::CONFIG_SEED,
},
solana_program::{
instruction::{AccountMeta, Instruction},
instruction::{
AccountMeta,
Instruction,
},
pubkey::Pubkey,
system_program,
},
solana_program_test::*,
solana_sdk::{signature::Signer, transaction::Transaction},
solana_sdk::{
signature::Signer,
transaction::Transaction,
},
};

#[tokio::test]
Expand Down
Loading

0 comments on commit 9e1ce6a

Please sign in to comment.