waffles_solana_sdk/
precompiles.rs

1//! Solana precompiled programs.
2
3#![cfg(feature = "full")]
4
5use {
6    crate::{
7        decode_error::DecodeError, feature_set::FeatureSet, instruction::CompiledInstruction,
8        pubkey::Pubkey,
9    },
10    lazy_static::lazy_static,
11    thiserror::Error,
12};
13
14/// Precompile errors
15#[derive(Error, Debug, Clone, PartialEq, Eq)]
16pub enum PrecompileError {
17    #[error("public key is not valid")]
18    InvalidPublicKey,
19    #[error("id is not valid")]
20    InvalidRecoveryId,
21    #[error("signature is not valid")]
22    InvalidSignature,
23    #[error("offset not valid")]
24    InvalidDataOffsets,
25    #[error("instruction is incorrect size")]
26    InvalidInstructionDataSize,
27}
28impl<T> DecodeError<T> for PrecompileError {
29    fn type_of() -> &'static str {
30        "PrecompileError"
31    }
32}
33
34/// All precompiled programs must implement the `Verify` function
35pub type Verify = fn(&[u8], &[&[u8]], &FeatureSet) -> std::result::Result<(), PrecompileError>;
36
37/// Information on a precompiled program
38pub struct Precompile {
39    /// Program id
40    pub program_id: Pubkey,
41    /// Feature to enable on, `None` indicates always enabled
42    pub feature: Option<Pubkey>,
43    /// Verification function
44    pub verify_fn: Verify,
45}
46impl Precompile {
47    /// Creates a new `Precompile`
48    pub fn new(program_id: Pubkey, feature: Option<Pubkey>, verify_fn: Verify) -> Self {
49        Precompile {
50            program_id,
51            feature,
52            verify_fn,
53        }
54    }
55    /// Check if a program id is this precompiled program
56    pub fn check_id<F>(&self, program_id: &Pubkey, is_enabled: F) -> bool
57    where
58        F: Fn(&Pubkey) -> bool,
59    {
60        #![allow(clippy::redundant_closure)]
61        self.feature
62            .map_or(true, |ref feature_id| is_enabled(feature_id))
63            && self.program_id == *program_id
64    }
65    /// Verify this precompiled program
66    pub fn verify(
67        &self,
68        data: &[u8],
69        instruction_datas: &[&[u8]],
70        feature_set: &FeatureSet,
71    ) -> std::result::Result<(), PrecompileError> {
72        (self.verify_fn)(data, instruction_datas, feature_set)
73    }
74}
75
76lazy_static! {
77    /// The list of all precompiled programs
78    static ref PRECOMPILES: Vec<Precompile> = vec![
79        Precompile::new(
80            crate::secp256k1_program::id(),
81            None, // always enabled
82            crate::secp256k1_instruction::verify,
83        ),
84        Precompile::new(
85            crate::ed25519_program::id(),
86            None, // always enabled
87            crate::ed25519_instruction::verify,
88        ),
89    ];
90}
91
92/// Check if a program is a precompiled program
93pub fn is_precompile<F>(program_id: &Pubkey, is_enabled: F) -> bool
94where
95    F: Fn(&Pubkey) -> bool,
96{
97    PRECOMPILES
98        .iter()
99        .any(|precompile| precompile.check_id(program_id, |feature_id| is_enabled(feature_id)))
100}
101
102pub fn get_precompiles<'a>() -> &'a [Precompile] {
103    &PRECOMPILES
104}
105
106/// Check that a program is precompiled and if so verify it
107pub fn verify_if_precompile(
108    program_id: &Pubkey,
109    precompile_instruction: &CompiledInstruction,
110    all_instructions: &[CompiledInstruction],
111    feature_set: &FeatureSet,
112) -> Result<(), PrecompileError> {
113    for precompile in PRECOMPILES.iter() {
114        if precompile.check_id(program_id, |feature_id| feature_set.is_active(feature_id)) {
115            let instruction_datas: Vec<_> = all_instructions
116                .iter()
117                .map(|instruction| instruction.data.as_ref())
118                .collect();
119            return precompile.verify(
120                &precompile_instruction.data,
121                &instruction_datas,
122                feature_set,
123            );
124        }
125    }
126    Ok(())
127}