use crate::*;
use solana_sdk::message::Message;
use solana_sdk::signature::Signature;
use solana_sdk::signer::keypair::Keypair;
use solana_sdk::signer::Signer;
use solana_sdk::transaction::Transaction;
#[derive(Default)]
pub struct BootstrapAttestationQueueParams {
pub reward: Option<u32>,
pub allow_authority_override_after: Option<u32>,
pub max_quote_verification_age: Option<u32>,
pub require_authority_heartbeat_permission: Option<bool>,
pub require_usage_permissions: Option<bool>,
pub node_timeout: Option<u32>,
pub queue_keypair: Option<Keypair>,
pub authority_keypair: Option<Keypair>,
pub verifier_enclave: Option<Vec<u8>>,
pub registry_key: Option<Vec<u8>>,
pub enclave_signer: Option<Keypair>,
}
pub struct BootstrappedAttestationQueue {
pub txn: Signature,
pub attestation_queue: Pubkey,
pub queue_authority: Pubkey,
pub verifier: Pubkey,
pub verifier_permission: Pubkey,
pub verifier_signer: Keypair,
}
pub const DEFAULT_VERIFIER_MR_ENCLAVE: [u8; 32] = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
27, 28, 29, 30, 31, 32,
];
pub async fn create_attestation_queue(
client: &solana_client::rpc_client::RpcClient,
payer: &Keypair,
params: Option<BootstrapAttestationQueueParams>,
) -> std::result::Result<BootstrappedAttestationQueue, switchboard_common::SbError> {
let params = params.unwrap_or_default();
let mut signers: Vec<&Keypair> = vec![payer];
let mut authority_pubkey = payer.pubkey();
if let Some(authority_keypair) = params.authority_keypair.as_ref() {
signers.push(authority_keypair);
authority_pubkey = authority_keypair.pubkey();
}
let queue_keypair = params.queue_keypair.unwrap_or(Keypair::new());
signers.push(&queue_keypair);
let verifier_keypair = Keypair::new();
signers.push(&verifier_keypair);
let verifier_signer = params.enclave_signer.unwrap_or(Keypair::new());
signers.push(&verifier_signer);
let attestation_queue_init_ixn = AttestationQueueInit::build_ix(&AttestationQueueInitArgs {
attestation_queue: queue_keypair.pubkey(),
queue_authority: Some(authority_pubkey),
payer: payer.pubkey(),
allow_authority_override_after: params.allow_authority_override_after.unwrap_or(180),
require_authority_heartbeat_permission: params
.require_authority_heartbeat_permission
.unwrap_or_default(),
require_usage_permissions: params.require_usage_permissions.unwrap_or_default(),
max_quote_verification_age: params.max_quote_verification_age.unwrap_or(10),
reward: params.reward.unwrap_or_default(),
node_timeout: params.node_timeout.unwrap_or(180),
})?;
let mut verifier_enclave = DEFAULT_VERIFIER_MR_ENCLAVE;
if let Some(verifier_enclave_measurement) = params.verifier_enclave {
if verifier_enclave_measurement.len() != 32 {
return Err(switchboard_common::SbError::Message(
"InvalidVerifierEnclaveMeasurement",
));
}
verifier_enclave = verifier_enclave_measurement.try_into().unwrap();
}
let attestation_queue_add_mr_enclave_ixn =
AttestationQueueAddMrEnclave::build_ix(&AttestationQueueAddMrEnclaveArgs {
attestation_queue: queue_keypair.pubkey(),
queue_authority: authority_pubkey,
mr_enclave: verifier_enclave,
})?;
let verifier_init_ixn = VerifierInit::build_ix(&VerifierInitArgs {
verifier: verifier_keypair.pubkey(),
attestation_queue: queue_keypair.pubkey(),
queue_authority: authority_pubkey,
payer: payer.pubkey(),
})?;
let verifier_permission_init_ixn = AttestationPermissionInit::build_ix(
queue_keypair.pubkey(),
authority_pubkey,
verifier_keypair.pubkey(),
payer.pubkey(),
)?;
let attestation_permission_set_ixn = AttestationPermissionSet::build_ix(
queue_keypair.pubkey(),
authority_pubkey,
verifier_keypair.pubkey(),
SwitchboardAttestationPermission::PermitNodeheartbeat,
true,
)?;
let mut registry_key = [0u8; 64];
if let Some(registry_key_vec) = params.registry_key {
if registry_key_vec.len() > 64 {
return Err(switchboard_common::SbError::Message(
"Registry key must be less than 64 bytes",
));
}
registry_key[0..registry_key_vec.len()].copy_from_slice(®istry_key_vec[..]);
}
let verifier_quote_rotate_ixn = VerifierQuoteRotate::build_ix(
&verifier_keypair.pubkey(),
&authority_pubkey,
&queue_keypair.pubkey(),
&verifier_signer.pubkey(),
registry_key,
)?;
let verifier_heartbeat_ixn = VerifierHeartbeat::build_ix(VerifierHeartbeatArgs {
verifier: verifier_keypair.pubkey(),
enclave_signer: verifier_signer.pubkey(),
attestation_queue: queue_keypair.pubkey(),
queue_authority: authority_pubkey,
gc_node: Pubkey::default(),
})?;
let blockhash = client
.get_latest_blockhash()
.map_err(|e| SbError::CustomError {
message: "failed to fetch recent blockhash".to_string(),
source: std::sync::Arc::new(e),
})?;
let tx = Transaction::new(
&signers,
Message::new(
&[
attestation_queue_init_ixn,
attestation_queue_add_mr_enclave_ixn,
verifier_init_ixn,
verifier_permission_init_ixn,
attestation_permission_set_ixn,
verifier_quote_rotate_ixn,
verifier_heartbeat_ixn,
],
Some(&payer.pubkey()),
),
blockhash,
);
let sig = client
.send_and_confirm_transaction(&tx)
.map_err(|e| SbError::CustomError {
message: "failed to send transaction".to_string(),
source: std::sync::Arc::new(e),
})?;
let result = BootstrappedAttestationQueue {
txn: sig,
attestation_queue: queue_keypair.pubkey(),
queue_authority: authority_pubkey,
verifier: verifier_keypair.pubkey(),
verifier_permission: AttestationPermissionAccountData::get_pda(
&authority_pubkey,
&queue_keypair.pubkey(),
&verifier_keypair.pubkey(),
),
verifier_signer: verifier_signer,
};
Ok(result)
}