waffles_solana_sdk/
precompiles.rs1#![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#[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
34pub type Verify = fn(&[u8], &[&[u8]], &FeatureSet) -> std::result::Result<(), PrecompileError>;
36
37pub struct Precompile {
39 pub program_id: Pubkey,
41 pub feature: Option<Pubkey>,
43 pub verify_fn: Verify,
45}
46impl Precompile {
47 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 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 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 static ref PRECOMPILES: Vec<Precompile> = vec![
79 Precompile::new(
80 crate::secp256k1_program::id(),
81 None, crate::secp256k1_instruction::verify,
83 ),
84 Precompile::new(
85 crate::ed25519_program::id(),
86 None, crate::ed25519_instruction::verify,
88 ),
89 ];
90}
91
92pub 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
106pub 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}