Skip to content
This repository was archived by the owner on Jan 22, 2025. It is now read-only.
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
39 changes: 21 additions & 18 deletions programs/bpf/tests/programs.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#[cfg(any(feature = "bpf_c", feature = "bpf_rust"))]
mod bpf {
use solana_runtime::bank::Bank;
use solana_runtime::bank_client::BankClient;
use solana_runtime::loader_utils::{create_invoke_instruction, load_program};
use solana_sdk::genesis_block::GenesisBlock;
use solana_sdk::native_loader;
Expand All @@ -27,7 +26,9 @@ mod bpf {
#[cfg(feature = "bpf_c")]
mod bpf_c {
use super::*;
use solana_runtime::sync_client::SyncClient;
use solana_sdk::bpf_loader;
use solana_sdk::signature::KeypairUtil;
use std::io::Read;

#[test]
Expand All @@ -38,14 +39,14 @@ mod bpf {
let mut elf = Vec::new();
file.read_to_end(&mut elf).unwrap();

let (genesis_block, mint_keypair) = GenesisBlock::new(50);
let (genesis_block, alice_keypair) = GenesisBlock::new(50);
let bank = Bank::new(&genesis_block);
let alice_client = BankClient::new(&bank, mint_keypair);

// Call user program
let program_id = load_program(&bank, &alice_client, &bpf_loader::id(), elf);
let instruction = create_invoke_instruction(alice_client.pubkey(), program_id, &1u8);
alice_client.process_instruction(instruction).unwrap();
let program_id = load_program(&bank, &alice_keypair, &bpf_loader::id(), elf);
let instruction = create_invoke_instruction(alice_keypair.pubkey(), program_id, &1u8);
bank.send_instruction(&[&alice_keypair], instruction)
.unwrap();
}

#[test]
Expand All @@ -67,22 +68,22 @@ mod bpf {
let mut elf = Vec::new();
file.read_to_end(&mut elf).unwrap();

let (genesis_block, mint_keypair) = GenesisBlock::new(50);
let (genesis_block, alice_keypair) = GenesisBlock::new(50);
let bank = Bank::new(&genesis_block);
let alice_client = BankClient::new(&bank, mint_keypair);

let loader_id = load_program(
&bank,
&alice_client,
&alice_keypair,
&native_loader::id(),
"solana_bpf_loader".as_bytes().to_vec(),
);

// Call user program
let program_id = load_program(&bank, &alice_client, &loader_id, elf);
let program_id = load_program(&bank, &alice_keypair, &loader_id, elf);
let instruction =
create_invoke_instruction(alice_client.pubkey(), program_id, &1u8);
alice_client.process_instruction(instruction).unwrap();
create_invoke_instruction(alice_keypair.pubkey(), program_id, &1u8);
bank.send_instruction(&[&alice_keypair], instruction)
.unwrap();
}
}
}
Expand All @@ -94,6 +95,8 @@ mod bpf {
#[cfg(feature = "bpf_rust")]
mod bpf_rust {
use super::*;
use solana_runtime::sync_client::SyncClient;
use solana_sdk::signature::KeypairUtil;
use std::io::Read;

#[test]
Expand All @@ -108,22 +111,22 @@ mod bpf {
let mut elf = Vec::new();
file.read_to_end(&mut elf).unwrap();

let (genesis_block, mint_keypair) = GenesisBlock::new(50);
let (genesis_block, alice_keypair) = GenesisBlock::new(50);
let bank = Bank::new(&genesis_block);
let alice_client = BankClient::new(&bank, mint_keypair);

let loader_id = load_program(
&bank,
&alice_client,
&alice_keypair,
&native_loader::id(),
"solana_bpf_loader".as_bytes().to_vec(),
);

// Call user program
let program_id = load_program(&bank, &alice_client, &loader_id, elf);
let program_id = load_program(&bank, &alice_keypair, &loader_id, elf);
let instruction =
create_invoke_instruction(alice_client.pubkey(), program_id, &1u8);
alice_client.process_instruction(instruction).unwrap();
create_invoke_instruction(alice_keypair.pubkey(), program_id, &1u8);
bank.send_instruction(&[&alice_keypair], instruction)
.unwrap();
}
}
}
Expand Down
12 changes: 6 additions & 6 deletions programs/failure_program/tests/failure.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
use solana_runtime::bank::Bank;
use solana_runtime::bank_client::BankClient;
use solana_runtime::loader_utils::{create_invoke_instruction, load_program};
use solana_runtime::sync_client::SyncClient;
use solana_sdk::genesis_block::GenesisBlock;
use solana_sdk::instruction::InstructionError;
use solana_sdk::native_loader;
use solana_sdk::signature::KeypairUtil;
use solana_sdk::transaction::TransactionError;

#[test]
fn test_program_native_failure() {
let (genesis_block, mint_keypair) = GenesisBlock::new(50);
let (genesis_block, alice_keypair) = GenesisBlock::new(50);
let bank = Bank::new(&genesis_block);
let alice_client = BankClient::new(&bank, mint_keypair);

let program = "failure".as_bytes().to_vec();
let program_id = load_program(&bank, &alice_client, &native_loader::id(), program);
let program_id = load_program(&bank, &alice_keypair, &native_loader::id(), program);

// Call user program
let instruction = create_invoke_instruction(alice_client.pubkey(), program_id, &1u8);
let instruction = create_invoke_instruction(alice_keypair.pubkey(), program_id, &1u8);
assert_eq!(
alice_client.process_instruction(instruction),
bank.send_instruction(&[&alice_keypair], instruction),
Err(TransactionError::InstructionError(
0,
InstructionError::GenericError
Expand Down
13 changes: 7 additions & 6 deletions programs/noop_program/tests/noop.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
use solana_runtime::bank::Bank;
use solana_runtime::bank_client::BankClient;
use solana_runtime::loader_utils::{create_invoke_instruction, load_program};
use solana_runtime::sync_client::SyncClient;
use solana_sdk::genesis_block::GenesisBlock;
use solana_sdk::native_loader;
use solana_sdk::signature::KeypairUtil;

#[test]
fn test_program_native_noop() {
solana_logger::setup();

let (genesis_block, mint_keypair) = GenesisBlock::new(50);
let (genesis_block, alice_keypair) = GenesisBlock::new(50);
let bank = Bank::new(&genesis_block);
let alice_client = BankClient::new(&bank, mint_keypair);

let program = "noop".as_bytes().to_vec();
let program_id = load_program(&bank, &alice_client, &native_loader::id(), program);
let program_id = load_program(&bank, &alice_keypair, &native_loader::id(), program);

// Call user program
let instruction = create_invoke_instruction(alice_client.pubkey(), program_id, &1u8);
alice_client.process_instruction(instruction).unwrap();
let instruction = create_invoke_instruction(alice_keypair.pubkey(), program_id, &1u8);
bank.send_instruction(&[&alice_keypair], instruction)
.unwrap();
}
1 change: 1 addition & 0 deletions runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub mod loader_utils;
mod native_loader;
pub mod runtime;
mod status_cache;
pub mod sync_client;
mod system_program;

#[macro_use]
Expand Down
16 changes: 8 additions & 8 deletions runtime/src/loader_utils.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::bank::Bank;
use crate::bank_client::BankClient;
use crate::sync_client::SyncClient;
use serde::Serialize;
use solana_sdk::instruction::{AccountMeta, Instruction};
use solana_sdk::loader_instruction::LoaderInstruction;
Expand All @@ -9,35 +9,35 @@ use solana_sdk::system_instruction::SystemInstruction;

pub fn load_program(
bank: &Bank,
from_client: &BankClient,
from_keypair: &Keypair,
loader_id: &Pubkey,
program: Vec<u8>,
) -> Pubkey {
let program_keypair = Keypair::new();
let program_pubkey = program_keypair.pubkey();

let instruction = SystemInstruction::new_program_account(
&from_client.pubkey(),
&from_keypair.pubkey(),
&program_pubkey,
1,
program.len() as u64,
loader_id,
);
from_client.process_instruction(instruction).unwrap();

let program_client = BankClient::new(bank, program_keypair);
bank.send_instruction(&[from_keypair], instruction).unwrap();

let chunk_size = 256; // Size of chunk just needs to fit into tx
let mut offset = 0;
for chunk in program.chunks(chunk_size) {
let instruction =
LoaderInstruction::new_write(&program_pubkey, loader_id, offset, chunk.to_vec());
program_client.process_instruction(instruction).unwrap();
bank.send_instruction(&[&program_keypair], instruction)
.unwrap();
offset += chunk_size as u32;
}

let instruction = LoaderInstruction::new_finalize(&program_pubkey, loader_id);
program_client.process_instruction(instruction).unwrap();
bank.send_instruction(&[&program_keypair], instruction)
.unwrap();

program_pubkey
}
Expand Down
106 changes: 106 additions & 0 deletions runtime/src/sync_client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
use crate::bank::Bank;
use solana_sdk::instruction::Instruction;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::system_instruction::SystemInstruction;
use solana_sdk::transaction::{Transaction, TransactionError};

// A client where each method waits for the server to complete before returning.
pub trait SyncClient {
fn send_transaction(
&self,
keypairs: &[&Keypair],
tx: Transaction,
) -> Result<(), TransactionError>;

/// Create and process a transaction from a list of instructions.
fn send_instructions(
&self,
keypairs: &[&Keypair],
instructions: Vec<Instruction>,
) -> Result<(), TransactionError>;

/// Create and process a transaction from a single instruction.
fn send_instruction(
&self,
keypairs: &[&Keypair],
instruction: Instruction,
) -> Result<(), TransactionError>;

/// Transfer lamports to pubkey
fn pay(
&self,
from_keypair: &Keypair,
to_pubkey: &Pubkey,
lamports: u64,
) -> Result<(), TransactionError>;
}

impl SyncClient for Bank {
fn send_transaction(
&self,
keypairs: &[&Keypair],
mut tx: Transaction,
) -> Result<(), TransactionError> {
tx.sign(keypairs, self.last_blockhash());
self.process_transaction(&tx)
}

/// Create and process a transaction from a list of instructions.
fn send_instructions(
&self,
keypairs: &[&Keypair],
instructions: Vec<Instruction>,
) -> Result<(), TransactionError> {
self.send_transaction(keypairs, Transaction::new(instructions))
}

/// Create and process a transaction from a single instruction.
fn send_instruction(
&self,
keypairs: &[&Keypair],
instruction: Instruction,
) -> Result<(), TransactionError> {
self.send_instructions(keypairs, vec![instruction])
}

/// Transfer lamports to pubkey
fn pay(
&self,
from_keypair: &Keypair,
to_pubkey: &Pubkey,
lamports: u64,
) -> Result<(), TransactionError> {
let move_instruction =
SystemInstruction::new_move(&from_keypair.pubkey(), to_pubkey, lamports);
self.send_instruction(&[from_keypair], move_instruction)
}
}

#[cfg(test)]
mod tests {
use super::*;
use solana_sdk::genesis_block::GenesisBlock;
use solana_sdk::instruction::AccountMeta;

#[test]
fn test_sync_client_new_with_keypairs() {
let (genesis_block, john_doe_keypair) = GenesisBlock::new(10_000);
let john_pubkey = john_doe_keypair.pubkey();
let jane_doe_keypair = Keypair::new();
let jane_pubkey = jane_doe_keypair.pubkey();
let doe_keypairs = vec![&john_doe_keypair, &jane_doe_keypair];
let bank = Bank::new(&genesis_block);

// Create 2-2 Multisig Move instruction.
let bob_pubkey = Keypair::new().pubkey();
let mut move_instruction = SystemInstruction::new_move(&john_pubkey, &bob_pubkey, 42);
move_instruction
.accounts
.push(AccountMeta::new(jane_pubkey, true));

bank.send_instruction(&doe_keypairs, move_instruction)
.unwrap();
assert_eq!(bank.get_balance(&bob_pubkey), 42);
}
}
16 changes: 7 additions & 9 deletions runtime/src/system_program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ pub fn entrypoint(
mod tests {
use super::*;
use crate::bank::Bank;
use crate::bank_client::BankClient;
use crate::sync_client::SyncClient;
use solana_sdk::account::Account;
use solana_sdk::genesis_block::GenesisBlock;
use solana_sdk::instruction::{AccountMeta, Instruction, InstructionError};
Expand Down Expand Up @@ -277,17 +277,15 @@ mod tests {

#[test]
fn test_system_unsigned_transaction() {
let (genesis_block, mint_keypair) = GenesisBlock::new(100);
let (genesis_block, alice_keypair) = GenesisBlock::new(100);
let bank = Bank::new(&genesis_block);
let alice_pubkey = alice_keypair.pubkey();

let alice_client = BankClient::new(&bank, mint_keypair);
let alice_pubkey = alice_client.pubkey();

let mallory_client = BankClient::new(&bank, Keypair::new());
let mallory_pubkey = mallory_client.pubkey();
let mallory_keypair = Keypair::new();
let mallory_pubkey = mallory_keypair.pubkey();

// Fund to account to bypass AccountNotFound error
alice_client.transfer(50, &mallory_pubkey).unwrap();
bank.pay(&alice_keypair, &mallory_pubkey, 50).unwrap();

// Erroneously sign transaction with recipient account key
// No signature case is tested by bank `test_zero_signatures()`
Expand All @@ -301,7 +299,7 @@ mod tests {
account_metas,
);
assert_eq!(
mallory_client.process_instruction(malicious_instruction),
bank.send_instruction(&[&mallory_keypair], malicious_instruction),
Err(TransactionError::InstructionError(
0,
InstructionError::MissingRequiredSignature
Expand Down