1#![cfg_attr(docsrs, feature(doc_auto_cfg))]
2use {
3 agave_feature_set::{enable_secp256r1_precompile, FeatureSet},
4 lazy_static::lazy_static,
5 solana_message::compiled_instruction::CompiledInstruction,
6 solana_precompile_error::PrecompileError,
7 solana_pubkey::Pubkey,
8};
9
10pub mod ed25519;
11pub mod secp256k1;
12pub mod secp256r1;
13
14pub type Verify = fn(&[u8], &[&[u8]], &FeatureSet) -> std::result::Result<(), PrecompileError>;
16
17pub struct Precompile {
19 pub program_id: Pubkey,
21 pub feature: Option<Pubkey>,
23 pub verify_fn: Verify,
25}
26impl Precompile {
27 pub fn new(program_id: Pubkey, feature: Option<Pubkey>, verify_fn: Verify) -> Self {
29 Precompile {
30 program_id,
31 feature,
32 verify_fn,
33 }
34 }
35 pub fn check_id<F>(&self, program_id: &Pubkey, is_enabled: F) -> bool
37 where
38 F: Fn(&Pubkey) -> bool,
39 {
40 self.feature
41 .is_none_or(|ref feature_id| is_enabled(feature_id))
42 && self.program_id == *program_id
43 }
44 pub fn verify(
46 &self,
47 data: &[u8],
48 instruction_datas: &[&[u8]],
49 feature_set: &FeatureSet,
50 ) -> std::result::Result<(), PrecompileError> {
51 (self.verify_fn)(data, instruction_datas, feature_set)
52 }
53}
54
55lazy_static! {
56 static ref PRECOMPILES: Vec<Precompile> = vec![
58 Precompile::new(
59 solana_sdk_ids::secp256k1_program::id(),
60 None, secp256k1::verify,
62 ),
63 Precompile::new(
64 solana_sdk_ids::ed25519_program::id(),
65 None, ed25519::verify,
67 ),
68 Precompile::new(
69 solana_sdk_ids::secp256r1_program::id(),
70 Some(enable_secp256r1_precompile::id()),
71 secp256r1::verify,
72 )
73 ];
74}
75
76pub fn is_precompile<F>(program_id: &Pubkey, is_enabled: F) -> bool
78where
79 F: Fn(&Pubkey) -> bool,
80{
81 PRECOMPILES
82 .iter()
83 .any(|precompile| precompile.check_id(program_id, |feature_id| is_enabled(feature_id)))
84}
85
86pub fn get_precompile<F>(program_id: &Pubkey, is_enabled: F) -> Option<&Precompile>
88where
89 F: Fn(&Pubkey) -> bool,
90{
91 PRECOMPILES
92 .iter()
93 .find(|precompile| precompile.check_id(program_id, |feature_id| is_enabled(feature_id)))
94}
95
96pub fn get_precompiles<'a>() -> &'a [Precompile] {
97 &PRECOMPILES
98}
99
100pub fn verify_if_precompile(
102 program_id: &Pubkey,
103 precompile_instruction: &CompiledInstruction,
104 all_instructions: &[CompiledInstruction],
105 feature_set: &FeatureSet,
106) -> Result<(), PrecompileError> {
107 for precompile in PRECOMPILES.iter() {
108 if precompile.check_id(program_id, |feature_id| feature_set.is_active(feature_id)) {
109 let instruction_datas: Vec<_> = all_instructions
110 .iter()
111 .map(|instruction| instruction.data.as_ref())
112 .collect();
113 return precompile.verify(
114 &precompile_instruction.data,
115 &instruction_datas,
116 feature_set,
117 );
118 }
119 }
120 Ok(())
121}