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