use crate::{cfg_client, prelude::*};
use solana_program::borsh0_10::get_instance_packed_len;
#[repr(u8)]
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, AnchorSerialize, AnchorDeserialize)]
pub enum RequestStatus {
#[default]
None = 0,
RequestPending = 1,
RequestCancelled = 2,
RequestFailure = 3,
RequestExpired = 4,
RequestSuccess = 5,
}
impl From<RequestStatus> for u8 {
fn from(value: RequestStatus) -> Self {
match value {
RequestStatus::RequestPending => 1,
RequestStatus::RequestCancelled => 2,
RequestStatus::RequestFailure => 3,
RequestStatus::RequestExpired => 4,
RequestStatus::RequestSuccess => 5,
_ => 0,
}
}
}
impl From<u8> for RequestStatus {
fn from(value: u8) -> Self {
match value {
1 => RequestStatus::RequestPending,
2 => RequestStatus::RequestCancelled,
3 => RequestStatus::RequestFailure,
4 => RequestStatus::RequestExpired,
5 => RequestStatus::RequestSuccess,
_ => RequestStatus::default(),
}
}
}
#[derive(Copy, Clone, AnchorDeserialize, AnchorSerialize, PartialEq)]
pub struct FunctionRequestTriggerRound {
pub status: RequestStatus,
pub bounty: u64,
pub request_slot: u64,
pub fulfilled_slot: u64,
pub expiration_slot: u64,
pub verifier: Pubkey,
pub enclave_signer: Pubkey,
pub valid_after_slot: u64,
pub _ebuf: [u8; 56],
}
impl Default for FunctionRequestTriggerRound {
fn default() -> Self {
unsafe { std::mem::zeroed() }
}
}
#[derive(AnchorDeserialize, AnchorSerialize, Clone, PartialEq)]
pub struct FunctionRequestAccountData {
pub is_triggered: u8,
pub status: RequestStatus,
pub authority: Pubkey,
pub payer: Pubkey,
pub function: Pubkey,
pub escrow: Pubkey,
pub attestation_queue: Pubkey,
pub active_request: FunctionRequestTriggerRound,
pub previous_request: FunctionRequestTriggerRound,
pub max_container_params_len: u32,
pub container_params_hash: [u8; 32],
pub container_params: Vec<u8>,
pub created_at: i64,
pub garbage_collection_slot: Option<u64>,
pub error_status: u8,
pub _ebuf: [u8; 255],
}
impl Default for FunctionRequestAccountData {
fn default() -> Self {
Self {
is_triggered: 0,
status: RequestStatus::None,
authority: Pubkey::default(),
payer: Pubkey::default(),
function: Pubkey::default(),
escrow: Pubkey::default(),
attestation_queue: Pubkey::default(),
active_request: FunctionRequestTriggerRound::default(),
previous_request: FunctionRequestTriggerRound::default(),
max_container_params_len: 0,
container_params_hash: [0u8; 32],
container_params: Vec::new(),
created_at: 0,
garbage_collection_slot: None,
error_status: 0,
_ebuf: [0u8; 255],
}
}
}
impl anchor_lang::AccountSerialize for FunctionRequestAccountData {
fn try_serialize<W: std::io::Write>(&self, writer: &mut W) -> anchor_lang::Result<()> {
if writer
.write_all(&FunctionRequestAccountData::discriminator())
.is_err()
{
return Err(anchor_lang::error::ErrorCode::AccountDidNotSerialize.into());
}
if AnchorSerialize::serialize(self, writer).is_err() {
return Err(anchor_lang::error::ErrorCode::AccountDidNotSerialize.into());
}
Ok(())
}
}
impl anchor_lang::AccountDeserialize for FunctionRequestAccountData {
fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result<Self> {
if buf.len() < FunctionRequestAccountData::discriminator().len() {
return Err(anchor_lang::error::ErrorCode::AccountDiscriminatorNotFound.into());
}
let given_disc = &buf[..8];
if FunctionRequestAccountData::discriminator() != given_disc {
return Err(
anchor_lang::error::Error::from(anchor_lang::error::AnchorError {
error_name: anchor_lang::error::ErrorCode::AccountDiscriminatorMismatch.name(),
error_code_number: anchor_lang::error::ErrorCode::AccountDiscriminatorMismatch
.into(),
error_msg: anchor_lang::error::ErrorCode::AccountDiscriminatorMismatch
.to_string(),
error_origin: Some(anchor_lang::error::ErrorOrigin::Source(
anchor_lang::error::Source {
filename: "programs/attestation_program/src/lib.rs",
line: 1u32,
},
)),
compared_values: None,
})
.with_account_name("FunctionRequestAccountData"),
);
}
Self::try_deserialize_unchecked(buf)
}
fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result<Self> {
let mut data: &[u8] = &buf[8..];
AnchorDeserialize::deserialize(&mut data)
.map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotDeserialize.into())
}
}
impl Discriminator for FunctionRequestAccountData {
const DISCRIMINATOR: [u8; 8] = [8, 14, 177, 85, 144, 65, 148, 246];
}
impl Owner for FunctionRequestAccountData {
fn owner() -> Pubkey {
SWITCHBOARD_ATTESTATION_PROGRAM_ID
}
}
impl FunctionRequestAccountData {
pub fn space(len: Option<u32>) -> usize {
let base: usize = 8 + get_instance_packed_len(&FunctionRequestAccountData::default()).unwrap();
let vec_elements: usize = len.unwrap_or(crate::DEFAULT_USERS_CONTAINER_PARAMS_LEN) as usize;
base + vec_elements
}
pub fn is_round_active(&self, clock: &Clock) -> bool {
if self.active_request.status == RequestStatus::RequestPending
&& self.active_request.expiration_slot > 0
&& clock.slot >= self.active_request.expiration_slot
{
return true;
}
false
}
pub fn validate_signer<'a>(
&self,
function_account_info: &AccountInfo<'a>,
signer: &AccountInfo<'a>,
) -> anchor_lang::Result<bool> {
if self.function != function_account_info.key() {
msg!("function key mismatch");
msg!(
"expected {}, received {}",
self.function,
function_account_info.key()
);
return Ok(false);
}
let function_loader =
AccountLoader::<'_, FunctionAccountData>::try_from(&function_account_info.clone())?;
function_loader.load()?; if self.active_request.enclave_signer != signer.key() {
msg!("request signer mismatch");
msg!(
"expected {}, received {}",
self.active_request.enclave_signer,
signer.key()
);
return Ok(false);
}
Ok(true)
}
cfg_client! {
pub fn get_discriminator_filter() -> solana_client::rpc_filter::RpcFilterType {
solana_client::rpc_filter::RpcFilterType::Memcmp(solana_client::rpc_filter::Memcmp::new_raw_bytes(
0,
FunctionRequestAccountData::discriminator().to_vec(),
))
}
pub fn get_is_triggered_filter() -> solana_client::rpc_filter::RpcFilterType {
solana_client::rpc_filter::RpcFilterType::Memcmp(solana_client::rpc_filter::Memcmp::new_raw_bytes(
8,
vec![1u8],
))
}
pub fn get_is_active_filter() -> solana_client::rpc_filter::RpcFilterType {
solana_client::rpc_filter::RpcFilterType::Memcmp(solana_client::rpc_filter::Memcmp::new_raw_bytes(
9,
vec![RequestStatus::RequestPending as u8],
))
}
pub fn get_queue_filter(queue_pubkey: &Pubkey) -> solana_client::rpc_filter::RpcFilterType {
solana_client::rpc_filter::RpcFilterType::Memcmp(solana_client::rpc_filter::Memcmp::new_raw_bytes(
138,
queue_pubkey.to_bytes().into(),
))
}
pub fn get_is_ready_filters(queue_pubkey: &Pubkey) -> Vec<solana_client::rpc_filter::RpcFilterType> {
vec![
FunctionRequestAccountData::get_discriminator_filter(),
FunctionRequestAccountData::get_is_triggered_filter(),
FunctionRequestAccountData::get_is_active_filter(),
FunctionRequestAccountData::get_queue_filter(queue_pubkey),
]
}
pub async fn fetch(
client: &solana_client::rpc_client::RpcClient,
pubkey: Pubkey,
) -> std::result::Result<Self, switchboard_common::Error> {
crate::client::fetch_anchor_account(client, pubkey).await
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::str::FromStr;
const REQUEST_DATA: [u8; 1309] = [
8, 14, 177, 85, 144, 65, 148, 246, 0, 4, 191, 163, 95, 149, 251, 196, 61, 38, 170, 30, 192,
210, 238, 210, 121, 251, 115, 80, 136, 183, 116, 88, 7, 195, 127, 225, 4, 177, 167, 250,
214, 98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 200, 91, 33, 133, 251, 77, 4, 45, 33, 88, 160, 219, 74, 253, 191, 56, 191,
52, 130, 87, 44, 197, 78, 47, 64, 1, 9, 49, 23, 46, 248, 118, 67, 254, 215, 187, 179, 81,
198, 84, 39, 244, 16, 113, 89, 56, 41, 133, 66, 71, 68, 238, 198, 34, 226, 219, 65, 150,
252, 243, 229, 140, 153, 112, 174, 177, 70, 231, 73, 196, 214, 194, 190, 219, 159, 24, 162,
119, 159, 16, 120, 53, 239, 102, 225, 241, 66, 97, 108, 144, 152, 47, 53, 76, 242, 215, 4,
0, 0, 0, 0, 0, 0, 0, 0, 212, 153, 154, 14, 0, 0, 0, 0, 225, 153, 154, 14, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 214, 176, 30, 24, 236, 238, 245, 97, 218, 201, 34, 20, 25, 94, 235, 88,
235, 48, 114, 193, 144, 126, 220, 233, 142, 238, 32, 191, 233, 220, 175, 23, 80, 233, 228,
192, 87, 36, 180, 107, 5, 182, 70, 125, 89, 139, 68, 5, 118, 218, 209, 167, 207, 52, 20,
76, 217, 241, 92, 50, 106, 53, 253, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
0, 0, 159, 54, 102, 77, 67, 235, 26, 94, 144, 172, 18, 65, 45, 54, 127, 59, 100, 213, 206,
91, 40, 101, 248, 189, 195, 19, 165, 190, 123, 227, 54, 103, 125, 0, 0, 0, 80, 73, 68, 61,
69, 53, 77, 65, 115, 122, 106, 122, 56, 113, 90, 90, 68, 72, 75, 113, 81, 50, 49, 103, 53,
119, 89, 117, 104, 77, 84, 106, 77, 98, 107, 49, 76, 52, 76, 52, 106, 66, 70, 88, 77, 103,
113, 71, 44, 77, 73, 78, 95, 82, 69, 83, 85, 76, 84, 61, 49, 44, 77, 65, 88, 95, 82, 69,
83, 85, 76, 84, 61, 49, 48, 44, 85, 83, 69, 82, 61, 68, 117, 53, 77, 111, 52, 89, 70, 70,
70, 76, 113, 84, 57, 75, 90, 81, 75, 80, 77, 119, 52, 67, 109, 101, 111, 53, 86, 102, 71,
76, 117, 114, 106, 99, 82, 104, 120, 104, 98, 51, 112, 106, 75, 130, 192, 8, 101, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];
const REQUEST_DATA_HEX: &str = "080eb155904194f60004bfa35f95fbc43d26aa1ec0d2eed279fb735088b7745807c37fe104b1a7fad6620000000000000000000000000000000000000000000000000000000000000000c85b2185fb4d042d2158a0db4afdbf38bf3482572cc54e2f40010931172ef87643fed7bbb351c65427f4107159382985424744eec622e2db4196fcf3e58c9970aeb146e749c4d6c2bedb9f18a2779f107835ef66e1f142616c90982f354cf2d7040000000000000000d4999a0e00000000e1999a0e000000000000000000000000d6b01e18eceef561dac92214195eeb58eb3072c1907edce98eee20bfe9dcaf1750e9e4c05724b46b05b6467d598b440576dad1a7cf34144cd9f15c326a35fd3c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200009f36664d43eb1a5e90ac12412d367f3b64d5ce5b2865f8bdc313a5be7be336677d0000005049443d45354d41737a6a7a38715a5a44484b715132316735775975684d546a4d626b314c344c346a4246584d6771472c4d494e5f524553554c543d312c4d41585f524553554c543d31302c555345523d4475354d6f34594646464c7154394b5a514b504d7734436d656f355666474c75726a63526878686233706a4b82c00865000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
const REQUEST_DATA_HEX_NO_DISC: &str = "0004bfa35f95fbc43d26aa1ec0d2eed279fb735088b7745807c37fe104b1a7fad6620000000000000000000000000000000000000000000000000000000000000000c85b2185fb4d042d2158a0db4afdbf38bf3482572cc54e2f40010931172ef87643fed7bbb351c65427f4107159382985424744eec622e2db4196fcf3e58c9970aeb146e749c4d6c2bedb9f18a2779f107835ef66e1f142616c90982f354cf2d7040000000000000000d4999a0e00000000e1999a0e000000000000000000000000d6b01e18eceef561dac92214195eeb58eb3072c1907edce98eee20bfe9dcaf1750e9e4c05724b46b05b6467d598b440576dad1a7cf34144cd9f15c326a35fd3c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200009f36664d43eb1a5e90ac12412d367f3b64d5ce5b2865f8bdc313a5be7be336677d0000005049443d45354d41737a6a7a38715a5a44484b715132316735775975684d546a4d626b314c344c346a4246584d6771472c4d494e5f524553554c543d312c4d41585f524553554c543d31302c555345523d4475354d6f34594646464c7154394b5a514b504d7734436d656f355666474c75726a63526878686233706a4b82c00865000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
const EXPECTED_CONTAINER_PARAMS: &str = "PID=E5MAszjz8qZZDHKqQ21g5wYuhMTjMbk1L4L4jBFXMgqG,MIN_RESULT=1,MAX_RESULT=10,USER=Du5Mo4YFFFLqT9KZQKPMw4Cmeo5VfGLurjcRhxhb3pjK";
#[test]
fn test_request_deserialization() {
let request =
FunctionRequestAccountData::try_deserialize_unchecked(&mut REQUEST_DATA.as_slice())
.unwrap();
let container_params = std::str::from_utf8(&request.container_params)
.unwrap()
.to_string();
println!("Max params Len: {}", request.max_container_params_len);
println!("Params Len: {}", request.container_params.len());
assert_eq!(container_params, EXPECTED_CONTAINER_PARAMS.to_string());
assert_eq!(
request.function,
Pubkey::from_str("EV78uGX5CKioM7MyY8tY1nQFJtNXnjVGTCV2tamWdXGh").unwrap()
);
assert_eq!(
request.escrow,
Pubkey::from_str("5aRhbaGeoe7HTwoMwGgeENGXuVCLcRBNxFrmFnWGG1bM").unwrap()
);
}
#[test]
fn test_hex_decode() {
let account_bytes = hex::decode(REQUEST_DATA_HEX).unwrap();
let request =
FunctionRequestAccountData::try_deserialize(&mut account_bytes.as_slice()).unwrap();
let container_params = std::str::from_utf8(&request.container_params)
.unwrap()
.to_string();
assert_eq!(container_params, EXPECTED_CONTAINER_PARAMS.to_string());
assert_eq!(
request.function,
Pubkey::from_str("EV78uGX5CKioM7MyY8tY1nQFJtNXnjVGTCV2tamWdXGh").unwrap()
);
assert_eq!(
request.escrow,
Pubkey::from_str("5aRhbaGeoe7HTwoMwGgeENGXuVCLcRBNxFrmFnWGG1bM").unwrap()
);
}
#[test]
fn test_hex_encode() {
let request =
FunctionRequestAccountData::try_deserialize(&mut REQUEST_DATA.as_slice()).unwrap();
let request_data = [
&FunctionRequestAccountData::DISCRIMINATOR[..],
&request.try_to_vec().unwrap()[..],
]
.concat();
let decoded_request =
FunctionRequestAccountData::try_deserialize(&mut request_data.as_slice()).unwrap();
assert_eq!(request.created_at, decoded_request.created_at);
assert_eq!(
request.container_params.len(),
decoded_request.container_params.len()
);
}
}