Skip to content

Commit

Permalink
Extract precompiles crate (solana-labs#3622)
Browse files Browse the repository at this point in the history
* extract solana-precompiles crate

* sort deps

* add missing doc_auto_cfg

Co-authored-by: Jon C <[email protected]>

---------

Co-authored-by: Jon C <[email protected]>
  • Loading branch information
kevinheavey and joncinque authored Nov 21, 2024
1 parent f9f54bc commit 1b8a4ad
Show file tree
Hide file tree
Showing 8 changed files with 204 additions and 114 deletions.
16 changes: 16 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ members = [
"sdk/package-metadata-macro",
"sdk/packet",
"sdk/precompile-error",
"sdk/precompiles",
"sdk/presigner",
"sdk/program",
"sdk/program-entrypoint",
Expand Down Expand Up @@ -498,6 +499,7 @@ solana-perf = { path = "perf", version = "=2.2.0" }
solana-poh = { path = "poh", version = "=2.2.0" }
solana-poseidon = { path = "poseidon", version = "=2.2.0" }
solana-precompile-error = { path = "sdk/precompile-error", version = "=2.2.0" }
solana-precompiles = { path = "sdk/precompiles", version = "=2.2.0" }
solana-presigner = { path = "sdk/presigner", version = "=2.2.0" }
solana-program = { path = "sdk/program", version = "=2.2.0", default-features = false }
solana-program-error = { path = "sdk/program-error", version = "=2.2.0" }
Expand Down
16 changes: 16 additions & 0 deletions programs/sbf/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ full = [
"dep:solana-compute-budget-interface",
"dep:solana-keypair",
"dep:solana-precompile-error",
"dep:solana-precompiles",
"dep:solana-presigner",
"dep:solana-quic-definitions",
"dep:solana-secp256k1-program",
Expand Down Expand Up @@ -75,7 +76,7 @@ frozen-abi = [
"solana-transaction-error/frozen-abi"
]
# Enables the "vendored" feature of openssl inside of secp256r1-program
openssl-vendored = ["solana-secp256r1-program/openssl-vendored"]
openssl-vendored = ["solana-precompiles/openssl-vendored"]

[dependencies]
bincode = { workspace = true }
Expand Down Expand Up @@ -135,6 +136,7 @@ solana-keypair = { workspace = true, optional = true, features = ["seed-derivabl
solana-native-token = { workspace = true }
solana-packet = { workspace = true, features = ["bincode", "serde"] }
solana-precompile-error = { workspace = true, optional = true }
solana-precompiles = { workspace = true, optional = true }
solana-presigner = { workspace = true, optional = true }
solana-program = { workspace = true }
solana-program-memory = { workspace = true }
Expand Down
33 changes: 33 additions & 0 deletions sdk/precompiles/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
[package]
name = "solana-precompiles"
description = "Solana precompiled programs."
documentation = "https://docs.rs/solana-precompiles"
version = { workspace = true }
authors = { workspace = true }
repository = { workspace = true }
homepage = { workspace = true }
license = { workspace = true }
edition = { workspace = true }

[dependencies]
lazy_static = { workspace = true }
solana-ed25519-program = { workspace = true }
solana-feature-set = { workspace = true }
solana-precompile-error = { workspace = true }
solana-program = { workspace = true, default-features = false }
solana-pubkey = { workspace = true }
solana-sdk-ids = { workspace = true }
solana-secp256k1-program = { workspace = true, features = ["bincode"] }
solana-secp256r1-program = { workspace = true, default-features = false }

[features]
# Enables the "vendored" feature of openssl inside of secp256r1-program
openssl-vendored = ["solana-secp256r1-program/openssl-vendored"]

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
all-features = true
rustdoc-args = ["--cfg=docsrs"]

[lints]
workspace = true
115 changes: 115 additions & 0 deletions sdk/precompiles/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
use {
lazy_static::lazy_static, solana_feature_set::FeatureSet,
solana_precompile_error::PrecompileError, solana_program::instruction::CompiledInstruction,
solana_pubkey::Pubkey,
};

/// All precompiled programs must implement the `Verify` function
pub type Verify = fn(&[u8], &[&[u8]], &FeatureSet) -> std::result::Result<(), PrecompileError>;

/// Information on a precompiled program
pub 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<F>(&self, program_id: &Pubkey, is_enabled: F) -> bool
where
F: Fn(&Pubkey) -> bool,
{
self.feature
.map_or(true, |ref feature_id| is_enabled(feature_id))
&& self.program_id == *program_id
}
/// Verify this precompiled program
pub fn verify(
&self,
data: &[u8],
instruction_datas: &[&[u8]],
feature_set: &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(
solana_sdk_ids::secp256k1_program::id(),
None, // always enabled
solana_secp256k1_program::verify,
),
Precompile::new(
solana_sdk_ids::ed25519_program::id(),
None, // always enabled
solana_ed25519_program::verify,
),
Precompile::new(
solana_sdk_ids::secp256r1_program::id(),
Some(solana_feature_set::enable_secp256r1_precompile::id()),
solana_secp256r1_program::verify,
)
];
}

/// Check if a program is a precompiled program
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)))
}

/// Find an enabled precompiled program
pub fn get_precompile<F>(program_id: &Pubkey, is_enabled: F) -> Option<&Precompile>
where
F: Fn(&Pubkey) -> bool,
{
PRECOMPILES
.iter()
.find(|precompile| precompile.check_id(program_id, |feature_id| is_enabled(feature_id)))
}

pub fn get_precompiles<'a>() -> &'a [Precompile] {
&PRECOMPILES
}

/// 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: &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(())
}
116 changes: 3 additions & 113 deletions sdk/src/precompiles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,117 +4,7 @@

#[deprecated(since = "2.1.0", note = "Use `solana-precompile-error` crate instead.")]
pub use solana_precompile_error::PrecompileError;
use {
lazy_static::lazy_static, solana_feature_set::FeatureSet,
solana_program::instruction::CompiledInstruction, solana_pubkey::Pubkey,
solana_secp256r1_program as secp256r1_program,
#[deprecated(since = "2.2.0", note = "Use `solana-precompiles` crate instead.")]
pub use solana_precompiles::{
get_precompile, get_precompiles, is_precompile, verify_if_precompile, Precompile, Verify,
};

/// All precompiled programs must implement the `Verify` function
pub type Verify = fn(&[u8], &[&[u8]], &FeatureSet) -> std::result::Result<(), PrecompileError>;

/// Information on a precompiled program
pub 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<F>(&self, program_id: &Pubkey, is_enabled: F) -> bool
where
F: Fn(&Pubkey) -> bool,
{
self.feature
.map_or(true, |ref feature_id| is_enabled(feature_id))
&& self.program_id == *program_id
}
/// Verify this precompiled program
pub fn verify(
&self,
data: &[u8],
instruction_datas: &[&[u8]],
feature_set: &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, // always enabled
crate::secp256k1_instruction::verify,
),
Precompile::new(
crate::ed25519_program::id(),
None, // always enabled
crate::ed25519_instruction::verify,
),
Precompile::new(
secp256r1_program::id(),
Some(solana_feature_set::enable_secp256r1_precompile::id()),
secp256r1_program::verify,
)
];
}

/// Check if a program is a precompiled program
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)))
}

/// Find an enabled precompiled program
pub fn get_precompile<F>(program_id: &Pubkey, is_enabled: F) -> Option<&Precompile>
where
F: Fn(&Pubkey) -> bool,
{
PRECOMPILES
.iter()
.find(|precompile| precompile.check_id(program_id, |feature_id| is_enabled(feature_id)))
}

pub fn get_precompiles<'a>() -> &'a [Precompile] {
&PRECOMPILES
}

/// 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: &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(())
}
Loading

0 comments on commit 1b8a4ad

Please sign in to comment.