arcium-client 0.9.2

A client-side library for interacting with the Arcium Solana program.
Documentation
#![allow(clippy::too_many_arguments)]
// We need this because clippy otherwise complains about a function internally generated by anchor's
// declare_program!.
//! Generated modules from the idls of the programs we want to interact with.

use crate::idl::arcium::{
    accounts::{MXEAccount, MxeRecoveryAccount},
    types::{AbortReason, ExecutionFailure, KeyRecoveryFailureReason, MxeStatus, SetUnset},
};
use anchor_lang::{
    declare_program,
    prelude::AccountMeta,
    solana_program::instruction::Instruction,
};
use arcium::types::{
    ArxNodeConfig,
    CallbackAccount,
    CallbackInstruction,
    ComputationReference,
    NodeMetadata,
    NodeRef,
};
use std::hash::{Hash, Hasher};

/// Number of 32-byte elements (matches RESCUE_KEY_COUNT in arcis-compiler).
pub const RESCUE_KEY_COUNT: usize = 5;

declare_program!(arcium);
#[cfg(feature = "staking")]
declare_program!(arcium_staking);

impl Hash for ComputationReference {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.computation_offset.hash(state);
        self.priority_fee.hash(state);
    }
}

impl Eq for ComputationReference {}

impl PartialEq for ComputationReference {
    fn eq(&self, other: &Self) -> bool {
        self.computation_offset == other.computation_offset
            && self.priority_fee == other.priority_fee
    }
}

impl PartialEq for NodeMetadata {
    fn eq(&self, other: &Self) -> bool {
        self.location == other.location && self.ip == other.ip && self.peer_id == other.peer_id
    }
}

impl PartialEq for ArxNodeConfig {
    fn eq(&self, other: &Self) -> bool {
        self.authority == other.authority && self.callback_authority == other.callback_authority
    }
}

impl PartialEq for NodeRef {
    fn eq(&self, other: &Self) -> bool {
        self.offset == other.offset && self.current_total_rewards == other.current_total_rewards
    }
}

impl PartialEq for MxeStatus {
    fn eq(&self, other: &Self) -> bool {
        matches!(
            (self, other),
            (MxeStatus::Active, MxeStatus::Active) | (MxeStatus::Migration, MxeStatus::Migration)
        )
    }
}

impl MXEAccount {
    pub fn x25519_pubkey(&self) -> Option<[u8; 32]> {
        match &self.utility_pubkeys {
            SetUnset::Set(keys) => Some(keys.x25519_pubkey),
            SetUnset::Unset(keys, set_vec) => {
                if set_vec.iter().all(|&b| b) {
                    Some(keys.x25519_pubkey)
                } else {
                    None
                }
            }
        }
    }

    pub fn ed25519_verifying_key(&self) -> Option<[u8; 32]> {
        match &self.utility_pubkeys {
            SetUnset::Set(keys) => Some(keys.ed25519_verifying_key),
            SetUnset::Unset(keys, set_vec) => {
                if set_vec.iter().all(|&b| b) {
                    Some(keys.ed25519_verifying_key)
                } else {
                    None
                }
            }
        }
    }

    pub fn elgamal_pubkey(&self) -> Option<[u8; 32]> {
        match &self.utility_pubkeys {
            SetUnset::Set(keys) => Some(keys.elgamal_pubkey),
            SetUnset::Unset(keys, set_vec) => {
                if set_vec.iter().all(|&b| b) {
                    Some(keys.elgamal_pubkey)
                } else {
                    None
                }
            }
        }
    }
}

impl ExecutionFailure {
    pub fn discriminator(&self) -> u8 {
        match self {
            ExecutionFailure::Serialization => 0,
            ExecutionFailure::Router => 1,
            ExecutionFailure::Circuit => 2,
            ExecutionFailure::Inputs => 3,
            ExecutionFailure::ProtocolInit => 4,
            ExecutionFailure::ProtocolRun => 5,
            ExecutionFailure::OutputTooLarge => 6,
            ExecutionFailure::TrustedDealer => 7,
            ExecutionFailure::Abort(AbortReason::InvalidMAC) => 50,
            ExecutionFailure::Abort(AbortReason::ExpectedSentShare) => 51,
            ExecutionFailure::Abort(AbortReason::ExpectedFieldElement) => 52,
            ExecutionFailure::Abort(AbortReason::ExpectedAbort) => 53,
            ExecutionFailure::Abort(AbortReason::MalformedData) => 54,
            ExecutionFailure::Abort(AbortReason::ComputationFailed) => 55,
            ExecutionFailure::Abort(AbortReason::InternalError) => 56,
            ExecutionFailure::Abort(AbortReason::PreprocessingStreamError) => 57,
            ExecutionFailure::Abort(AbortReason::DivisionByZero) => 58,
            ExecutionFailure::Abort(AbortReason::NoSignature) => 59,
            ExecutionFailure::Abort(AbortReason::InvalidSignature) => 60,
            ExecutionFailure::Abort(AbortReason::PrimitiveError) => 61,
            ExecutionFailure::Abort(AbortReason::InvalidBatchLength) => 62,
            ExecutionFailure::Abort(AbortReason::QuadraticNonResidue) => 63,
            ExecutionFailure::Abort(AbortReason::BitConversionError) => 64,
            ExecutionFailure::Abort(AbortReason::ChannelClosed) => 65,
            ExecutionFailure::Abort(AbortReason::TimeoutElapsed) => 66,
            ExecutionFailure::KeyRecoveryFailure(KeyRecoveryFailureReason::KeysDigestMismatch) => {
                100
            }
            ExecutionFailure::KeyRecoveryFailure(
                KeyRecoveryFailureReason::X25519PubkeyMismatch,
            ) => 101,
            ExecutionFailure::KeyRecoveryFailure(
                KeyRecoveryFailureReason::Ed25519VerifyingKeyMismatch,
            ) => 102,
            ExecutionFailure::KeyRecoveryFailure(
                KeyRecoveryFailureReason::ElGamalPubkeyMismatch,
            ) => 103,
            ExecutionFailure::KeyRecoveryFailure(KeyRecoveryFailureReason::TooManyCorruptPeers) => {
                104
            }
            ExecutionFailure::KeyRecoveryFailure(KeyRecoveryFailureReason::NoPubkeysSet) => 105,
            ExecutionFailure::KeyRecoveryFailure(KeyRecoveryFailureReason::Serialization) => 106,
        }
    }

    pub fn from_discriminator(discriminator: u8) -> Option<Self> {
        match discriminator {
            0 => Some(ExecutionFailure::Serialization),
            1 => Some(ExecutionFailure::Router),
            2 => Some(ExecutionFailure::Circuit),
            3 => Some(ExecutionFailure::Inputs),
            4 => Some(ExecutionFailure::ProtocolInit),
            5 => Some(ExecutionFailure::ProtocolRun),
            6 => Some(ExecutionFailure::OutputTooLarge),
            7 => Some(ExecutionFailure::TrustedDealer),
            50 => Some(ExecutionFailure::Abort(AbortReason::InvalidMAC)),
            51 => Some(ExecutionFailure::Abort(AbortReason::ExpectedSentShare)),
            52 => Some(ExecutionFailure::Abort(AbortReason::ExpectedFieldElement)),
            53 => Some(ExecutionFailure::Abort(AbortReason::ExpectedAbort)),
            54 => Some(ExecutionFailure::Abort(AbortReason::MalformedData)),
            55 => Some(ExecutionFailure::Abort(AbortReason::ComputationFailed)),
            56 => Some(ExecutionFailure::Abort(AbortReason::InternalError)),
            57 => Some(ExecutionFailure::Abort(
                AbortReason::PreprocessingStreamError,
            )),
            58 => Some(ExecutionFailure::Abort(AbortReason::DivisionByZero)),
            59 => Some(ExecutionFailure::Abort(AbortReason::NoSignature)),
            60 => Some(ExecutionFailure::Abort(AbortReason::InvalidSignature)),
            61 => Some(ExecutionFailure::Abort(AbortReason::PrimitiveError)),
            62 => Some(ExecutionFailure::Abort(AbortReason::InvalidBatchLength)),
            63 => Some(ExecutionFailure::Abort(AbortReason::QuadraticNonResidue)),
            64 => Some(ExecutionFailure::Abort(AbortReason::BitConversionError)),
            65 => Some(ExecutionFailure::Abort(AbortReason::ChannelClosed)),
            66 => Some(ExecutionFailure::Abort(AbortReason::TimeoutElapsed)),
            100 => Some(ExecutionFailure::KeyRecoveryFailure(
                KeyRecoveryFailureReason::KeysDigestMismatch,
            )),
            101 => Some(ExecutionFailure::KeyRecoveryFailure(
                KeyRecoveryFailureReason::X25519PubkeyMismatch,
            )),
            102 => Some(ExecutionFailure::KeyRecoveryFailure(
                KeyRecoveryFailureReason::Ed25519VerifyingKeyMismatch,
            )),
            103 => Some(ExecutionFailure::KeyRecoveryFailure(
                KeyRecoveryFailureReason::ElGamalPubkeyMismatch,
            )),
            104 => Some(ExecutionFailure::KeyRecoveryFailure(
                KeyRecoveryFailureReason::TooManyCorruptPeers,
            )),
            105 => Some(ExecutionFailure::KeyRecoveryFailure(
                KeyRecoveryFailureReason::NoPubkeysSet,
            )),
            106 => Some(ExecutionFailure::KeyRecoveryFailure(
                KeyRecoveryFailureReason::Serialization,
            )),

            _ => None,
        }
    }
}

impl MxeRecoveryAccount {
    pub fn n_peers_submitted_shares(&self) -> usize {
        self.shares
            .iter()
            .filter(|&s| *s != [[0u8; 32]; RESCUE_KEY_COUNT])
            .count()
    }
}

impl CallbackInstruction {
    pub fn to_instruction(&self, ix_data: &[u8]) -> Instruction {
        let mut data = Vec::with_capacity(self.discriminator.len() + ix_data.len());
        data.extend_from_slice(&self.discriminator);
        data.extend_from_slice(ix_data);
        Instruction {
            program_id: self.program_id,
            accounts: self.accounts.iter().map(|acc| acc.into()).collect(),
            data,
        }
    }
}

impl From<&CallbackAccount> for AccountMeta {
    fn from(acc: &CallbackAccount) -> Self {
        AccountMeta {
            pubkey: acc.pubkey,
            is_signer: false,
            is_writable: acc.is_writable,
        }
    }
}

// Although Epoch is the same in `arcium` and `arcium_staking`
// (which imports it from `arcium`) when it gets exported via the idl this information gets lost and
// rust thinks they're two different types. We add these two traits so that we can convert between
// them and don't have to constantly think about which Epoch is needed where.
#[cfg(feature = "staking")]
impl From<arcium_staking::types::Epoch> for arcium::types::Epoch {
    fn from(val: arcium_staking::types::Epoch) -> Self {
        arcium::types::Epoch(val.0)
    }
}

#[cfg(feature = "staking")]
impl From<arcium::types::Epoch> for arcium_staking::types::Epoch {
    fn from(val: arcium::types::Epoch) -> Self {
        arcium_staking::types::Epoch(val.0)
    }
}

#[repr(u8)]
pub enum BLSDomainSeparator {
    Success = 0,
    Failure = 1,
    PoP = 2,
}