Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract precompiles crate #3622

Merged
merged 3 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 {
kevinheavey marked this conversation as resolved.
Show resolved Hide resolved
lazy_static::lazy_static, solana_feature_set::FeatureSet,
solana_precompile_error::PrecompileError, solana_program::instruction::CompiledInstruction,
joncinque marked this conversation as resolved.
Show resolved Hide resolved
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
Loading