Skip to content
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
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,8 @@ solana-zk-token-sdk = { git = "https://github.com/firedancer-io/agave", rev = "6
# This feature is used to compile a target with a builtin replaced by a BPF program.
# Requires the `CORE_BPF_PROGRAM_ID` and `CORE_BPF_TARGET` environment variables.
core-bpf = []
# Same as the `core-bpf` feature, but also includes special-casing required for
# conformance testing a BPF program against a builtin.
core-bpf-conformance = []
# This feature is used to stub out certain parts of the agave runtime for fuzzing
stub-agave = ["solana-program-runtime/stub-proc-instr"]
6 changes: 3 additions & 3 deletions macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,17 +106,17 @@ pub fn declare_core_bpf_default_compute_units(_: TokenStream) -> TokenStream {

if program_id == solana_sdk::address_lookup_table::program::id() {
tokens = quote! {
#[cfg(feature = "core-bpf")]
#[cfg(feature = "core-bpf-conformance")]
const CORE_BPF_DEFAULT_COMPUTE_UNITS: u64 = solana_address_lookup_table_program::processor::DEFAULT_COMPUTE_UNITS;
}
} else if program_id == solana_sdk::config::program::id() {
tokens = quote! {
#[cfg(feature = "core-bpf")]
#[cfg(feature = "core-bpf-conformance")]
const CORE_BPF_DEFAULT_COMPUTE_UNITS: u64 = solana_config_program::config_processor::DEFAULT_COMPUTE_UNITS;
}
} else if program_id == solana_sdk::stake::program::id() {
tokens = quote! {
#[cfg(feature = "core-bpf")]
#[cfg(feature = "core-bpf-conformance")]
const CORE_BPF_DEFAULT_COMPUTE_UNITS: u64 = solana_stake_program::stake_instruction::DEFAULT_COMPUTE_UNITS;
}
}
Expand Down
2 changes: 1 addition & 1 deletion scripts/build_core_bpf.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,6 @@ set_core_bpf_vars "$1"

CORE_BPF_PROGRAM_ID=$CORE_BPF_PROGRAM_ID CORE_BPF_TARGET=$CORE_BPF_TARGET FORCE_RECOMPILE=true $CARGO build \
--target x86_64-unknown-linux-gnu \
--features core-bpf \
--features core-bpf-conformance \
--lib \
--release
31 changes: 14 additions & 17 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,8 @@ use std::ffi::c_int;
use std::sync::Arc;
use thiserror::Error;

#[cfg(feature = "core-bpf")]
use {
solana_sdk::account::WritableAccount, solana_sdk::slot_hashes::SlotHashes,
solana_sdk::sysvar::Sysvar,
};
#[cfg(any(feature = "core-bpf", feature = "core-bpf-conformance"))]
use solana_sdk::{account::WritableAccount, slot_hashes::SlotHashes, sysvar::Sysvar};

// macro to rewrite &[IDENTIFIER, ...] to &[feature_u64(IDENTIFIER::id()), ...]
#[macro_export]
Expand Down Expand Up @@ -579,7 +576,7 @@ fn load_builtins(cache: &mut ProgramCacheForTxBatch) -> HashSet<Pubkey> {
}

fn execute_instr(mut input: InstrContext) -> Option<InstrEffects> {
#[cfg(feature = "core-bpf")]
#[cfg(feature = "core-bpf-conformance")]
// If the fixture declares `cu_avail` to be less than the builtin version's
// `DEFAULT_COMPUTE_UNITS`, the program should fail on compute meter
// exhaustion.
Expand All @@ -595,7 +592,7 @@ fn execute_instr(mut input: InstrContext) -> Option<InstrEffects> {
}
budget
};
#[cfg(not(feature = "core-bpf"))]
#[cfg(not(feature = "core-bpf-conformance"))]
let compute_budget = ComputeBudget {
compute_unit_limit: input.cu_avail,
..ComputeBudget::default()
Expand All @@ -607,7 +604,7 @@ fn execute_instr(mut input: InstrContext) -> Option<InstrEffects> {
sysvar_cache.fill_missing_entries(|pubkey, callbackback| {
if let Some(account) = input.accounts.iter().find(|(key, _)| key == pubkey) {
if account.1.lamports > 0 {
#[cfg(feature = "core-bpf")]
#[cfg(any(feature = "core-bpf", feature = "core-bpf-conformance"))]
// BPF versions of programs, such as Address Lookup Table, rely
// on the new `SolGetSysvar` syscall. However, APIs for
// querying slot hashes built on top of `SolGetSysvar` are
Expand Down Expand Up @@ -679,7 +676,7 @@ fn execute_instr(mut input: InstrContext) -> Option<InstrEffects> {
.accounts
.iter()
.map(|(pubkey, account)| {
#[cfg(feature = "core-bpf")]
#[cfg(any(feature = "core-bpf", feature = "core-bpf-conformance"))]
// Fixtures provide the program account as a builtin (owned by
// native loader), but the program-runtime will expect the account
// owner to match the cache entry.
Expand Down Expand Up @@ -756,7 +753,7 @@ fn execute_instr(mut input: InstrContext) -> Option<InstrEffects> {
let mut newly_loaded_programs = HashSet::<Pubkey>::new();

for acc in &input.accounts {
#[cfg(feature = "core-bpf")]
#[cfg(any(feature = "core-bpf", feature = "core-bpf-conformance"))]
// The Core BPF program's ELF has already been added to the cache.
// Its transaction account was stubbed out, so it can't be loaded via
// callback (inputs), since the account doesn't contain the ELF.
Expand Down Expand Up @@ -888,21 +885,21 @@ fn execute_instr(mut input: InstrContext) -> Option<InstrEffects> {
&mut timings,
);

#[cfg(feature = "core-bpf")]
#[cfg(feature = "core-bpf-conformance")]
// To keep alignment with a builtin run, deduct only the CUs the builtin
// version would have consumed, so the fixture realizes the same CU
// deduction across both BPF and builtin in its effects.
let cu_avail = input
.cu_avail
.saturating_sub(CORE_BPF_DEFAULT_COMPUTE_UNITS);
#[cfg(not(feature = "core-bpf"))]
#[cfg(not(feature = "core-bpf-conformance"))]
let cu_avail = input.cu_avail - compute_units_consumed;

let return_data = transaction_context.get_return_data().1.to_vec();

Some(InstrEffects {
custom_err: if let Err(InstructionError::Custom(code)) = result {
#[cfg(feature = "core-bpf")]
#[cfg(feature = "core-bpf-conformance")]
// See comment below under `result` for special-casing of custom
// errors for Core BPF programs.
if program_id == &solana_sdk::address_lookup_table::program::id() && code == 10 {
Expand All @@ -912,14 +909,14 @@ fn execute_instr(mut input: InstrContext) -> Option<InstrEffects> {
} else {
Some(code)
}
#[cfg(not(feature = "core-bpf"))]
#[cfg(not(feature = "core-bpf-conformance"))]
Some(code)
} else {
None
},
#[allow(clippy::map_identity)]
result: result.err().map(|err| {
#[cfg(feature = "core-bpf")]
#[cfg(feature = "core-bpf-conformance")]
// Some errors don't directly map between builtins and their BPF
// versions.
//
Expand All @@ -944,7 +941,7 @@ fn execute_instr(mut input: InstrContext) -> Option<InstrEffects> {
{
return InstructionError::ComputationalBudgetExceeded;
}
#[cfg(feature = "core-bpf")]
#[cfg(feature = "core-bpf-conformance")]
// Another such error case arises when a program performs a write
// to an account, but the data it writes is the exact same data
// that's currently stored in the account state.
Expand Down Expand Up @@ -987,7 +984,7 @@ fn execute_instr(mut input: InstrContext) -> Option<InstrEffects> {
.into_iter()
.enumerate()
.map(|(index, data)| {
#[cfg(feature = "core-bpf")]
#[cfg(any(feature = "core-bpf", feature = "core-bpf-conformance"))]
// Fixtures provide the program account as a builtin account
// (owned by native loader).
//
Expand Down