use crate::prelude::*;
pub type MrEnclave = [u8; 32];
#[zero_copy(unsafe)]
#[repr(packed)]
#[derive(Debug, PartialEq)]
pub struct Quote {
pub enclave_signer: Pubkey,
pub mr_enclave: [u8; 32],
pub verification_status: u8,
pub verification_timestamp: i64,
pub valid_until: i64,
pub quote_registry: [u8; 32],
pub registry_key: [u8; 64],
pub _ebuf: [u8; 256],
}
impl Default for Quote {
fn default() -> Self {
unsafe { std::mem::zeroed() }
}
}
impl Quote {
pub fn reset_verification(&mut self) -> anchor_lang::Result<()> {
if self.verification_status != VerificationStatus::VerificationOverride as u8 {
self.verification_status = VerificationStatus::None.into();
}
self.enclave_signer = Pubkey::default();
self.verification_timestamp = 0;
self.valid_until = 0;
Ok(())
}
pub fn is_verified(&self, clock: &Clock) -> bool {
match self.verification_status.into() {
VerificationStatus::VerificationOverride => true,
VerificationStatus::VerificationSuccess => self.valid_until > clock.unix_timestamp,
_ => false,
}
}
}
pub trait ToU8 {
fn to_u8(&self) -> u8;
}
impl ToU8 for bool {
fn to_u8(&self) -> u8 {
if *self {
1
} else {
0
}
}
}
impl ToU8 for &bool {
fn to_u8(&self) -> u8 {
if **self {
1
} else {
0
}
}
}
pub trait ToBool {
fn to_bool(&self) -> bool;
}
impl ToBool for u8 {
fn to_bool(&self) -> bool {
!matches!(*self, 0)
}
}
impl ToBool for &u8 {
fn to_bool(&self) -> bool {
!matches!(**self, 0)
}
}
#[repr(u8)]
#[derive(
Copy, Clone, Default, Debug, Eq, PartialEq, AnchorSerialize, AnchorDeserialize, InitSpace,
)]
pub enum BoolWithLock {
#[default]
Disabled, Enabled, DisabledLocked, EnabledLocked, }
impl BoolWithLock {
pub fn is_enabled(&self) -> bool {
let byte: u8 = (*self).into();
byte & (1 << 0) != 0
}
pub fn is_disabled(&self) -> bool {
!self.is_enabled()
}
pub fn is_locked(&self) -> bool {
let byte: u8 = (*self).into();
byte & (1 << 1) != 0
}
fn from_flags(is_enabled: bool, is_locked: Option<bool>) -> Self {
let mut value: u8 = 0;
if is_enabled {
value |= 1 << 0; }
if is_locked.unwrap_or_default() {
value |= 1 << 1; }
value.into()
}
pub fn assert_unlocked(&self) -> anchor_lang::Result<()> {
if self.is_locked() {
return Err(error!(SwitchboardError::ConfigParameterLocked));
}
Ok(())
}
pub fn update(&mut self, is_enabled: bool, is_locked: Option<bool>) -> anchor_lang::Result<()> {
self.assert_unlocked()?;
let new_value = Self::from_flags(is_enabled, is_locked);
*self = new_value;
Ok(())
}
pub fn lock(&mut self) -> anchor_lang::Result<()> {
if self.is_locked() {
return Ok(());
}
let mut val: u8 = (*self).into();
val |= 1 << 1;
*self = val.into();
Ok(())
}
}
impl From<BoolWithLock> for u8 {
fn from(value: BoolWithLock) -> Self {
match value {
BoolWithLock::Disabled => 0,
BoolWithLock::Enabled => 1,
BoolWithLock::DisabledLocked => 2,
BoolWithLock::EnabledLocked => 3,
}
}
}
impl From<u8> for BoolWithLock {
fn from(value: u8) -> Self {
match value {
1 => BoolWithLock::Enabled,
2 => BoolWithLock::DisabledLocked,
3 => BoolWithLock::EnabledLocked,
_ => BoolWithLock::default(),
}
}
}
#[repr(u8)]
#[derive(
Copy, Clone, Default, Debug, Eq, PartialEq, AnchorSerialize, AnchorDeserialize, InitSpace,
)]
pub enum ResourceLevel {
#[default]
None = 0, Authority,
Function,
Queue,
}
impl PartialOrd for ResourceLevel {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for ResourceLevel {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
(*self as u8).cmp(&(*other as u8))
}
}
impl From<ResourceLevel> for u8 {
fn from(value: ResourceLevel) -> Self {
match value {
ResourceLevel::Authority => 1,
ResourceLevel::Function => 2,
ResourceLevel::Queue => 3,
_ => 0,
}
}
}
impl From<u8> for ResourceLevel {
fn from(value: u8) -> Self {
match value {
1 => ResourceLevel::Authority,
2 => ResourceLevel::Function,
3 => ResourceLevel::Queue,
_ => ResourceLevel::default(),
}
}
}
impl From<ResourceLevel> for bool {
fn from(value: ResourceLevel) -> Self {
!matches!(value, ResourceLevel::None)
}
}
impl ResourceLevel {
pub fn update(
&mut self,
access_level: &ResourceLevel,
reset: Option<bool>,
) -> anchor_lang::Result<()> {
let target_value = if reset.unwrap_or_default() {
ResourceLevel::None
} else {
*access_level
};
if self == &target_value {
return Ok(());
}
if self > &mut access_level.clone() {
msg!(
"ResourceLevel: curr ({:?}), target ({:?}), access_level ({:?})",
self,
target_value,
access_level
);
return Err(error!(SwitchboardError::IllegalExecuteAttempt));
}
*self = target_value;
Ok(())
}
}