Skip to content

Commit 43ec754

Browse files
committed
harness: generic-vm: agave vm v1
1 parent f3f5f61 commit 43ec754

File tree

4 files changed

+150
-55
lines changed

4 files changed

+150
-55
lines changed

harness/src/lib.rs

Lines changed: 30 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -455,16 +455,14 @@ pub use mollusk_svm_result as result;
455455
use mollusk_svm_result::Compare;
456456
#[cfg(feature = "precompiles")]
457457
use solana_precompile_error::PrecompileError;
458-
#[cfg(feature = "invocation-inspect-callback")]
459-
use solana_transaction_context::InstructionAccount;
460458
use {
461459
crate::{
462460
account_store::AccountStore,
463461
compile_accounts::CompiledAccounts,
464462
epoch_stake::EpochStake,
465463
program::ProgramCache,
466464
sysvar::Sysvars,
467-
vm::{agave::AgaveVM, SolanaVM},
465+
vm::{agave::AgaveVM, SolanaVM, SolanaVMContext, SolanaVMInstruction, SolanaVMTrace},
468466
},
469467
agave_feature_set::FeatureSet,
470468
mollusk_svm_error::error::{MolluskError, MolluskPanic},
@@ -473,14 +471,19 @@ use {
473471
solana_compute_budget::compute_budget::ComputeBudget,
474472
solana_hash::Hash,
475473
solana_instruction::{AccountMeta, Instruction},
476-
solana_program_runtime::invoke_context::{EnvironmentConfig, InvokeContext},
474+
solana_program_runtime::invoke_context::EnvironmentConfig,
477475
solana_pubkey::Pubkey,
478476
solana_svm_callback::InvokeContextCallback,
479477
solana_svm_log_collector::LogCollector,
480478
solana_svm_timings::ExecuteTimings,
481479
solana_transaction_context::TransactionContext,
482480
std::{cell::RefCell, collections::HashSet, iter::once, marker::PhantomData, rc::Rc},
483481
};
482+
#[cfg(feature = "invocation-inspect-callback")]
483+
use {
484+
solana_program_runtime::invoke_context::InvokeContext,
485+
solana_transaction_context::InstructionAccount,
486+
};
484487

485488
pub(crate) const DEFAULT_LOADER_KEY: Pubkey = solana_sdk_ids::bpf_loader_upgradeable::id();
486489

@@ -797,54 +800,39 @@ impl<VM: SolanaVM> Mollusk<VM> {
797800
};
798801
let runtime_features = self.feature_set.runtime_features();
799802
let sysvar_cache = self.sysvars.setup_sysvar_cache(accounts);
800-
let mut invoke_context = InvokeContext::new(
801-
&mut transaction_context,
802-
&mut program_cache,
803-
EnvironmentConfig::new(
803+
804+
let context = SolanaVMContext {
805+
transaction_context: &mut transaction_context,
806+
program_cache: &mut program_cache,
807+
compute_budget: self.compute_budget,
808+
environment_config: EnvironmentConfig::new(
804809
Hash::default(),
805810
/* blockhash_lamports_per_signature */ 5000, // The default value
806811
&callback,
807812
&runtime_features,
808813
&sysvar_cache,
809814
),
810-
self.logger.clone(),
811-
self.compute_budget.to_budget(),
812-
self.compute_budget.to_cost(),
813-
);
814-
815-
// Configure the next instruction frame for this invocation.
816-
invoke_context
817-
.transaction_context
818-
.configure_next_instruction_for_tests(
819-
program_id_index,
820-
instruction_accounts.clone(),
821-
&instruction.data,
822-
)
823-
.expect("failed to configure next instruction");
824-
825-
#[cfg(feature = "invocation-inspect-callback")]
826-
self.invocation_inspect_callback.before_invocation(
827-
&instruction.program_id,
828-
&instruction.data,
829-
&instruction_accounts,
830-
&invoke_context,
831-
);
815+
};
832816

833-
let result = if invoke_context.is_precompile(&instruction.program_id) {
834-
invoke_context.process_precompile(
835-
&instruction.program_id,
836-
&instruction.data,
837-
std::iter::once(instruction.data.as_ref()),
838-
)
839-
} else {
840-
invoke_context.process_instruction(&mut compute_units_consumed, &mut timings)
817+
let instruction = SolanaVMInstruction {
818+
program_id_index,
819+
accounts: instruction_accounts,
820+
data: &instruction.data,
841821
};
842822

843-
#[cfg(feature = "invocation-inspect-callback")]
844-
self.invocation_inspect_callback
845-
.after_invocation(&invoke_context);
823+
let trace = SolanaVMTrace {
824+
compute_units_consumed: &mut compute_units_consumed,
825+
execute_timings: &mut timings,
826+
log_collector: self.logger.clone(),
827+
};
846828

847-
result
829+
VM::process_instruction(
830+
context,
831+
instruction,
832+
trace,
833+
#[cfg(feature = "invocation-inspect-callback")]
834+
self.invocation_inspect_callback.as_ref(),
835+
)
848836
};
849837

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

harness/src/vm.rs

Lines changed: 0 additions & 13 deletions
This file was deleted.

harness/src/vm/agave.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
//! The SBPF virtual machine used in Anza's Agave validator.
2+
3+
#[cfg(feature = "invocation-inspect-callback")]
4+
use crate::InvocationInspectCallback;
5+
use {
6+
super::{SolanaVM, SolanaVMContext, SolanaVMInstruction, SolanaVMTrace},
7+
solana_instruction_error::InstructionError,
8+
solana_program_runtime::invoke_context::InvokeContext,
9+
};
10+
11+
/// The SBPF virtual machine used in Anza's Agave validator.
12+
pub struct AgaveVM {}
13+
14+
impl SolanaVM for AgaveVM {
15+
fn process_instruction(
16+
context: SolanaVMContext,
17+
instruction: SolanaVMInstruction,
18+
trace: SolanaVMTrace,
19+
#[cfg(feature = "invocation-inspect-callback")]
20+
invocation_inspect_callback: &dyn InvocationInspectCallback,
21+
) -> Result<(), InstructionError> {
22+
let mut invoke_context = InvokeContext::new(
23+
context.transaction_context,
24+
context.program_cache,
25+
context.environment_config,
26+
trace.log_collector,
27+
context.compute_budget.to_budget(),
28+
context.compute_budget.to_cost(),
29+
);
30+
31+
// Configure the next instruction frame for this invocation.
32+
invoke_context
33+
.transaction_context
34+
.configure_next_instruction_for_tests(
35+
instruction.program_id_index,
36+
instruction.accounts.clone(),
37+
instruction.data,
38+
)
39+
.expect("failed to configure next instruction");
40+
41+
let program_id = invoke_context
42+
.transaction_context
43+
.get_key_of_account_at_index(instruction.program_id_index)
44+
.cloned()?;
45+
46+
#[cfg(feature = "invocation-inspect-callback")]
47+
invocation_inspect_callback.before_invocation(
48+
&program_id,
49+
instruction.data,
50+
&instruction.accounts,
51+
&invoke_context,
52+
);
53+
54+
let result = if invoke_context.is_precompile(&program_id) {
55+
invoke_context.process_precompile(
56+
&program_id,
57+
instruction.data,
58+
std::iter::once(instruction.data),
59+
)
60+
} else {
61+
invoke_context.process_instruction(trace.compute_units_consumed, trace.execute_timings)
62+
};
63+
64+
#[cfg(feature = "invocation-inspect-callback")]
65+
invocation_inspect_callback.after_invocation(&invoke_context);
66+
67+
result
68+
}
69+
}

harness/src/vm/mod.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//! Virtual Machine API for using Mollusk with custom VMs.
2+
3+
pub mod agave;
4+
5+
#[cfg(feature = "invocation-inspect-callback")]
6+
use crate::InvocationInspectCallback;
7+
use {
8+
solana_compute_budget::compute_budget::ComputeBudget,
9+
solana_instruction_error::InstructionError,
10+
solana_program_runtime::{
11+
invoke_context::EnvironmentConfig, loaded_programs::ProgramCacheForTxBatch,
12+
},
13+
solana_svm_log_collector::LogCollector,
14+
solana_svm_timings::ExecuteTimings,
15+
solana_transaction_context::{InstructionAccount, TransactionContext},
16+
std::{cell::RefCell, rc::Rc},
17+
};
18+
19+
/// Context required to process a Solana instruction in a VM.
20+
pub struct SolanaVMContext<'a> {
21+
pub transaction_context: &'a mut TransactionContext,
22+
pub program_cache: &'a mut ProgramCacheForTxBatch,
23+
pub compute_budget: ComputeBudget,
24+
pub environment_config: EnvironmentConfig<'a>,
25+
}
26+
27+
/// A Solana instruction to be processed by a VM.
28+
pub struct SolanaVMInstruction<'a> {
29+
pub program_id_index: u16,
30+
pub accounts: Vec<InstructionAccount>,
31+
pub data: &'a [u8],
32+
}
33+
34+
/// Trace information about a Solana VM instruction invocation.
35+
pub struct SolanaVMTrace<'a> {
36+
pub compute_units_consumed: &'a mut u64,
37+
pub execute_timings: &'a mut ExecuteTimings,
38+
pub log_collector: Option<Rc<RefCell<LogCollector>>>,
39+
}
40+
41+
/// A virtual machine compatible with the Solana calling convention.
42+
pub trait SolanaVM {
43+
/// Process a Solana instruction.
44+
fn process_instruction(
45+
context: SolanaVMContext,
46+
instruction: SolanaVMInstruction,
47+
trace: SolanaVMTrace,
48+
#[cfg(feature = "invocation-inspect-callback")]
49+
invocation_inspect_callback: &dyn InvocationInspectCallback,
50+
) -> Result<(), InstructionError>;
51+
}

0 commit comments

Comments
 (0)