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

feat: modify API to allow certain use cases; add ed25519/secp256k1 precompiles #78

Closed
wants to merge 7 commits into from
Closed
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
1,186 changes: 687 additions & 499 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ solana-compute-budget-program = "~1.18"
solana-loader-v4-program = "~1.18"
bincode = "1.3"
indexmap = "2.2.6"
solana-address-lookup-table-program = "1.18.8"
solana-address-lookup-table-program = "~1.18"
log = "0.4.21"
solana-vote-program = "~1.18"
solana-stake-program = "~1.18"
Expand Down
4 changes: 2 additions & 2 deletions benches/banks_client_comparison.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use solana_program::{
rent::Rent,
};
use solana_sdk::{
account::Account, feature_set::FeatureSet, message::Message, signature::Keypair,
account::Account, bpf_loader, feature_set::FeatureSet, message::Message, signature::Keypair,
signer::Signer, transaction::Transaction,
};

Expand Down Expand Up @@ -99,7 +99,7 @@ fn criterion_benchmark(c: &mut Criterion) {
let payer_pk = payer_kp.pubkey();
let program_id = Pubkey::new_unique();

svm.add_program(program_id, &read_counter_program());
svm.add_program(&bpf_loader::id(), program_id, &read_counter_program());
svm.airdrop(&payer_pk, 1000000000).unwrap();
let feature_set = svm.get_feature_set();
let counter_address = Pubkey::new_unique();
Expand Down
4 changes: 2 additions & 2 deletions benches/simple_bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use solana_program::{
pubkey::Pubkey,
};
use solana_sdk::{
account::Account, message::Message, signature::Keypair, signer::Signer,
account::Account, bpf_loader, message::Message, signature::Keypair, signer::Signer,
transaction::Transaction,
};

Expand Down Expand Up @@ -45,7 +45,7 @@ fn criterion_benchmark(c: &mut Criterion) {
let payer_pk = payer_kp.pubkey();
let program_id = Pubkey::new_unique();

svm.add_program(program_id, &read_counter_program());
svm.add_program(&bpf_loader::id(), program_id, &read_counter_program());
svm.airdrop(&payer_pk, 1000000000).unwrap();
let counter_address = Pubkey::new_unique();
c.bench_function("simple_bench", |b| {
Expand Down
43 changes: 16 additions & 27 deletions src/accounts_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use solana_program::{
bpf_loader, bpf_loader_deprecated,
bpf_loader_upgradeable::{self, UpgradeableLoaderState},
clock::Clock,
instruction::InstructionError,
loader_v4::{self, LoaderV4State},
message::{
v0::{LoadedAddresses, MessageAddressTableLookup},
Expand Down Expand Up @@ -55,7 +54,7 @@ where
}

#[derive(Default)]
pub(crate) struct AccountsDb {
pub struct AccountsDb {
inner: HashMap<Pubkey, AccountSharedData>,
pub(crate) programs_cache: LoadedProgramsForTxBatch,
pub(crate) sysvar_cache: SysvarCache,
Expand All @@ -78,7 +77,7 @@ impl AccountsDb {
account: AccountSharedData,
) -> Result<(), LiteSVMError> {
if account.executable() && pubkey != Pubkey::default() {
let loaded_program = self.load_program(&account)?;
let loaded_program = self.load_program(&account);
self.programs_cache
.replenish(pubkey, Arc::new(loaded_program));
} else {
Expand Down Expand Up @@ -185,10 +184,7 @@ impl AccountsDb {
Ok(())
}

fn load_program(
&self,
program_account: &AccountSharedData,
) -> Result<LoadedProgram, InstructionError> {
fn load_program(&self, program_account: &AccountSharedData) -> LoadedProgram {
let metrics = &mut LoadProgramMetrics::default();

let owner = program_account.owner();
Expand All @@ -206,21 +202,19 @@ impl AccountsDb {
program_account.data().len(),
&mut LoadProgramMetrics::default(),
)
.map_err(|_| InstructionError::InvalidAccountData)
.unwrap()
} else if bpf_loader_upgradeable::check_id(owner) {
let Ok(UpgradeableLoaderState::Program {
programdata_address,
}) = program_account.state()
else {
error!(
panic!(
"Program account data does not deserialize to UpgradeableLoaderState::Program"
);
return Err(InstructionError::InvalidAccountData);
};
let programdata_account = self.get_account(&programdata_address).ok_or_else(|| {
error!("Program data account {programdata_address} not found");
InstructionError::MissingAccount
})?;
let programdata_account = self.get_account(&programdata_address).unwrap_or_else(|| {
panic!("Program data account {programdata_address} not found");
});
let program_data = programdata_account.data();
if let Some(programdata) =
program_data.get(UpgradeableLoaderState::size_of_programdata_metadata()..)
Expand All @@ -236,13 +230,11 @@ impl AccountsDb {
.data()
.len()
.saturating_add(program_data.len()),
metrics).map_err(|_| {
error!("Error encountered when calling LoadedProgram::new() for bpf_loader_upgradeable.");
InstructionError::InvalidAccountData
})
metrics).unwrap_or_else(|_|
panic!("Error encountered when calling LoadedProgram::new() for bpf_loader_upgradeable.")
)
} else {
error!("Index out of bounds using bpf_loader_upgradeable.");
Err(InstructionError::InvalidAccountData)
panic!("Index out of bounds using bpf_loader_upgradeable.");
}
} else if loader_v4::check_id(owner) {
if let Some(elf_bytes) = program_account
Expand All @@ -259,17 +251,14 @@ impl AccountsDb {
program_account.data().len(),
metrics,
)
.map_err(|_| {
error!("Error encountered when calling LoadedProgram::new() for loader_v4.");
InstructionError::InvalidAccountData
.unwrap_or_else(|_| {
panic!("Error encountered when calling LoadedProgram::new() for loader_v4.");
})
} else {
error!("Index out of bounds using loader_v4.");
Err(InstructionError::InvalidAccountData)
panic!("Index out of bounds using loader_v4.");
}
} else {
error!("Owner does not match any expected loader.");
Err(InstructionError::IncorrectProgramId)
panic!("Owner does not match any expected loader.");
}
}

Expand Down
37 changes: 27 additions & 10 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use solana_sdk::{
account::{Account, AccountSharedData, ReadableAccount, WritableAccount},
bpf_loader,
clock::Clock,
ed25519_program,
epoch_rewards::EpochRewards,
epoch_schedule::EpochSchedule,
feature_set::{include_loaded_accounts_data_size_in_fee_calculation, FeatureSet},
Expand All @@ -35,6 +36,7 @@ use solana_sdk::{
nonce_account,
pubkey::Pubkey,
rent::Rent,
secp256k1_program,
signature::{Keypair, Signature},
signer::Signer,
slot_hashes::SlotHashes,
Expand Down Expand Up @@ -62,12 +64,12 @@ use crate::{
};

pub mod error;
pub mod spl;
pub mod types;

mod accounts_db;
mod builtin;
mod history;
mod spl;
mod utils;

// The test code doesn't actually get run because it's not
Expand All @@ -78,7 +80,7 @@ mod utils;
pub struct ReadmeDoctests;

pub struct LiteSVM {
accounts: AccountsDb,
pub accounts: AccountsDb,
airdrop_kp: Keypair,
feature_set: Arc<FeatureSet>,
latest_blockhash: Hash,
Expand Down Expand Up @@ -301,14 +303,14 @@ impl LiteSVM {
path: impl AsRef<Path>,
) -> Result<(), std::io::Error> {
let bytes = std::fs::read(path)?;
self.add_program(program_id, &bytes);
self.add_program(&bpf_loader::id(), program_id, &bytes);
Ok(())
}

pub fn add_program(&mut self, program_id: Pubkey, program_bytes: &[u8]) {
pub fn add_program(&mut self, loader_id: &Pubkey, program_id: Pubkey, program_bytes: &[u8]) {
let program_len = program_bytes.len();
let lamports = self.minimum_balance_for_rent_exemption(program_len);
let mut account = AccountSharedData::new(lamports, program_len, &bpf_loader::id());
let mut account = AccountSharedData::new(lamports, program_len, loader_id);
account.set_executable(true);
account.set_data_from_slice(program_bytes);
let current_slot = self
Expand All @@ -333,7 +335,11 @@ impl LiteSVM {
)
.unwrap_or_default();
loaded_program.effective_slot = current_slot;
self.accounts.add_account(program_id, account).unwrap();
self.accounts
.add_account(program_id, account)
.unwrap_or_else(|err| {
panic!("Failed to add program; program_id={program_id}; err={err}")
});
self.accounts
.programs_cache
.replenish(program_id, Arc::new(loaded_program));
Expand Down Expand Up @@ -442,6 +448,13 @@ impl LiteSVM {
let mut account_found = true;
let account = if solana_sdk::sysvar::instructions::check_id(key) {
construct_instructions_account(message)
} else if ed25519_program::check_id(key) || secp256k1_program::check_id(key) {
let mut account = AccountSharedData::default();
account.set_owner(native_loader::id());
account.set_lamports(1);
account.set_executable(true);

account
} else {
let instruction_account = u8::try_from(i)
.map(|i| instruction_accounts.contains(&&i))
Expand Down Expand Up @@ -787,9 +800,13 @@ impl LiteSVM {
}
}

pub fn simulate_transaction(&self, tx: impl Into<VersionedTransaction>) -> TransactionResult {
pub fn simulate_transaction(
&self,
tx: impl Into<VersionedTransaction>,
) -> Result<(TransactionMetadata, Vec<(Pubkey, AccountSharedData)>), FailedTransactionMetadata>
{
let ExecutionResult {
post_accounts: _,
post_accounts,
tx_result,
signature,
compute_units_consumed,
Expand All @@ -812,9 +829,9 @@ impl LiteSVM {
};

if let Err(tx_err) = tx_result {
TransactionResult::Err(FailedTransactionMetadata { err: tx_err, meta })
Err(FailedTransactionMetadata { err: tx_err, meta })
} else {
TransactionResult::Ok(meta)
Ok((meta, post_accounts))
}
}

Expand Down
18 changes: 14 additions & 4 deletions src/spl/mod.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,36 @@
use solana_sdk::pubkey;
use solana_sdk::{bpf_loader, pubkey};

use crate::LiteSVM;

pub const TOKEN_ELF: &[u8] = include_bytes!("programs/spl_token-3.5.0.so");
pub const TOKEN_2022_ELF: &[u8] = include_bytes!("programs/spl_token_2022-1.0.0.so");
pub const ASSOCIATED_TOKEN_ACCOUNT_ELF: &[u8] =
include_bytes!("programs/spl_associated_token_account-1.1.1.so");

pub fn load_spl_programs(svm: &mut LiteSVM) {
svm.add_program(
&bpf_loader::id(),
pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"),
include_bytes!("programs/spl_token-3.5.0.so"),
TOKEN_ELF,
);
svm.add_program(
&bpf_loader::id(),
pubkey!("TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"),
include_bytes!("programs/spl_token_2022-1.0.0.so"),
TOKEN_2022_ELF,
);
svm.add_program(
&bpf_loader::id(),
pubkey!("Memo1UhkJRfHyvLMcVucJwxXeuD728EqVDDwQDxFMNo"),
include_bytes!("programs/spl_memo-1.0.0.so"),
);
svm.add_program(
&bpf_loader::id(),
pubkey!("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"),
include_bytes!("programs/spl_memo-3.0.0.so"),
);
svm.add_program(
&bpf_loader::id(),
pubkey!("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"),
include_bytes!("programs/spl_associated_token_account-1.1.1.so"),
ASSOCIATED_TOKEN_ACCOUNT_ELF,
);
}
5 changes: 3 additions & 2 deletions tests/counter_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use solana_program::{
pubkey::Pubkey,
rent::Rent,
};
use solana_sdk::bpf_loader;
use solana_sdk::transaction::{TransactionError, VersionedTransaction};
use solana_sdk::{
account::Account,
Expand All @@ -34,7 +35,7 @@ pub fn integration_test() {
let payer_kp = Keypair::new();
let payer_pk = payer_kp.pubkey();
let program_id = pubkey!("GtdambwDgHWrDJdVPBkEHGhCwokqgAoch162teUjJse2");
svm.add_program(program_id, &read_counter_program());
svm.add_program(&bpf_loader::id(), program_id, &read_counter_program());
svm.airdrop(&payer_pk, 1000000000).unwrap();
let blockhash = svm.latest_blockhash();
let counter_address = pubkey!("J39wvrFY2AkoAUCke5347RMNk3ditxZfVidoZ7U6Fguf");
Expand Down Expand Up @@ -249,7 +250,7 @@ fn test_address_lookup_table() {
let payer_kp = Keypair::new();
let payer_pk = payer_kp.pubkey();
let program_id = pubkey!("GtdambwDgHWrDJdVPBkEHGhCwokqgAoch162teUjJse2");
svm.add_program(program_id, &read_counter_program());
svm.add_program(&bpf_loader::id(), program_id, &read_counter_program());
svm.airdrop(&payer_pk, 1000000000).unwrap();
let blockhash = svm.latest_blockhash();
let counter_address = pubkey!("J39wvrFY2AkoAUCke5347RMNk3ditxZfVidoZ7U6Fguf");
Expand Down
3 changes: 2 additions & 1 deletion tests/loaders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use solana_program::{
message::Message,
};
use solana_sdk::{
bpf_loader,
bpf_loader_upgradeable::{self, UpgradeableLoaderState},
message::VersionedMessage,
pubkey::Pubkey,
Expand Down Expand Up @@ -136,7 +137,7 @@ fn hello_world_with_store() {

let program_kp = Keypair::new();
let program_id = program_kp.pubkey();
svm.add_program(program_id, program_bytes);
svm.add_program(&bpf_loader::id(), program_id, program_bytes);

let instruction = Instruction::new_with_bytes(
program_id,
Expand Down
1 change: 1 addition & 0 deletions tests/stake_program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ fn get_minimum_delegation(svm: &mut LiteSVM, payer: &Keypair) -> u64 {
let mut data = svm
.simulate_transaction(transaction)
.unwrap()
.0
.return_data
.data;
data.resize(8, 0);
Expand Down