working
This commit is contained in:
parent
6673c29746
commit
d2d711dd29
|
@ -12,7 +12,7 @@ pub struct AttestationQueueAccountData {
|
||||||
// Authority controls adding/removing allowed enclave measurements
|
// Authority controls adding/removing allowed enclave measurements
|
||||||
pub authority: Pubkey,
|
pub authority: Pubkey,
|
||||||
// allowed enclave measurements
|
// allowed enclave measurements
|
||||||
pub mr_enclaves: [[u8; 32]; 32],
|
pub mr_enclaves: [MrEnclave; 32],
|
||||||
pub mr_enclaves_len: u32,
|
pub mr_enclaves_len: u32,
|
||||||
pub data: [Pubkey; 128],
|
pub data: [Pubkey; 128],
|
||||||
pub data_len: u32,
|
pub data_len: u32,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
use super::QuoteAccountData;
|
||||||
|
use crate::cfg_client;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::{cfg_client, QuoteAccountData, SWITCHBOARD_ATTESTATION_PROGRAM_ID};
|
|
||||||
use anchor_lang::{Discriminator, Owner, ZeroCopy};
|
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
use std::cell::Ref;
|
use std::cell::Ref;
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,8 @@ use std::cell::Ref;
|
||||||
|
|
||||||
use crate::{QUOTE_SEED, SWITCHBOARD_ATTESTATION_PROGRAM_ID};
|
use crate::{QUOTE_SEED, SWITCHBOARD_ATTESTATION_PROGRAM_ID};
|
||||||
|
|
||||||
|
pub type MrEnclave = [u8; 32];
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||||
pub enum VerificationStatus {
|
pub enum VerificationStatus {
|
||||||
|
@ -31,7 +33,7 @@ pub struct QuoteAccountData {
|
||||||
/// Queue used for attestation to verify a MRENCLAVE measurement.
|
/// Queue used for attestation to verify a MRENCLAVE measurement.
|
||||||
pub attestation_queue: Pubkey,
|
pub attestation_queue: Pubkey,
|
||||||
/// The quotes MRENCLAVE measurement dictating the contents of the secure enclave.
|
/// The quotes MRENCLAVE measurement dictating the contents of the secure enclave.
|
||||||
pub mr_enclave: [u8; 32],
|
pub mr_enclave: MrEnclave,
|
||||||
pub verification_status: u8,
|
pub verification_status: u8,
|
||||||
pub verification_timestamp: i64,
|
pub verification_timestamp: i64,
|
||||||
pub valid_until: i64,
|
pub valid_until: i64,
|
||||||
|
|
|
@ -1,8 +1,4 @@
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use anchor_lang::solana_program::entrypoint::ProgramResult;
|
|
||||||
use anchor_lang::solana_program::instruction::Instruction;
|
|
||||||
use anchor_lang::solana_program::program::{invoke, invoke_signed};
|
|
||||||
use anchor_lang::{Discriminator, InstructionData};
|
|
||||||
|
|
||||||
#[derive(Accounts)]
|
#[derive(Accounts)]
|
||||||
#[instruction(params: FunctionTriggerParams)] // rpc parameters hint
|
#[instruction(params: FunctionTriggerParams)] // rpc parameters hint
|
||||||
|
|
|
@ -1,10 +1,4 @@
|
||||||
use crate::cfg_client;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use anchor_lang::solana_program::entrypoint::ProgramResult;
|
|
||||||
use anchor_lang::solana_program::instruction::Instruction;
|
|
||||||
use anchor_lang::solana_program::program::{invoke, invoke_signed};
|
|
||||||
use anchor_lang::{Discriminator, InstructionData};
|
|
||||||
use anchor_spl::token::TokenAccount;
|
|
||||||
|
|
||||||
#[derive(Accounts)]
|
#[derive(Accounts)]
|
||||||
#[instruction(params: FunctionVerifyParams)] // rpc parameters hint
|
#[instruction(params: FunctionVerifyParams)] // rpc parameters hint
|
||||||
|
@ -201,203 +195,4 @@ impl<'info> FunctionVerify<'info> {
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg_client! {
|
|
||||||
pub async fn build(
|
|
||||||
client: &solana_client::rpc_client::RpcClient,
|
|
||||||
fn_signer: std::sync::Arc<solana_sdk::signer::keypair::Keypair>,
|
|
||||||
pubkeys: &FunctionVerifyPubkeys,
|
|
||||||
mr_enclave: [u8; 32],
|
|
||||||
) -> std::result::Result<Instruction, switchboard_common::error::Error> {
|
|
||||||
let fn_signer_pubkey = crate::client::to_pubkey(fn_signer)?;
|
|
||||||
|
|
||||||
let current_time = std::time::SystemTime::now()
|
|
||||||
.duration_since(std::time::UNIX_EPOCH)
|
|
||||||
.unwrap()
|
|
||||||
.as_secs() as i64;
|
|
||||||
|
|
||||||
let fn_data: FunctionAccountData = load_account(&client, pubkeys.function).await?;
|
|
||||||
|
|
||||||
let verifier_quote: QuoteAccountData = load_account(&client, pubkeys.verifier).await?;
|
|
||||||
|
|
||||||
let queue_data: AttestationQueueAccountData =
|
|
||||||
crate::client::load_account(&client, fn_data.attestation_queue).await?;
|
|
||||||
|
|
||||||
// let escrow = fn_data.escrow;
|
|
||||||
let (fn_quote, _) = Pubkey::find_program_address(
|
|
||||||
&[b"QuoteAccountData", &pubkeys.function.to_bytes()],
|
|
||||||
&SWITCHBOARD_ATTESTATION_PROGRAM_ID,
|
|
||||||
);
|
|
||||||
|
|
||||||
let (verifier_permission, _) = Pubkey::find_program_address(
|
|
||||||
&[
|
|
||||||
b"PermissionAccountData",
|
|
||||||
&queue_data.authority.to_bytes(),
|
|
||||||
&fn_data.attestation_queue.to_bytes(),
|
|
||||||
&pubkeys.payer.to_bytes(),
|
|
||||||
],
|
|
||||||
&SWITCHBOARD_ATTESTATION_PROGRAM_ID,
|
|
||||||
);
|
|
||||||
|
|
||||||
let (fn_permission, _) = Pubkey::find_program_address(
|
|
||||||
&[
|
|
||||||
b"PermissionAccountData",
|
|
||||||
&queue_data.authority.to_bytes(),
|
|
||||||
&fn_data.attestation_queue.to_bytes(),
|
|
||||||
&pubkeys.function.to_bytes(),
|
|
||||||
],
|
|
||||||
&SWITCHBOARD_ATTESTATION_PROGRAM_ID,
|
|
||||||
);
|
|
||||||
|
|
||||||
let (state, _) =
|
|
||||||
Pubkey::find_program_address(&[b"STATE"], &SWITCHBOARD_ATTESTATION_PROGRAM_ID);
|
|
||||||
|
|
||||||
let accounts = FunctionVerifyAccounts {
|
|
||||||
function: pubkeys.function,
|
|
||||||
fn_signer: fn_signer_pubkey,
|
|
||||||
fn_quote,
|
|
||||||
verifier_quote: pubkeys.verifier,
|
|
||||||
secured_signer: verifier_quote.authority,
|
|
||||||
attestation_queue: fn_data.attestation_queue,
|
|
||||||
escrow: fn_data.escrow,
|
|
||||||
receiver: pubkeys.reward_receiver,
|
|
||||||
verifier_permission,
|
|
||||||
fn_permission,
|
|
||||||
state,
|
|
||||||
token_program: anchor_spl::token::ID,
|
|
||||||
payer: pubkeys.payer,
|
|
||||||
system_program: anchor_lang::solana_program::system_program::ID,
|
|
||||||
};
|
|
||||||
|
|
||||||
let next_allowed_timestamp = fn_data
|
|
||||||
.next_execution_timestamp()
|
|
||||||
.map(|x| x.timestamp())
|
|
||||||
.unwrap_or(i64::MAX);
|
|
||||||
|
|
||||||
Ok(Self::build_ix(
|
|
||||||
accounts,
|
|
||||||
current_time,
|
|
||||||
next_allowed_timestamp,
|
|
||||||
false,
|
|
||||||
mr_enclave,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn build_ix(
|
|
||||||
accounts: FunctionVerifyAccounts,
|
|
||||||
observed_time: i64,
|
|
||||||
next_allowed_timestamp: i64,
|
|
||||||
is_failure: bool,
|
|
||||||
mr_enclave: [u8; 32],
|
|
||||||
) -> Instruction {
|
|
||||||
Instruction {
|
|
||||||
program_id: SWITCHBOARD_ATTESTATION_PROGRAM_ID,
|
|
||||||
accounts: accounts.to_account_metas(None),
|
|
||||||
data: FunctionVerifyParams {
|
|
||||||
observed_time,
|
|
||||||
next_allowed_timestamp,
|
|
||||||
is_failure,
|
|
||||||
mr_enclave,
|
|
||||||
}
|
|
||||||
.data(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg_client! {
|
|
||||||
pub struct FunctionVerifyAccounts {
|
|
||||||
pub function: Pubkey,
|
|
||||||
pub fn_signer: Pubkey,
|
|
||||||
pub fn_quote: Pubkey,
|
|
||||||
pub verifier_quote: Pubkey,
|
|
||||||
pub secured_signer: Pubkey,
|
|
||||||
pub attestation_queue: Pubkey,
|
|
||||||
pub escrow: Pubkey,
|
|
||||||
pub receiver: Pubkey,
|
|
||||||
pub verifier_permission: Pubkey,
|
|
||||||
pub fn_permission: Pubkey,
|
|
||||||
pub state: Pubkey,
|
|
||||||
pub token_program: Pubkey,
|
|
||||||
pub payer: Pubkey,
|
|
||||||
pub system_program: Pubkey,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToAccountMetas for FunctionVerifyAccounts {
|
|
||||||
fn to_account_metas(&self, _: Option<bool>) -> Vec<AccountMeta> {
|
|
||||||
vec![
|
|
||||||
AccountMeta {
|
|
||||||
pubkey: self.function,
|
|
||||||
is_signer: false,
|
|
||||||
is_writable: true,
|
|
||||||
},
|
|
||||||
AccountMeta {
|
|
||||||
pubkey: self.fn_signer,
|
|
||||||
is_signer: true,
|
|
||||||
is_writable: false,
|
|
||||||
},
|
|
||||||
AccountMeta {
|
|
||||||
pubkey: self.fn_quote,
|
|
||||||
is_signer: false,
|
|
||||||
is_writable: true,
|
|
||||||
},
|
|
||||||
AccountMeta {
|
|
||||||
pubkey: self.verifier_quote,
|
|
||||||
is_signer: false,
|
|
||||||
is_writable: false,
|
|
||||||
},
|
|
||||||
AccountMeta {
|
|
||||||
pubkey: self.secured_signer,
|
|
||||||
is_signer: true,
|
|
||||||
is_writable: false,
|
|
||||||
},
|
|
||||||
AccountMeta {
|
|
||||||
pubkey: self.attestation_queue,
|
|
||||||
is_signer: false,
|
|
||||||
is_writable: false,
|
|
||||||
},
|
|
||||||
AccountMeta {
|
|
||||||
pubkey: self.escrow,
|
|
||||||
is_signer: false,
|
|
||||||
is_writable: true,
|
|
||||||
},
|
|
||||||
AccountMeta {
|
|
||||||
pubkey: self.receiver,
|
|
||||||
is_signer: false,
|
|
||||||
is_writable: true,
|
|
||||||
},
|
|
||||||
AccountMeta {
|
|
||||||
pubkey: self.verifier_permission,
|
|
||||||
is_signer: false,
|
|
||||||
is_writable: false,
|
|
||||||
},
|
|
||||||
AccountMeta {
|
|
||||||
pubkey: self.fn_permission,
|
|
||||||
is_signer: false,
|
|
||||||
is_writable: false,
|
|
||||||
},
|
|
||||||
AccountMeta {
|
|
||||||
pubkey: self.state,
|
|
||||||
is_signer: false,
|
|
||||||
is_writable: true,
|
|
||||||
},
|
|
||||||
AccountMeta {
|
|
||||||
pubkey: self.token_program,
|
|
||||||
is_signer: false,
|
|
||||||
is_writable: false,
|
|
||||||
},
|
|
||||||
AccountMeta {
|
|
||||||
pubkey: self.payer,
|
|
||||||
is_signer: true,
|
|
||||||
is_writable: true,
|
|
||||||
},
|
|
||||||
AccountMeta {
|
|
||||||
pubkey: self.system_program,
|
|
||||||
is_signer: false,
|
|
||||||
is_writable: false,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,296 @@
|
||||||
|
use crate::prelude::*;
|
||||||
|
use anchor_lang::solana_program::instruction::Instruction;
|
||||||
|
use anchor_lang::solana_program::message::Message;
|
||||||
|
use anchor_lang::solana_program::pubkey::Pubkey;
|
||||||
|
use sgx_quote::Quote;
|
||||||
|
use solana_client::rpc_client::RpcClient;
|
||||||
|
use solana_sdk::commitment_config::CommitmentConfig;
|
||||||
|
use solana_sdk::signer::keypair::Keypair;
|
||||||
|
use std::result::Result;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct FunctionRunner {
|
||||||
|
pub client: Arc<RpcClient>,
|
||||||
|
|
||||||
|
signer_keypair: Arc<Keypair>,
|
||||||
|
pub signer: Pubkey,
|
||||||
|
|
||||||
|
pub function: Pubkey,
|
||||||
|
pub quote: Pubkey,
|
||||||
|
pub payer: Pubkey,
|
||||||
|
pub verifier: Pubkey,
|
||||||
|
pub reward_receiver: Pubkey,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for FunctionRunner {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"SwitchboardFunctionRunner: url: {}, signer: {}, function: {}, verifier: {}",
|
||||||
|
self.client.url(),
|
||||||
|
self.signer,
|
||||||
|
self.function.to_string(),
|
||||||
|
self.verifier.to_string()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FunctionRunner {
|
||||||
|
pub fn new_with_client(client: RpcClient) -> Result<Self, SwitchboardClientError> {
|
||||||
|
let signer_keypair = generate_signer();
|
||||||
|
let signer = signer_to_pubkey(signer_keypair.clone())?;
|
||||||
|
|
||||||
|
let function = load_env_pubkey("FUNCTION_KEY")?;
|
||||||
|
let payer = load_env_pubkey("PAYER")?;
|
||||||
|
let verifier = load_env_pubkey("VERIFIER")?;
|
||||||
|
let reward_receiver = load_env_pubkey("REWARD_RECEIVER")?;
|
||||||
|
|
||||||
|
let (quote, _bump) = Pubkey::find_program_address(
|
||||||
|
&[QUOTE_SEED, function.as_ref()],
|
||||||
|
&SWITCHBOARD_ATTESTATION_PROGRAM_ID,
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
client: Arc::new(client),
|
||||||
|
signer_keypair,
|
||||||
|
signer,
|
||||||
|
function,
|
||||||
|
quote,
|
||||||
|
payer,
|
||||||
|
verifier,
|
||||||
|
reward_receiver,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(
|
||||||
|
url: &str,
|
||||||
|
commitment: Option<CommitmentConfig>,
|
||||||
|
) -> Result<Self, SwitchboardClientError> {
|
||||||
|
Self::new_with_client(RpcClient::new_with_commitment(
|
||||||
|
url,
|
||||||
|
commitment.unwrap_or_default(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_from_cluster(
|
||||||
|
cluster: Cluster,
|
||||||
|
commitment: Option<CommitmentConfig>,
|
||||||
|
) -> Result<Self, SwitchboardClientError> {
|
||||||
|
Self::new(cluster.url(), commitment)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn build_verify_ixn(
|
||||||
|
&self,
|
||||||
|
mr_enclave: MrEnclave,
|
||||||
|
) -> Result<Instruction, SwitchboardClientError> {
|
||||||
|
let current_time = std::time::SystemTime::now()
|
||||||
|
.duration_since(std::time::UNIX_EPOCH)
|
||||||
|
.unwrap()
|
||||||
|
.as_secs() as i64;
|
||||||
|
|
||||||
|
let fn_data: FunctionAccountData = load_account(&self.client, self.function).await?;
|
||||||
|
|
||||||
|
let verifier_quote: QuoteAccountData = load_account(&self.client, self.verifier).await?;
|
||||||
|
|
||||||
|
let queue_data: AttestationQueueAccountData =
|
||||||
|
crate::client::load_account(&self.client, fn_data.attestation_queue).await?;
|
||||||
|
|
||||||
|
// let escrow = fn_data.escrow;
|
||||||
|
let (fn_quote, _) = Pubkey::find_program_address(
|
||||||
|
&[b"QuoteAccountData", &self.function.to_bytes()],
|
||||||
|
&SWITCHBOARD_ATTESTATION_PROGRAM_ID,
|
||||||
|
);
|
||||||
|
|
||||||
|
let (verifier_permission, _) = Pubkey::find_program_address(
|
||||||
|
&[
|
||||||
|
b"PermissionAccountData",
|
||||||
|
&queue_data.authority.to_bytes(),
|
||||||
|
&fn_data.attestation_queue.to_bytes(),
|
||||||
|
&self.payer.to_bytes(), // assuming the verifier payer is also the authority
|
||||||
|
],
|
||||||
|
&SWITCHBOARD_ATTESTATION_PROGRAM_ID,
|
||||||
|
);
|
||||||
|
|
||||||
|
let (fn_permission, _) = Pubkey::find_program_address(
|
||||||
|
&[
|
||||||
|
b"PermissionAccountData",
|
||||||
|
&queue_data.authority.to_bytes(),
|
||||||
|
&fn_data.attestation_queue.to_bytes(),
|
||||||
|
&self.function.to_bytes(),
|
||||||
|
],
|
||||||
|
&SWITCHBOARD_ATTESTATION_PROGRAM_ID,
|
||||||
|
);
|
||||||
|
|
||||||
|
let (state, _) =
|
||||||
|
Pubkey::find_program_address(&[b"STATE"], &SWITCHBOARD_ATTESTATION_PROGRAM_ID);
|
||||||
|
|
||||||
|
let pubkeys = FunctionVerifyPubkeys {
|
||||||
|
function: self.function,
|
||||||
|
fn_signer: self.signer,
|
||||||
|
fn_quote,
|
||||||
|
verifier_quote: self.verifier,
|
||||||
|
secured_signer: verifier_quote.authority,
|
||||||
|
attestation_queue: fn_data.attestation_queue,
|
||||||
|
escrow: fn_data.escrow,
|
||||||
|
receiver: self.reward_receiver,
|
||||||
|
verifier_permission,
|
||||||
|
fn_permission,
|
||||||
|
state,
|
||||||
|
token_program: anchor_spl::token::ID,
|
||||||
|
payer: self.payer,
|
||||||
|
system_program: anchor_lang::solana_program::system_program::ID,
|
||||||
|
};
|
||||||
|
|
||||||
|
let next_allowed_timestamp = fn_data
|
||||||
|
.next_execution_timestamp()
|
||||||
|
.map(|x| x.timestamp())
|
||||||
|
.unwrap_or(i64::MAX);
|
||||||
|
|
||||||
|
let ixn_params = FunctionVerifyParams {
|
||||||
|
observed_time: current_time,
|
||||||
|
next_allowed_timestamp,
|
||||||
|
is_failure: false,
|
||||||
|
mr_enclave,
|
||||||
|
};
|
||||||
|
let ixn = Instruction {
|
||||||
|
program_id: SWITCHBOARD_ATTESTATION_PROGRAM_ID,
|
||||||
|
accounts: pubkeys.to_account_metas(None),
|
||||||
|
data: ixn_params.data(),
|
||||||
|
};
|
||||||
|
Ok(ixn)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_result(
|
||||||
|
&self,
|
||||||
|
mut ixs: Vec<Instruction>,
|
||||||
|
) -> Result<FunctionResult, SwitchboardClientError> {
|
||||||
|
let quote_raw = Gramine::generate_quote(&self.signer.to_bytes()).unwrap();
|
||||||
|
let quote = Quote::parse("e_raw).unwrap();
|
||||||
|
let mr_enclave: MrEnclave = quote.isv_report.mrenclave.try_into().unwrap();
|
||||||
|
|
||||||
|
let verify_ixn = self.build_verify_ixn(mr_enclave).await?;
|
||||||
|
ixs.insert(0, verify_ixn);
|
||||||
|
let message = Message::new(&ixs, Some(&self.payer));
|
||||||
|
let blockhash = self.client.get_latest_blockhash().unwrap();
|
||||||
|
let mut tx = solana_sdk::transaction::Transaction::new_unsigned(message);
|
||||||
|
tx.partial_sign(&[self.signer_keypair.as_ref()], blockhash);
|
||||||
|
|
||||||
|
Ok(FunctionResult {
|
||||||
|
version: 1,
|
||||||
|
chain: switchboard_common::Chain::Solana,
|
||||||
|
key: self.function.to_bytes(),
|
||||||
|
signer: self.signer.to_bytes(),
|
||||||
|
serialized_tx: bincode::serialize(&tx).unwrap(),
|
||||||
|
quote: quote_raw,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn emit(&self, ixs: Vec<Instruction>) -> Result<(), SwitchboardClientError> {
|
||||||
|
self.get_result(ixs)
|
||||||
|
.await
|
||||||
|
.map_err(|e| SwitchboardClientError::CustomError {
|
||||||
|
message: "failed to run function verify".to_string(),
|
||||||
|
source: Box::new(e),
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
|
.emit();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FunctionVerifyPubkeys {
|
||||||
|
pub function: Pubkey,
|
||||||
|
pub fn_signer: Pubkey,
|
||||||
|
pub fn_quote: Pubkey,
|
||||||
|
pub verifier_quote: Pubkey,
|
||||||
|
pub secured_signer: Pubkey,
|
||||||
|
pub attestation_queue: Pubkey,
|
||||||
|
pub escrow: Pubkey,
|
||||||
|
pub receiver: Pubkey,
|
||||||
|
pub verifier_permission: Pubkey,
|
||||||
|
pub fn_permission: Pubkey,
|
||||||
|
pub state: Pubkey,
|
||||||
|
pub token_program: Pubkey,
|
||||||
|
pub payer: Pubkey,
|
||||||
|
pub system_program: Pubkey,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToAccountMetas for FunctionVerifyPubkeys {
|
||||||
|
fn to_account_metas(&self, _: Option<bool>) -> Vec<AccountMeta> {
|
||||||
|
vec![
|
||||||
|
AccountMeta {
|
||||||
|
pubkey: self.function,
|
||||||
|
is_signer: false,
|
||||||
|
is_writable: true,
|
||||||
|
},
|
||||||
|
AccountMeta {
|
||||||
|
pubkey: self.fn_signer,
|
||||||
|
is_signer: true,
|
||||||
|
is_writable: false,
|
||||||
|
},
|
||||||
|
AccountMeta {
|
||||||
|
pubkey: self.fn_quote,
|
||||||
|
is_signer: false,
|
||||||
|
is_writable: true,
|
||||||
|
},
|
||||||
|
AccountMeta {
|
||||||
|
pubkey: self.verifier_quote,
|
||||||
|
is_signer: false,
|
||||||
|
is_writable: false,
|
||||||
|
},
|
||||||
|
AccountMeta {
|
||||||
|
pubkey: self.secured_signer,
|
||||||
|
is_signer: true,
|
||||||
|
is_writable: false,
|
||||||
|
},
|
||||||
|
AccountMeta {
|
||||||
|
pubkey: self.attestation_queue,
|
||||||
|
is_signer: false,
|
||||||
|
is_writable: false,
|
||||||
|
},
|
||||||
|
AccountMeta {
|
||||||
|
pubkey: self.escrow,
|
||||||
|
is_signer: false,
|
||||||
|
is_writable: true,
|
||||||
|
},
|
||||||
|
AccountMeta {
|
||||||
|
pubkey: self.receiver,
|
||||||
|
is_signer: false,
|
||||||
|
is_writable: true,
|
||||||
|
},
|
||||||
|
AccountMeta {
|
||||||
|
pubkey: self.verifier_permission,
|
||||||
|
is_signer: false,
|
||||||
|
is_writable: false,
|
||||||
|
},
|
||||||
|
AccountMeta {
|
||||||
|
pubkey: self.fn_permission,
|
||||||
|
is_signer: false,
|
||||||
|
is_writable: false,
|
||||||
|
},
|
||||||
|
AccountMeta {
|
||||||
|
pubkey: self.state,
|
||||||
|
is_signer: false,
|
||||||
|
is_writable: true,
|
||||||
|
},
|
||||||
|
AccountMeta {
|
||||||
|
pubkey: self.token_program,
|
||||||
|
is_signer: false,
|
||||||
|
is_writable: false,
|
||||||
|
},
|
||||||
|
AccountMeta {
|
||||||
|
pubkey: self.payer,
|
||||||
|
is_signer: true,
|
||||||
|
is_writable: true,
|
||||||
|
},
|
||||||
|
AccountMeta {
|
||||||
|
pubkey: self.system_program,
|
||||||
|
is_signer: false,
|
||||||
|
is_writable: false,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,100 +0,0 @@
|
||||||
use crate::prelude::*;
|
|
||||||
|
|
||||||
use anchor_lang::solana_program::instruction::Instruction;
|
|
||||||
use anchor_lang::solana_program::message::Message;
|
|
||||||
use anchor_lang::solana_program::pubkey::Pubkey;
|
|
||||||
use sgx_quote::Quote;
|
|
||||||
use solana_sdk::signer::keypair::Keypair;
|
|
||||||
|
|
||||||
use std::env;
|
|
||||||
use std::result::Result;
|
|
||||||
use std::str::FromStr;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use crate::attestation_program::FunctionVerify;
|
|
||||||
use crate::{QUOTE_SEED, SWITCHBOARD_ATTESTATION_PROGRAM_ID};
|
|
||||||
|
|
||||||
pub async fn function_verify(
|
|
||||||
url: String,
|
|
||||||
fn_signer: Arc<Keypair>,
|
|
||||||
mut ixs: Vec<Instruction>,
|
|
||||||
) -> Result<switchboard_common::FunctionResult, switchboard_common::Error> {
|
|
||||||
let fn_signer_pubkey = crate::client::to_pubkey(fn_signer.clone())?;
|
|
||||||
|
|
||||||
let client = solana_client::rpc_client::RpcClient::new_with_commitment(
|
|
||||||
url,
|
|
||||||
solana_sdk::commitment_config::CommitmentConfig::processed(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let quote_raw =
|
|
||||||
switchboard_common::Gramine::generate_quote(&fn_signer_pubkey.to_bytes()).unwrap();
|
|
||||||
let quote = Quote::parse("e_raw).unwrap();
|
|
||||||
|
|
||||||
let pubkeys = FunctionVerifyPubkeys::load_from_env()?;
|
|
||||||
|
|
||||||
let ix = FunctionVerify::build(
|
|
||||||
&client,
|
|
||||||
fn_signer.clone(),
|
|
||||||
&pubkeys,
|
|
||||||
quote.isv_report.mrenclave.try_into().unwrap(),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
ixs.insert(0, ix);
|
|
||||||
|
|
||||||
let message = Message::new(&ixs, Some(&pubkeys.payer));
|
|
||||||
|
|
||||||
let blockhash = client.get_latest_blockhash().unwrap();
|
|
||||||
|
|
||||||
let mut tx = solana_sdk::transaction::Transaction::new_unsigned(message);
|
|
||||||
tx.partial_sign(&[fn_signer.as_ref()], blockhash);
|
|
||||||
|
|
||||||
Ok(switchboard_common::FunctionResult {
|
|
||||||
version: 1,
|
|
||||||
chain: switchboard_common::Chain::Solana,
|
|
||||||
key: pubkeys.function.to_bytes(),
|
|
||||||
signer: fn_signer_pubkey.to_bytes(),
|
|
||||||
serialized_tx: bincode::serialize(&tx).unwrap(),
|
|
||||||
quote: quote_raw,
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct FunctionVerifyPubkeys {
|
|
||||||
pub function: Pubkey,
|
|
||||||
pub quote: Pubkey,
|
|
||||||
pub payer: Pubkey,
|
|
||||||
pub verifier: Pubkey,
|
|
||||||
pub reward_receiver: Pubkey,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FunctionVerifyPubkeys {
|
|
||||||
pub fn load_from_env() -> std::result::Result<Self, switchboard_common::Error> {
|
|
||||||
let function = Pubkey::from_str(&env::var("FUNCTION_KEY").unwrap()).unwrap();
|
|
||||||
let payer = Pubkey::from_str(&env::var("PAYER").unwrap()).unwrap();
|
|
||||||
|
|
||||||
let verifier = &env::var("VERIFIER").unwrap_or(String::new());
|
|
||||||
if verifier.is_empty() {
|
|
||||||
return Err(switchboard_common::Error::CustomMessage(
|
|
||||||
"verifier missing".to_string(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let (quote, _bump) = Pubkey::find_program_address(
|
|
||||||
&[QUOTE_SEED, function.as_ref()],
|
|
||||||
&SWITCHBOARD_ATTESTATION_PROGRAM_ID,
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
function,
|
|
||||||
quote,
|
|
||||||
payer,
|
|
||||||
verifier: Pubkey::from_str(verifier).map_err(|_| {
|
|
||||||
switchboard_common::Error::CustomMessage(
|
|
||||||
"failed to parse pubkey string".to_string(),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
reward_receiver: Pubkey::from_str(&env::var("REWARD_RECEIVER").unwrap()).unwrap(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +1,5 @@
|
||||||
pub mod function_verify;
|
pub mod function_runner;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
pub use function_verify::*;
|
pub use function_runner::*;
|
||||||
pub use utils::*;
|
pub use utils::*;
|
||||||
|
|
|
@ -1,8 +1,15 @@
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use solana_sdk::signer::keypair::{keypair_from_seed, Keypair};
|
use solana_sdk::signer::keypair::{keypair_from_seed, Keypair};
|
||||||
|
use std::env;
|
||||||
use std::result::Result;
|
use std::result::Result;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
|
pub fn load_env_pubkey(key: &str) -> Result<Pubkey, SwitchboardClientError> {
|
||||||
|
Pubkey::from_str(&env::var(key).unwrap())
|
||||||
|
.map_err(|_| SwitchboardClientError::EnvVariableMissing(key.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn generate_signer() -> Arc<Keypair> {
|
pub fn generate_signer() -> Arc<Keypair> {
|
||||||
let mut randomness = [0; 32];
|
let mut randomness = [0; 32];
|
||||||
|
@ -10,9 +17,11 @@ pub fn generate_signer() -> Arc<Keypair> {
|
||||||
Arc::new(keypair_from_seed(&randomness).unwrap())
|
Arc::new(keypair_from_seed(&randomness).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_pubkey(signer: Arc<Keypair>) -> std::result::Result<Pubkey, switchboard_common::Error> {
|
pub fn signer_to_pubkey(
|
||||||
|
signer: Arc<Keypair>,
|
||||||
|
) -> std::result::Result<Pubkey, SwitchboardClientError> {
|
||||||
let pubkey = Pubkey::from_str(signer.to_base58_string().as_str()).map_err(|_| {
|
let pubkey = Pubkey::from_str(signer.to_base58_string().as_str()).map_err(|_| {
|
||||||
switchboard_common::Error::CustomMessage("failed to parse pubkey string".to_string())
|
SwitchboardClientError::CustomMessage("failed to parse pubkey string".to_string())
|
||||||
})?;
|
})?;
|
||||||
Ok(pubkey)
|
Ok(pubkey)
|
||||||
}
|
}
|
||||||
|
@ -20,10 +29,19 @@ pub fn to_pubkey(signer: Arc<Keypair>) -> std::result::Result<Pubkey, switchboar
|
||||||
pub async fn load_account<T: bytemuck::Pod>(
|
pub async fn load_account<T: bytemuck::Pod>(
|
||||||
client: &solana_client::rpc_client::RpcClient,
|
client: &solana_client::rpc_client::RpcClient,
|
||||||
pubkey: Pubkey,
|
pubkey: Pubkey,
|
||||||
) -> Result<T, switchboard_common::Error> {
|
) -> Result<T, SwitchboardClientError> {
|
||||||
let data = client
|
let data = client
|
||||||
.get_account_data(&pubkey)
|
.get_account_data(&pubkey)
|
||||||
.map_err(|_| switchboard_common::Error::CustomMessage("AnchorParseError".to_string()))?;
|
.map_err(|_| SwitchboardClientError::CustomMessage("AnchorParseError".to_string()))?;
|
||||||
Ok(*bytemuck::try_from_bytes::<T>(&data[8..])
|
Ok(*bytemuck::try_from_bytes::<T>(&data[8..])
|
||||||
.map_err(|_| switchboard_common::Error::CustomMessage("AnchorParseError".to_string()))?)
|
.map_err(|_| SwitchboardClientError::CustomMessage("AnchorParseError".to_string()))?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unix_timestamp() -> i64 {
|
||||||
|
SystemTime::now()
|
||||||
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.unwrap_or_default()
|
||||||
|
.as_secs()
|
||||||
|
.try_into()
|
||||||
|
.unwrap_or(0)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,6 @@ pub use oracle_program::*;
|
||||||
pub mod attestation_program;
|
pub mod attestation_program;
|
||||||
pub use attestation_program::*;
|
pub use attestation_program::*;
|
||||||
|
|
||||||
pub use switchboard_common::{Chain, Error as SwitchboardClientError, FunctionResult};
|
|
||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
|
||||||
pub mod seeds;
|
pub mod seeds;
|
||||||
|
|
|
@ -17,6 +17,8 @@ pub use rust_decimal;
|
||||||
cfg_client! {
|
cfg_client! {
|
||||||
pub use crate::client::*;
|
pub use crate::client::*;
|
||||||
|
|
||||||
|
pub use switchboard_common::Gramine;
|
||||||
|
|
||||||
pub use anchor_client;
|
pub use anchor_client;
|
||||||
pub use anchor_client::anchor_lang;
|
pub use anchor_client::anchor_lang;
|
||||||
pub use anchor_client::solana_client;
|
pub use anchor_client::solana_client;
|
||||||
|
@ -24,6 +26,8 @@ cfg_client! {
|
||||||
pub use anchor_client::anchor_lang::solana_program;
|
pub use anchor_client::anchor_lang::solana_program;
|
||||||
pub use anchor_client::Cluster;
|
pub use anchor_client::Cluster;
|
||||||
|
|
||||||
|
pub use solana_sdk::signer::keypair::{keypair_from_seed, Keypair};
|
||||||
|
|
||||||
pub use anchor_lang::prelude::*;
|
pub use anchor_lang::prelude::*;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,4 +39,10 @@ cfg_program! {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use anchor_lang::prelude::*;
|
pub use anchor_lang::prelude::*;
|
||||||
pub use anchor_lang::{Discriminator, Owner, ZeroCopy};
|
pub use anchor_lang::{
|
||||||
|
AnchorDeserialize, AnchorSerialize, Discriminator, InstructionData, Owner, ZeroCopy,
|
||||||
|
};
|
||||||
|
pub use anchor_spl::token::{Mint, TokenAccount};
|
||||||
|
pub use solana_program::entrypoint::ProgramResult;
|
||||||
|
pub use solana_program::instruction::Instruction;
|
||||||
|
pub use solana_program::program::{invoke, invoke_signed};
|
||||||
|
|
|
@ -8,6 +8,6 @@ pub use crate::oracle_program::{
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use crate::attestation_program::{
|
pub use crate::attestation_program::{
|
||||||
FunctionStatus, FunctionTriggerParams, FunctionVerifyParams, SwitchboardAttestationPermission,
|
FunctionStatus, FunctionTriggerParams, FunctionVerifyParams, MrEnclave,
|
||||||
VerificationStatus,
|
SwitchboardAttestationPermission, VerificationStatus,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue