Skip to main content

agave_precompiles/
lib.rs

1#![cfg(feature = "agave-unstable-api")]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3use {
4    agave_feature_set::FeatureSet, solana_message::compiled_instruction::CompiledInstruction,
5    solana_precompile_error::PrecompileError, solana_pubkey::Pubkey, std::sync::LazyLock,
6};
7
8pub mod ed25519;
9pub mod secp256k1;
10pub mod secp256r1;
11
12/// All precompiled programs must implement the `Verify` function
13pub type Verify = fn(&[u8], &[&[u8]], &FeatureSet) -> std::result::Result<(), PrecompileError>;
14
15/// Information on a precompiled program
16pub struct Precompile {
17    /// Program id
18    pub program_id: Pubkey,
19    /// Feature to enable on, `None` indicates always enabled
20    pub feature: Option<Pubkey>,
21    /// Verification function
22    pub verify_fn: Verify,
23}
24impl Precompile {
25    /// Creates a new `Precompile`
26    pub fn new(program_id: Pubkey, feature: Option<Pubkey>, verify_fn: Verify) -> Self {
27        Precompile {
28            program_id,
29            feature,
30            verify_fn,
31        }
32    }
33    /// Check if a program id is this precompiled program
34    pub fn check_id<F>(&self, program_id: &Pubkey, is_enabled: F) -> bool
35    where
36        F: Fn(&Pubkey) -> bool,
37    {
38        self.feature
39            .is_none_or(|ref feature_id| is_enabled(feature_id))
40            && self.program_id == *program_id
41    }
42    /// Verify this precompiled program
43    pub fn verify(
44        &self,
45        data: &[u8],
46        instruction_datas: &[&[u8]],
47        feature_set: &FeatureSet,
48    ) -> std::result::Result<(), PrecompileError> {
49        (self.verify_fn)(data, instruction_datas, feature_set)
50    }
51}
52
53/// The list of all precompiled programs
54static PRECOMPILES: LazyLock<Vec<Precompile>> = LazyLock::new(|| {
55    vec![
56        Precompile::new(
57            solana_sdk_ids::secp256k1_program::id(),
58            None, // always enabled
59            secp256k1::verify,
60        ),
61        Precompile::new(
62            solana_sdk_ids::ed25519_program::id(),
63            None, // always enabled
64            ed25519::verify,
65        ),
66        Precompile::new(
67            solana_sdk_ids::secp256r1_program::id(),
68            None, // always enabled
69            secp256r1::verify,
70        ),
71    ]
72});
73
74/// Check if a program is a precompiled program
75pub fn is_precompile<F>(program_id: &Pubkey, is_enabled: F) -> bool
76where
77    F: Fn(&Pubkey) -> bool,
78{
79    PRECOMPILES
80        .iter()
81        .any(|precompile| precompile.check_id(program_id, |feature_id| is_enabled(feature_id)))
82}
83
84/// Find an enabled precompiled program
85pub fn get_precompile<F>(program_id: &Pubkey, is_enabled: F) -> Option<&Precompile>
86where
87    F: Fn(&Pubkey) -> bool,
88{
89    PRECOMPILES
90        .iter()
91        .find(|precompile| precompile.check_id(program_id, |feature_id| is_enabled(feature_id)))
92}
93
94pub fn get_precompiles<'a>() -> &'a [Precompile] {
95    &PRECOMPILES
96}
97
98/// Check that a program is precompiled and if so verify it
99pub fn verify_if_precompile(
100    program_id: &Pubkey,
101    precompile_instruction: &CompiledInstruction,
102    all_instructions: &[CompiledInstruction],
103    feature_set: &FeatureSet,
104) -> Result<(), PrecompileError> {
105    for precompile in PRECOMPILES.iter() {
106        if precompile.check_id(program_id, |feature_id| feature_set.is_active(feature_id)) {
107            let instruction_datas: Vec<_> = all_instructions
108                .iter()
109                .map(|instruction| instruction.data.as_ref())
110                .collect();
111            return precompile.verify(
112                &precompile_instruction.data,
113                &instruction_datas,
114                feature_set,
115            );
116        }
117    }
118    Ok(())
119}
120
121#[cfg(test)]
122pub(crate) fn test_verify_with_alignment(
123    verify: Verify,
124    instruction_data: &[u8],
125    instruction_datas: &[&[u8]],
126    feature_set: &FeatureSet,
127) -> Result<(), PrecompileError> {
128    // Copy instruction data.
129    let mut instruction_data_copy = vec![0u8; instruction_data.len().checked_add(1).unwrap()];
130    instruction_data_copy[0..instruction_data.len()].copy_from_slice(instruction_data);
131    // Verify the instruction data.
132    let result = verify(
133        &instruction_data_copy[..instruction_data.len()],
134        instruction_datas,
135        feature_set,
136    );
137
138    // Shift alignment by 1 to test `verify` does not rely on alignment.
139    instruction_data_copy[1..].copy_from_slice(instruction_data);
140    let result_shifted = verify(&instruction_data_copy[1..], instruction_datas, feature_set);
141    assert_eq!(result, result_shifted);
142    result
143}