From 5ca52d785cf64c624e684be138cf363872d6d7aa Mon Sep 17 00:00:00 2001 From: jackcmay Date: Tue, 23 Oct 2018 14:44:41 -0700 Subject: [PATCH] Preload BPF loader (#1573) Preload BPF loader --- src/bank.rs | 18 +++++++++++++++ src/bpf_loader.rs | 19 ++++++++++++++++ src/fullnode.rs | 2 +- src/lib.rs | 1 + src/native_loader.rs | 7 +++--- tests/programs.rs | 53 ++++++++++++++++++++++++++++++++++++++------ 6 files changed, 89 insertions(+), 11 deletions(-) create mode 100644 src/bpf_loader.rs diff --git a/src/bank.rs b/src/bank.rs index 94fd051742..6d4ddf76a3 100644 --- a/src/bank.rs +++ b/src/bank.rs @@ -5,6 +5,7 @@ use bincode::deserialize; use bincode::serialize; +use bpf_loader; use budget_program::BudgetState; use budget_transaction::BudgetTransaction; use counter::Counter; @@ -187,6 +188,13 @@ impl Default for Bank { } impl Bank { + /// Create an Bank with built-in programs. + pub fn new_with_builtin_programs() -> Self { + let bank = Self::default(); + bank.add_builtin_programs(); + bank + } + /// Create an Bank using a deposit. pub fn new_from_deposit(deposit: &Payment) -> Self { let bank = Self::default(); @@ -195,6 +203,7 @@ impl Bank { let account = accounts.entry(deposit.to).or_insert_with(Account::default); Self::apply_payment(deposit, account); } + bank.add_builtin_programs(); bank } @@ -209,6 +218,15 @@ impl Bank { bank } + fn add_builtin_programs(&self) { + // Preload Bpf Loader account + let mut accounts = self.accounts.write().unwrap(); + let mut account = accounts + .entry(bpf_loader::id()) + .or_insert_with(Account::default); + bpf_loader::populate_account(&mut account); + } + /// Commit funds to the given account fn apply_payment(payment: &Payment, account: &mut Account) { trace!("apply payments {}", payment.tokens); diff --git a/src/bpf_loader.rs b/src/bpf_loader.rs new file mode 100644 index 0000000000..e8d983b3f6 --- /dev/null +++ b/src/bpf_loader.rs @@ -0,0 +1,19 @@ +//! BPF loader +use native_loader; +use solana_program_interface::account::Account; +use solana_program_interface::pubkey::Pubkey; + +pub const BPF_LOADER_PROGRAM_ID: [u8; 32] = [6u8; 32]; +pub const BPF_LOADER_NAME: &str = "bpf_loader"; + +pub fn id() -> Pubkey { + Pubkey::new(&BPF_LOADER_PROGRAM_ID) +} + +pub fn populate_account(account: &mut Account) { + account.tokens = 0; + account.program_id = id(); + account.userdata = BPF_LOADER_NAME.as_bytes().to_vec(); + account.executable = true; + account.loader_program_id = native_loader::id(); +} diff --git a/src/fullnode.rs b/src/fullnode.rs index 553c26c94c..3b15b3a4ba 100644 --- a/src/fullnode.rs +++ b/src/fullnode.rs @@ -585,7 +585,7 @@ impl Fullnode { ledger_path: &str, leader_scheduler: &mut LeaderScheduler, ) -> (Bank, u64, u64, Vec) { - let bank = Bank::default(); + let bank = Bank::new_with_builtin_programs(); let entries = read_ledger(ledger_path, true).expect("opening ledger"); let entries = entries .map(|e| e.unwrap_or_else(|err| panic!("failed to parse entry. error: {}", err))); diff --git a/src/lib.rs b/src/lib.rs index bc8b0146db..1a9c72a38a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,6 +12,7 @@ pub mod counter; pub mod bank; pub mod banking_stage; pub mod blob_fetch_stage; +pub mod bpf_loader; pub mod broadcast_stage; pub mod budget; pub mod budget_instruction; diff --git a/src/native_loader.rs b/src/native_loader.rs index fdbbf0e9a1..27508f6823 100644 --- a/src/native_loader.rs +++ b/src/native_loader.rs @@ -1,3 +1,4 @@ +//! Native loader use bincode::deserialize; use libc; #[cfg(unix)] @@ -39,18 +40,18 @@ fn create_path(name: &str) -> PathBuf { ) } -pub const NATIVE_PROGRAM_ID: [u8; 32] = [2u8; 32]; +const NATIVE_LOADER_PROGRAM_ID: [u8; 32] = [2u8; 32]; // All native programs export a symbol named process() const ENTRYPOINT: &str = "process"; type Entrypoint = unsafe extern "C" fn(keyed_accounts: &mut [KeyedAccount], data: &[u8]) -> bool; pub fn check_id(program_id: &Pubkey) -> bool { - program_id.as_ref() == NATIVE_PROGRAM_ID + program_id.as_ref() == NATIVE_LOADER_PROGRAM_ID } pub fn id() -> Pubkey { - Pubkey::new(&NATIVE_PROGRAM_ID) + Pubkey::new(&NATIVE_LOADER_PROGRAM_ID) } pub fn process_transaction(keyed_accounts: &mut [KeyedAccount], tx_data: &[u8]) -> bool { diff --git a/tests/programs.rs b/tests/programs.rs index eea54ec5fa..905ce82a17 100644 --- a/tests/programs.rs +++ b/tests/programs.rs @@ -5,6 +5,8 @@ extern crate solana_program_interface; use bincode::serialize; use solana::bank::Bank; +#[cfg(feature = "bpf_c")] +use solana::bpf_loader; use solana::loader_transaction::LoaderTransaction; use solana::logger; use solana::mint::Mint; @@ -60,7 +62,7 @@ impl Loader { let bank = Bank::new(&mint); let loader = Keypair::new(); - // allocate, populate, finalize, and spawn BPF loader + // allocate, populate, finalize, and spawn loader let tx = Transaction::system_create( &mint.keypair(), @@ -104,6 +106,15 @@ impl Loader { Loader { mint, bank, loader } } + + #[cfg(feature = "bpf_c")] + pub fn new_bpf() -> Self { + let mint = Mint::new(50); + let bank = Bank::new(&mint); + let loader = bpf_loader::id(); + + Loader { mint, bank, loader } + } } struct Program { @@ -114,7 +125,7 @@ impl Program { pub fn new(loader: &Loader, userdata: Vec) -> Self { let program = Keypair::new(); - // allocate, populate, and finalize and spawn program + // allocate, populate, finalize and spawn program let tx = Transaction::system_create( &loader.mint.keypair(), @@ -131,7 +142,7 @@ impl Program { loader.bank.process_transactions(&vec![tx.clone()]), ); - let chunk_size = 256; // Size of chunk just needs to fix into tx + let chunk_size = 256; // Size of chunk just needs to fit into tx let mut offset = 0; for chunk in userdata.chunks(chunk_size) { let tx = Transaction::write( @@ -178,7 +189,6 @@ fn test_program_native_noop() { let program = Program::new(&loader, userdata); // Call user program - let tx = Transaction::new( &loader.mint.keypair(), &[], @@ -260,6 +270,38 @@ fn test_program_lua_move_funds() { assert_eq!(loader.bank.get_balance(&to), 11); } +#[cfg(feature = "bpf_c")] +#[test] +fn test_program_builtin_bpf_noop() { + logger::setup(); + + let loader = Loader::new_bpf(); + let program = Program::new( + &loader, + elf::File::open_path(&create_bpf_path("noop_c")) + .unwrap() + .get_section(PLATFORM_SECTION_C) + .unwrap() + .data + .clone(), + ); + + // Call user program + let tx = Transaction::new( + &loader.mint.keypair(), + &[], + program.program.pubkey(), + vec![1u8], + loader.mint.last_id(), + 0, + ); + check_tx_results( + &loader.bank, + &tx, + loader.bank.process_transactions(&vec![tx.clone()]), + ); +} + #[cfg(feature = "bpf_c")] #[test] fn test_program_bpf_noop_c() { @@ -277,7 +319,6 @@ fn test_program_bpf_noop_c() { ); // Call user program - let tx = Transaction::new( &loader.mint.keypair(), &[], @@ -304,7 +345,6 @@ impl TicTacToe { let game = Keypair::new(); // Create game account - let tx = Transaction::system_create( &loader.mint.keypair(), game.pubkey(), @@ -400,7 +440,6 @@ impl Dashboard { let dashboard = Keypair::new(); // Create game account - let tx = Transaction::system_create( &loader.mint.keypair(), dashboard.pubkey(),