-
Notifications
You must be signed in to change notification settings - Fork 4.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Cleanup and standardize precompiles (#19918)
- Loading branch information
Showing
7 changed files
with
251 additions
and
157 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
//! @brief Solana precompiled programs | ||
#![cfg(feature = "full")] | ||
|
||
use { | ||
crate::{ | ||
decode_error::DecodeError, | ||
feature_set::{ed25519_program_enabled, FeatureSet}, | ||
instruction::CompiledInstruction, | ||
pubkey::Pubkey, | ||
}, | ||
lazy_static::lazy_static, | ||
std::sync::Arc, | ||
thiserror::Error, | ||
}; | ||
|
||
/// Precompile errors | ||
#[derive(Error, Debug, Clone, PartialEq)] | ||
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" | ||
} | ||
} | ||
|
||
/// All precompiled programs must implement the `Verify` function | ||
pub type Verify = fn(&[u8], &[&[u8]], &Arc<FeatureSet>) -> std::result::Result<(), PrecompileError>; | ||
|
||
/// Information on a precompiled program | ||
struct Precompile { | ||
/// Program id | ||
pub program_id: Pubkey, | ||
/// Feature to enable on, `None` indicates always enabled | ||
pub feature: Option<Pubkey>, | ||
/// Verification function | ||
pub verify_fn: Verify, | ||
} | ||
impl Precompile { | ||
/// Creates a new `Precompile` | ||
pub fn new(program_id: Pubkey, feature: Option<Pubkey>, verify_fn: Verify) -> Self { | ||
Precompile { | ||
program_id, | ||
feature, | ||
verify_fn, | ||
} | ||
} | ||
/// Check if a program id is this precompiled program | ||
pub fn check_id(&self, program_id: &Pubkey, feature_set: &Arc<FeatureSet>) -> bool { | ||
self.feature.map_or(true, |f| feature_set.is_active(&f)) && self.program_id == *program_id | ||
} | ||
/// Verify this precompiled program | ||
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! { | ||
/// The list of all precompiled programs | ||
static ref PRECOMPILES: Vec<Precompile> = vec![ | ||
Precompile::new( | ||
crate::secp256k1_program::id(), | ||
None, | ||
crate::secp256k1_instruction::verify, | ||
), | ||
Precompile::new( | ||
crate::ed25519_program::id(), | ||
Some(ed25519_program_enabled::id()), | ||
crate::ed25519_instruction::verify, | ||
), | ||
]; | ||
} | ||
|
||
/// Check if a program is a precompiled program | ||
pub fn is_precompile(program_id: &Pubkey, feature_set: &Arc<FeatureSet>) -> bool { | ||
PRECOMPILES | ||
.iter() | ||
.any(|precompile| precompile.check_id(program_id, feature_set)) | ||
} | ||
|
||
/// Check that a program is precompiled and if so verify it | ||
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_set) { | ||
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(()) | ||
} |
Oops, something went wrong.