Skip to content

Commit 3c25ec1

Browse files
authored
harness: add support for precompiles (#69)
1 parent b729810 commit 3c25ec1

File tree

6 files changed

+116
-21
lines changed

6 files changed

+116
-21
lines changed

Cargo.lock

Lines changed: 8 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ version = "0.0.12"
2222
bincode = "1.3.3"
2323
bs58 = "0.5.1"
2424
criterion = "0.5.1"
25+
ed25519-dalek = "=1.0.1"
26+
libsecp256k1 = "0.6.0"
2527
mollusk-svm = { path = "harness", version = "0.0.12" }
2628
mollusk-svm-bencher = { path = "bencher", version = "0.0.12" }
2729
mollusk-svm-error = { path = "error", version = "0.0.12" }
@@ -35,6 +37,7 @@ num-format = "0.4.4"
3537
prost = "0.10"
3638
prost-build = "0.10"
3739
prost-types = "0.10"
40+
rand0-7 = { package = "rand", version = "0.7" }
3841
rayon = "1.10.0"
3942
serde = "1.0.203"
4043
serde_json = "1.0.117"

harness/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ solana-timings = { workspace = true }
3737

3838
[dev-dependencies]
3939
criterion = { workspace = true }
40+
ed25519-dalek = { workspace = true }
41+
libsecp256k1 = { workspace = true }
42+
rand0-7 = { workspace = true }
4043
rayon = { workspace = true }
4144
serial_test = { workspace = true }
4245

harness/src/lib.rs

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ use {
4747
solana_program_runtime::invoke_context::{EnvironmentConfig, InvokeContext},
4848
solana_sdk::{
4949
account::AccountSharedData, bpf_loader_upgradeable, feature_set::FeatureSet,
50-
fee::FeeStructure, hash::Hash, instruction::Instruction, pubkey::Pubkey,
51-
transaction_context::TransactionContext,
50+
fee::FeeStructure, hash::Hash, instruction::Instruction, precompiles::get_precompile,
51+
pubkey::Pubkey, transaction_context::TransactionContext,
5252
},
5353
solana_timings::ExecuteTimings,
5454
std::sync::Arc,
@@ -156,11 +156,15 @@ impl Mollusk {
156156
let mut compute_units_consumed = 0;
157157
let mut timings = ExecuteTimings::default();
158158

159-
let loader_key = self
160-
.program_cache
161-
.load_program(&instruction.program_id)
162-
.or_panic_with(MolluskError::ProgramNotCached(&instruction.program_id))
163-
.account_owner();
159+
let loader_key = if crate::program::precompile_keys::is_precompile(&instruction.program_id)
160+
{
161+
crate::program::loader_keys::NATIVE_LOADER
162+
} else {
163+
self.program_cache
164+
.load_program(&instruction.program_id)
165+
.or_panic_with(MolluskError::ProgramNotCached(&instruction.program_id))
166+
.account_owner()
167+
};
164168

165169
let CompiledAccounts {
166170
program_id_index,
@@ -178,7 +182,7 @@ impl Mollusk {
178182
let invoke_result = {
179183
let mut program_cache = self.program_cache.cache().write().unwrap();
180184
let sysvar_cache = self.sysvars.setup_sysvar_cache(accounts);
181-
InvokeContext::new(
185+
let mut invoke_context = InvokeContext::new(
182186
&mut transaction_context,
183187
&mut program_cache,
184188
EnvironmentConfig::new(
@@ -191,14 +195,26 @@ impl Mollusk {
191195
),
192196
None,
193197
self.compute_budget,
194-
)
195-
.process_instruction(
196-
&instruction.data,
197-
&instruction_accounts,
198-
&[program_id_index],
199-
&mut compute_units_consumed,
200-
&mut timings,
201-
)
198+
);
199+
if let Some(precompile) = get_precompile(&instruction.program_id, |feature_id| {
200+
invoke_context.get_feature_set().is_active(feature_id)
201+
}) {
202+
invoke_context.process_precompile(
203+
precompile,
204+
&instruction.data,
205+
&instruction_accounts,
206+
&[program_id_index],
207+
std::iter::once(instruction.data.as_ref()),
208+
)
209+
} else {
210+
invoke_context.process_instruction(
211+
&instruction.data,
212+
&instruction_accounts,
213+
&[program_id_index],
214+
&mut compute_units_consumed,
215+
&mut timings,
216+
)
217+
}
202218
};
203219

204220
let resulting_accounts: Vec<(Pubkey, AccountSharedData)> = accounts

harness/src/program.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,23 @@ pub mod loader_keys {
2727
};
2828
}
2929

30+
pub mod precompile_keys {
31+
use solana_sdk::pubkey::Pubkey;
32+
pub use solana_sdk::{
33+
ed25519_program::ID as ED25519_PROGRAM,
34+
secp256k1_program::ID as SECP256K1_PROGRAM,
35+
// secp256r1_program::ID as SECP256R1_PROGRAM, // Add me when patch version for 2.1 is
36+
// advanced!
37+
};
38+
39+
pub(crate) fn is_precompile(program_id: &Pubkey) -> bool {
40+
matches!(
41+
*program_id,
42+
ED25519_PROGRAM | SECP256K1_PROGRAM /* | SECP256R1_PROGRAM */ // Add me when patch version for 2.1 is advanced!
43+
)
44+
}
45+
}
46+
3047
pub struct ProgramCache {
3148
cache: RwLock<ProgramCacheForTxBatch>,
3249
}

harness/tests/precompile.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
use {
2+
mollusk_svm::{result::Check, Mollusk},
3+
rand0_7::thread_rng,
4+
solana_sdk::{
5+
account::{AccountSharedData, WritableAccount},
6+
ed25519_instruction::new_ed25519_instruction,
7+
ed25519_program, native_loader,
8+
pubkey::Pubkey,
9+
secp256k1_instruction::new_secp256k1_instruction,
10+
secp256k1_program,
11+
},
12+
};
13+
14+
fn precompile_account() -> AccountSharedData {
15+
let mut account = AccountSharedData::new(1, 0, &native_loader::id());
16+
account.set_executable(true);
17+
account
18+
}
19+
20+
#[test]
21+
fn test_secp256k1() {
22+
let mollusk = Mollusk::default();
23+
let secret_key = libsecp256k1::SecretKey::random(&mut thread_rng());
24+
25+
mollusk.process_and_validate_instruction(
26+
&new_secp256k1_instruction(&secret_key, b"hello"),
27+
&[
28+
(Pubkey::new_unique(), AccountSharedData::default()),
29+
(secp256k1_program::id(), precompile_account()),
30+
],
31+
&[Check::success()],
32+
);
33+
}
34+
35+
#[test]
36+
fn test_ed25519() {
37+
let mollusk = Mollusk::default();
38+
let secret_key = ed25519_dalek::Keypair::generate(&mut thread_rng());
39+
40+
mollusk.process_and_validate_instruction(
41+
&new_ed25519_instruction(&secret_key, b"hello"),
42+
&[
43+
(Pubkey::new_unique(), AccountSharedData::default()),
44+
(ed25519_program::id(), precompile_account()),
45+
],
46+
&[Check::success()],
47+
);
48+
}
49+
50+
#[test]
51+
fn test_secp256r1() {
52+
// Add me when patch version for 2.1 is advanced!
53+
}

0 commit comments

Comments
 (0)