diff --git a/programs/librapay/Cargo.lock b/programs/librapay/Cargo.lock index 112a4b7339..77802f5b0d 100644 --- a/programs/librapay/Cargo.lock +++ b/programs/librapay/Cargo.lock @@ -1359,7 +1359,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "memmap" -version = "0.6.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2599,10 +2599,12 @@ dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "solana-logger 0.24.0", "solana-sdk 0.24.0", - "solana_rbpf 0.1.20", + "solana_rbpf 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2691,10 +2693,10 @@ name = "solana-move-loader-program" version = "0.24.0" dependencies = [ "bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "serde_bytes 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2712,6 +2714,7 @@ dependencies = [ "solana_libra_vm_cache_map 0.0.1-sol4 (registry+https://github.com/rust-lang/crates.io-index)", "solana_libra_vm_runtime 0.0.1-sol4 (registry+https://github.com/rust-lang/crates.io-index)", "solana_libra_vm_runtime_types 0.0.1-sol4 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2735,12 +2738,13 @@ dependencies = [ "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", "solana-bpf-loader-program 0.24.0", "solana-logger 0.24.0", "solana-measure 0.24.0", @@ -2752,6 +2756,7 @@ dependencies = [ "solana-vote-program 0.24.0", "sys-info 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2769,7 +2774,7 @@ dependencies = [ "hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2804,7 +2809,6 @@ dependencies = [ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "solana-config-program 0.24.0", @@ -3168,7 +3172,8 @@ dependencies = [ [[package]] name = "solana_rbpf" -version = "0.1.20" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "combine 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4212,7 +4217,7 @@ dependencies = [ "checksum mach_o_sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3e854583a83f20cf329bb9283366335387f7db59d640d1412167e05fedb98826" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" -"checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" +"checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" "checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f" "checksum memsec 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ccabb92f665f997bcb4f3ade019a8e07315148d8bcef3e65fbc5dbd65a22eb04" "checksum mime 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "dd1d63acd1b78403cc0c325605908475dd9b9a3acbf65ed8bcab97e27014afcf" @@ -4365,6 +4370,7 @@ dependencies = [ "checksum solana_libra_vm_cache_map 0.0.1-sol4 (registry+https://github.com/rust-lang/crates.io-index)" = "37fa2e1f00a87514cd2169149a5f81a89279703b2523979688d6ef84081a4690" "checksum solana_libra_vm_runtime 0.0.1-sol4 (registry+https://github.com/rust-lang/crates.io-index)" = "ff9f8a7b8212dc4ece5d93f2839896e633c34d7463856e4a555cbcb5c67e9c26" "checksum solana_libra_vm_runtime_types 0.0.1-sol4 (registry+https://github.com/rust-lang/crates.io-index)" = "254c23c8f30e7c82ae4dc6694e743400d674c66d371b700eec03378ba994f00b" +"checksum solana_rbpf 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "053e2a0f1f6c6298bf832493aeacdd6df98efb756a90feabd33caca9c708f2be" "checksum sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf77cb82ba8453b42b6ae1d692e4cdc92f9a47beaf89a847c8be83f4e328ad3" "checksum spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" diff --git a/runtime/benches/accounts.rs b/runtime/benches/accounts.rs index 5520366a17..b5256b8eb1 100644 --- a/runtime/benches/accounts.rs +++ b/runtime/benches/accounts.rs @@ -72,7 +72,5 @@ fn test_accounts_hash_bank_hash(bencher: &mut Bencher) { let mut pubkeys: Vec = vec![]; create_test_accounts(&accounts, &mut pubkeys, 60000, 0); let ancestors = vec![(0, 0)].into_iter().collect(); - bencher.iter(|| { - accounts.verify_bank_hash(0, &ancestors); - }); + bencher.iter(|| assert!(accounts.verify_bank_hash(0, &ancestors))); } diff --git a/runtime/benches/message_processor.rs b/runtime/benches/message_processor.rs index ba2e4470b0..4aef94e302 100644 --- a/runtime/benches/message_processor.rs +++ b/runtime/benches/message_processor.rs @@ -3,7 +3,7 @@ extern crate test; use log::*; -use solana_runtime::message_processor::*; +use solana_runtime::message_processor::PreAccount; use solana_sdk::{account::Account, pubkey::Pubkey}; use test::Bencher; @@ -13,26 +13,18 @@ fn bench_verify_account_changes_data(bencher: &mut Bencher) { let owner = Pubkey::new_rand(); let non_owner = Pubkey::new_rand(); - let pre = PreInstructionAccount::new( - &Account::new(0, BUFSIZE, &owner), - true, - need_account_data_checked(&owner, &owner, true), - ); + let pre = PreAccount::new(&Account::new(0, BUFSIZE, &owner), true, &owner); let post = Account::new(0, BUFSIZE, &owner); - assert_eq!(verify_account_changes(&owner, &pre, &post), Ok(())); + assert_eq!(pre.verify(&owner, &post), Ok(())); // this one should be faster bencher.iter(|| { - verify_account_changes(&owner, &pre, &post).unwrap(); + pre.verify(&owner, &post).unwrap(); }); let summary = bencher.bench(|_bencher| {}).unwrap(); info!("data no change by owner: {} ns/iter", summary.median); - let pre = PreInstructionAccount::new( - &Account::new(0, BUFSIZE, &owner), - true, - need_account_data_checked(&owner, &non_owner, true), - ); + let pre = PreAccount::new(&Account::new(0, BUFSIZE, &owner), true, &non_owner); match pre.data { Some(ref data) => bencher.iter(|| *data == post.data), None => panic!("No data!"), @@ -40,7 +32,7 @@ fn bench_verify_account_changes_data(bencher: &mut Bencher) { let summary = bencher.bench(|_bencher| {}).unwrap(); info!("data compare {} ns/iter", summary.median); bencher.iter(|| { - verify_account_changes(&non_owner, &pre, &post).unwrap(); + pre.verify(&non_owner, &post).unwrap(); }); let summary = bencher.bench(|_bencher| {}).unwrap(); info!("data no change by non owner: {} ns/iter", summary.median); @@ -53,14 +45,14 @@ static BUF1: [u8; BUFSIZE] = [1; BUFSIZE]; #[bench] fn bench_is_zeroed(bencher: &mut Bencher) { bencher.iter(|| { - is_zeroed(&BUF0); + PreAccount::is_zeroed(&BUF0); }); } #[bench] fn bench_is_zeroed_not(bencher: &mut Bencher) { bencher.iter(|| { - is_zeroed(&BUF1); + PreAccount::is_zeroed(&BUF1); }); } diff --git a/runtime/src/message_processor.rs b/runtime/src/message_processor.rs index 515906d006..8f3b0b66c2 100644 --- a/runtime/src/message_processor.rs +++ b/runtime/src/message_processor.rs @@ -1,5 +1,4 @@ -use crate::native_loader; -use crate::system_instruction_processor; +use crate::{native_loader, system_instruction_processor}; use serde::{Deserialize, Serialize}; use solana_sdk::{ account::{create_keyed_readonly_accounts, Account, KeyedAccount}, @@ -20,7 +19,8 @@ use libloading::os::windows::*; // The relevant state of an account before an Instruction executes, used // to verify account integrity after the Instruction completes -pub struct PreInstructionAccount { +#[derive(Clone, Debug, PartialEq)] +pub struct PreAccount { pub is_writable: bool, pub lamports: u64, pub data_len: usize, @@ -29,13 +29,13 @@ pub struct PreInstructionAccount { pub executable: bool, pub rent_epoch: Epoch, } -impl PreInstructionAccount { - pub fn new(account: &Account, is_writable: bool, copy_data: bool) -> Self { +impl PreAccount { + pub fn new(account: &Account, is_writable: bool, program_id: &Pubkey) -> Self { Self { is_writable, lamports: account.lamports, data_len: account.data.len(), - data: if copy_data { + data: if Self::should_verify_data(&account.owner, program_id, is_writable) { Some(account.data.clone()) } else { None @@ -45,86 +45,92 @@ impl PreInstructionAccount { rent_epoch: account.rent_epoch, } } -} -pub fn need_account_data_checked(program_id: &Pubkey, owner: &Pubkey, is_writable: bool) -> bool { - // For accounts not assigned to the program, the data may not change. - program_id != owner - // Read-only account data may not change. - || !is_writable -} -pub fn verify_account_changes( - program_id: &Pubkey, - pre: &PreInstructionAccount, - post: &Account, -) -> Result<(), InstructionError> { - // Verify the transaction - // Only the owner of the account may change owner and - // only if the account is writable and - // only if the data is zero-initialized or empty - if pre.owner != post.owner - && (!pre.is_writable // line coverage used to get branch coverage - || *program_id != pre.owner // line coverage used to get branch coverage - || !is_zeroed(&post.data)) - { - return Err(InstructionError::ModifiedProgramId); + fn should_verify_data(owner: &Pubkey, program_id: &Pubkey, is_writable: bool) -> bool { + // For accounts not assigned to the program, the data may not change. + program_id != owner + // Read-only account data may not change. + || !is_writable } - // An account not assigned to the program cannot have its balance decrease. - if *program_id != pre.owner // line coverage used to get branch coverage - && pre.lamports > post.lamports - { - return Err(InstructionError::ExternalAccountLamportSpend); - } + pub fn verify(&self, program_id: &Pubkey, post: &Account) -> Result<(), InstructionError> { + // Verify the transaction - // The balance of read-only accounts may not change. - if !pre.is_writable // line coverage used to get branch coverage - && pre.lamports != post.lamports - { - return Err(InstructionError::ReadonlyLamportChange); - } + // Only the owner of the account may change owner and + // only if the account is writable and + // only if the data is zero-initialized or empty + if self.owner != post.owner + && (!self.is_writable // line coverage used to get branch coverage + || *program_id != self.owner // line coverage used to get branch coverage + || !Self::is_zeroed(&post.data)) + { + return Err(InstructionError::ModifiedProgramId); + } - // Only the system program can change the size of the data - // and only if the system program owns the account - if pre.data_len != post.data.len() - && (!system_program::check_id(program_id) // line coverage used to get branch coverage - || !system_program::check_id(&pre.owner)) - { - return Err(InstructionError::AccountDataSizeChanged); - } + // An account not assigned to the program cannot have its balance decrease. + if *program_id != self.owner // line coverage used to get branch coverage + && self.lamports > post.lamports + { + return Err(InstructionError::ExternalAccountLamportSpend); + } - if need_account_data_checked(&pre.owner, program_id, pre.is_writable) { - match &pre.data { - Some(data) if *data == post.data => (), - _ => { - if !pre.is_writable { - return Err(InstructionError::ReadonlyDataModified); - } else { - return Err(InstructionError::ExternalAccountDataModified); + // The balance of read-only accounts may not change. + if !self.is_writable // line coverage used to get branch coverage + && self.lamports != post.lamports + { + return Err(InstructionError::ReadonlyLamportChange); + } + + // Only the system program can change the size of the data + // and only if the system program owns the account + if self.data_len != post.data.len() + && (!system_program::check_id(program_id) // line coverage used to get branch coverage + || !system_program::check_id(&self.owner)) + { + return Err(InstructionError::AccountDataSizeChanged); + } + + if Self::should_verify_data(&self.owner, program_id, self.is_writable) { + match &self.data { + Some(data) if *data == post.data => (), + _ => { + if !self.is_writable { + return Err(InstructionError::ReadonlyDataModified); + } else { + return Err(InstructionError::ExternalAccountDataModified); + } } } } + + // executable is one-way (false->true) and only the account owner may set it. + if self.executable != post.executable + && (!self.is_writable // line coverage used to get branch coverage + || self.executable // line coverage used to get branch coverage + || *program_id != self.owner) + { + return Err(InstructionError::ExecutableModified); + } + + // No one modifies r ent_epoch (yet). + if self.rent_epoch != post.rent_epoch { + return Err(InstructionError::RentEpochModified); + } + + Ok(()) } - // executable is one-way (false->true) and only the account owner may set it. - if pre.executable != post.executable - && (!pre.is_writable // line coverage used to get branch coverage - || pre.executable // line coverage used to get branch coverage - || *program_id != pre.owner) - { - return Err(InstructionError::ExecutableModified); - } + pub fn is_zeroed(buf: &[u8]) -> bool { + const ZEROS_LEN: usize = 1024; + static ZEROS: [u8; ZEROS_LEN] = [0; ZEROS_LEN]; + let mut chunks = buf.chunks_exact(ZEROS_LEN); - // No one modifies rent_epoch (yet). - if pre.rent_epoch != post.rent_epoch { - return Err(InstructionError::RentEpochModified); + chunks.all(|chunk| chunk == &ZEROS[..]) + && chunks.remainder() == &ZEROS[..chunks.remainder().len()] } - - Ok(()) } pub type ProcessInstruction = fn(&Pubkey, &[KeyedAccount], &[u8]) -> Result<(), InstructionError>; - pub type SymbolCache = RwLock, Symbol>>; #[derive(Serialize, Deserialize)] @@ -232,21 +238,40 @@ impl MessageProcessor { Ok(()) } - pub fn sum_account_lamports(accounts: &[Rc>]) -> u128 { - // Note: This is an O(n^2) algorithm, - // but performed on a very small slice and requires no heap allocations - accounts - .iter() - .enumerate() - .map(|(i, a)| { - for account in accounts.iter().skip(i + 1) { - if Rc::ptr_eq(a, account) { - return 0; // don't double count duplicates - } + pub fn verify( + program_id: &Pubkey, + pre_accounts: &[PreAccount], + executable_accounts: &[(Pubkey, RefCell)], + program_accounts: &[Rc>], + ) -> Result<(), InstructionError> { + // Verify all accounts have zero outstanding refs + Self::verify_account_references(executable_accounts, program_accounts)?; + + // Verify the per-account instruction results + let (mut pre_sum, mut post_sum) = (0_u128, 0_u128); + 'root: for (i, (pre_account, account)) in + pre_accounts.iter().zip(program_accounts).enumerate() + { + // Note: This is an O(n^2) algorithm, + // but performed on a very small slice and requires no heap allocations + for account_after in program_accounts.iter().skip(i + 1) { + if Rc::ptr_eq(account, account_after) { + continue 'root; // don't verify duplicates } - u128::from(a.borrow().lamports) - }) - .sum() + } + let account = account + .try_borrow() + .map_err(|_| InstructionError::AccountBorrowFailed)?; + pre_account.verify(&program_id, &account)?; + pre_sum += u128::from(pre_account.lamports); + post_sum += u128::from(account.lamports); + } + + // Verify that the total sum of all the lamports did not change + if pre_sum != post_sum { + return Err(InstructionError::UnbalancedInstruction); + } + Ok(()) } /// Execute an instruction @@ -269,32 +294,20 @@ impl MessageProcessor { .map(|(i, account)| { let is_writable = message.is_writable(instruction.accounts[i] as usize); let account = account.borrow(); - PreInstructionAccount::new( - &account, - is_writable, - need_account_data_checked(&account.owner, program_id, is_writable), - ) + PreAccount::new(&account, is_writable, program_id) }) .collect(); - // Sum total lamports before instruction processing - let pre_total = Self::sum_account_lamports(program_accounts); self.process_instruction(message, instruction, executable_accounts, program_accounts)?; - // Verify all accounts have zero outstanding refs - Self::verify_account_references(executable_accounts, program_accounts)?; - // Verify the instruction - for (pre_account, post_account) in pre_accounts.iter().zip(program_accounts.iter()) { - let post_account = post_account - .try_borrow() - .map_err(|_| InstructionError::AccountBorrowFailed)?; - verify_account_changes(&program_id, pre_account, &post_account)?; - } - // Verify total sum of all the lamports did not change - let post_total = Self::sum_account_lamports(program_accounts); - if pre_total != post_total { - return Err(InstructionError::UnbalancedInstruction); - } + // Verify the instruction results + Self::verify( + &program_id, + &pre_accounts, + executable_accounts, + program_accounts, + )?; + Ok(()) } @@ -329,15 +342,6 @@ impl MessageProcessor { } } -pub const ZEROS_LEN: usize = 1024; -static ZEROS: [u8; ZEROS_LEN] = [0; ZEROS_LEN]; -pub fn is_zeroed(buf: &[u8]) -> bool { - let mut chunks = buf.chunks_exact(ZEROS_LEN); - - chunks.all(|chunk| chunk == &ZEROS[..]) - && chunks.remainder() == &ZEROS[..chunks.remainder().len()] -} - #[cfg(test)] mod tests { use super::*; @@ -349,23 +353,24 @@ mod tests { #[test] fn test_is_zeroed() { + const ZEROS_LEN: usize = 1024; let mut buf = [0; ZEROS_LEN]; - assert_eq!(is_zeroed(&buf), true); + assert_eq!(PreAccount::is_zeroed(&buf), true); buf[0] = 1; - assert_eq!(is_zeroed(&buf), false); + assert_eq!(PreAccount::is_zeroed(&buf), false); let mut buf = [0; ZEROS_LEN - 1]; - assert_eq!(is_zeroed(&buf), true); + assert_eq!(PreAccount::is_zeroed(&buf), true); buf[0] = 1; - assert_eq!(is_zeroed(&buf), false); + assert_eq!(PreAccount::is_zeroed(&buf), false); let mut buf = [0; ZEROS_LEN + 1]; - assert_eq!(is_zeroed(&buf), true); + assert_eq!(PreAccount::is_zeroed(&buf), true); buf[0] = 1; - assert_eq!(is_zeroed(&buf), false); + assert_eq!(PreAccount::is_zeroed(&buf), false); let buf = vec![]; - assert_eq!(is_zeroed(&buf), true); + assert_eq!(PreAccount::is_zeroed(&buf), true); } #[test] @@ -394,51 +399,6 @@ mod tests { ); } - #[test] - fn test_sum_account_lamports() { - let owner_pubkey = Pubkey::new_rand(); - let account1 = Rc::new(RefCell::new(Account::new(1, 1, &owner_pubkey))); - let account2 = Rc::new(RefCell::new(Account::new(2, 1, &owner_pubkey))); - let account3 = Rc::new(RefCell::new(Account::new(3, 1, &owner_pubkey))); - - assert_eq!(0, MessageProcessor::sum_account_lamports(&vec![])); - assert_eq!( - 6, - MessageProcessor::sum_account_lamports(&vec![ - account1.clone(), - account2.clone(), - account3.clone() - ]) - ); - assert_eq!( - 3, - MessageProcessor::sum_account_lamports(&vec![ - account1.clone(), - account2.clone(), - account1.clone() - ]) - ); - assert_eq!( - 1, - MessageProcessor::sum_account_lamports(&vec![ - account1.clone(), - account1.clone(), - account1.clone() - ]) - ); - assert_eq!( - 6, - MessageProcessor::sum_account_lamports(&vec![ - account1.clone(), - account2.clone(), - account3.clone(), - account1.clone(), - account2.clone(), - account3.clone(), - ]) - ); - } - #[test] fn test_verify_account_changes_owner() { fn change_owner( @@ -447,15 +407,8 @@ mod tests { post: &Pubkey, is_writable: bool, ) -> Result<(), InstructionError> { - verify_account_changes( - &ix, - &PreInstructionAccount::new( - &Account::new(0, 0, pre), - is_writable, - need_account_data_checked(pre, ix, is_writable), - ), - &Account::new(0, 0, post), - ) + PreAccount::new(&Account::new(0, 0, pre), is_writable, ix) + .verify(ix, &Account::new(0, 0, post)) } let system_program_id = system_program::id(); @@ -505,27 +458,27 @@ mod tests { ); assert_eq!( - verify_account_changes( + PreAccount::new( + &Account::new_data(0, &[42], &mallory_program_id).unwrap(), + true, &mallory_program_id, - &PreInstructionAccount::new( - &Account::new_data(0, &[42], &mallory_program_id).unwrap(), - true, - need_account_data_checked(&mallory_program_id, &mallory_program_id, true), - ), - &Account::new_data(0, &[0], &alice_program_id,).unwrap(), + ) + .verify( + &mallory_program_id, + &Account::new_data(0, &[0], &alice_program_id).unwrap(), ), Ok(()), "mallory should be able to change the account owner, if she leaves clear data" ); assert_eq!( - verify_account_changes( + PreAccount::new( + &Account::new_data(0, &[42], &mallory_program_id).unwrap(), + true, &mallory_program_id, - &PreInstructionAccount::new( - &Account::new_data(0, &[42], &mallory_program_id).unwrap(), - true, - need_account_data_checked(&mallory_program_id, &mallory_program_id, true), - ), - &Account::new_data(0, &[42], &alice_program_id,).unwrap(), + ) + .verify( + &mallory_program_id, + &Account::new_data(0, &[42], &alice_program_id).unwrap(), ), Err(InstructionError::ModifiedProgramId), "mallory should not be able to inject data into the alice program" @@ -540,14 +493,14 @@ mod tests { pre_executable: bool, post_executable: bool| -> Result<(), InstructionError> { - let pre = PreInstructionAccount::new( + let pre = PreAccount::new( &Account { owner, executable: pre_executable, ..Account::default() }, is_writable, - need_account_data_checked(&owner, &program_id, is_writable), + &program_id, ); let post = Account { @@ -555,7 +508,7 @@ mod tests { executable: post_executable, ..Account::default() }; - verify_account_changes(&program_id, &pre, &post) + pre.verify(&program_id, &post) }; let mallory_program_id = Pubkey::new_rand(); @@ -591,14 +544,14 @@ mod tests { #[test] fn test_verify_account_changes_data_len() { assert_eq!( - verify_account_changes( + PreAccount::new( + &Account::new_data(0, &[0], &system_program::id()).unwrap(), + true, + &system_program::id() + ) + .verify( &system_program::id(), - &PreInstructionAccount::new( - &Account::new_data(0, &[0], &system_program::id()).unwrap(), - true, - need_account_data_checked(&system_program::id(), &system_program::id(), true), - ), - &Account::new_data(0, &[0, 0], &system_program::id()).unwrap(), + &Account::new_data(0, &[0, 0], &system_program::id()).unwrap() ), Ok(()), "system program should be able to change the data len" @@ -606,13 +559,12 @@ mod tests { let alice_program_id = Pubkey::new_rand(); assert_eq!( - verify_account_changes( - &system_program::id(), - &PreInstructionAccount::new( + PreAccount::new( &Account::new_data(0, &[0], &alice_program_id).unwrap(), true, - need_account_data_checked(&alice_program_id, &system_program::id(), true), - ), + &system_program::id(), + ).verify( + &system_program::id(), &Account::new_data(0, &[0, 0], &alice_program_id).unwrap(), ), Err(InstructionError::AccountDataSizeChanged), @@ -626,13 +578,13 @@ mod tests { let change_data = |program_id: &Pubkey, is_writable: bool| -> Result<(), InstructionError> { - let pre = PreInstructionAccount::new( + let pre = PreAccount::new( &Account::new_data(0, &[0], &alice_program_id).unwrap(), is_writable, - need_account_data_checked(&alice_program_id, &program_id, is_writable), + &program_id, ); let post = Account::new_data(0, &[42], &alice_program_id).unwrap(); - verify_account_changes(&program_id, &pre, &post) + pre.verify(&program_id, &post) }; let mallory_program_id = Pubkey::new_rand(); @@ -658,22 +610,22 @@ mod tests { #[test] fn test_verify_account_changes_rent_epoch() { let alice_program_id = Pubkey::new_rand(); - let pre = PreInstructionAccount::new( + let pre = PreAccount::new( &Account::new(0, 0, &alice_program_id), false, - need_account_data_checked(&alice_program_id, &system_program::id(), false), + &system_program::id(), ); let mut post = Account::new(0, 0, &alice_program_id); assert_eq!( - verify_account_changes(&system_program::id(), &pre, &post), + pre.verify(&system_program::id(), &post), Ok(()), "nothing changed!" ); post.rent_epoch += 1; assert_eq!( - verify_account_changes(&system_program::id(), &pre, &post), + pre.verify(&system_program::id(), &post), Err(InstructionError::RentEpochModified), "no one touches rent_epoch" ); @@ -683,16 +635,16 @@ mod tests { fn test_verify_account_changes_deduct_lamports_and_reassign_account() { let alice_program_id = Pubkey::new_rand(); let bob_program_id = Pubkey::new_rand(); - let pre = PreInstructionAccount::new( + let pre = PreAccount::new( &Account::new_data(42, &[42], &alice_program_id).unwrap(), true, - need_account_data_checked(&alice_program_id, &alice_program_id, true), + &alice_program_id, ); let post = Account::new_data(1, &[0], &bob_program_id).unwrap(); // positive test of this capability assert_eq!( - verify_account_changes(&alice_program_id, &pre, &post), + pre.verify(&alice_program_id, &post), Ok(()), "alice should be able to deduct lamports and give the account to bob if the data is zeroed", ); @@ -701,51 +653,51 @@ mod tests { #[test] fn test_verify_account_changes_lamports() { let alice_program_id = Pubkey::new_rand(); - let pre = PreInstructionAccount::new( + let pre = PreAccount::new( &Account::new(42, 0, &alice_program_id), false, - need_account_data_checked(&alice_program_id, &system_program::id(), false), + &system_program::id(), ); let post = Account::new(0, 0, &alice_program_id); assert_eq!( - verify_account_changes(&system_program::id(), &pre, &post), + pre.verify(&system_program::id(), &post), Err(InstructionError::ExternalAccountLamportSpend), "debit should fail, even if system program" ); - let pre = PreInstructionAccount::new( + let pre = PreAccount::new( &Account::new(42, 0, &alice_program_id), false, - need_account_data_checked(&alice_program_id, &alice_program_id, false), + &alice_program_id, ); assert_eq!( - verify_account_changes(&alice_program_id, &pre, &post,), + pre.verify(&alice_program_id, &post,), Err(InstructionError::ReadonlyLamportChange), "debit should fail, even if owning program" ); - let pre = PreInstructionAccount::new( + let pre = PreAccount::new( &Account::new(42, 0, &alice_program_id), true, - need_account_data_checked(&alice_program_id, &system_program::id(), true), + &system_program::id(), ); let post = Account::new(0, 0, &system_program::id()); assert_eq!( - verify_account_changes(&system_program::id(), &pre, &post), + pre.verify(&system_program::id(), &post), Err(InstructionError::ModifiedProgramId), "system program can't debit the account unless it was the pre.owner" ); - let pre = PreInstructionAccount::new( + let pre = PreAccount::new( &Account::new(42, 0, &system_program::id()), true, - need_account_data_checked(&system_program::id(), &system_program::id(), true), + &system_program::id(), ); let post = Account::new(0, 0, &alice_program_id); assert_eq!( - verify_account_changes(&system_program::id(), &pre, &post), + pre.verify(&system_program::id(), &post), Ok(()), "system can spend (and change owner)" ); @@ -754,34 +706,34 @@ mod tests { #[test] fn test_verify_account_changes_data_size_changed() { let alice_program_id = Pubkey::new_rand(); - let pre = PreInstructionAccount::new( + let pre = PreAccount::new( &Account::new_data(42, &[0], &alice_program_id).unwrap(), true, - need_account_data_checked(&alice_program_id, &system_program::id(), true), + &system_program::id(), ); let post = Account::new_data(42, &[0, 0], &alice_program_id).unwrap(); assert_eq!( - verify_account_changes(&system_program::id(), &pre, &post), + pre.verify(&system_program::id(), &post), Err(InstructionError::AccountDataSizeChanged), "system program should not be able to change another program's account data size" ); - let pre = PreInstructionAccount::new( + let pre = PreAccount::new( &Account::new_data(42, &[0], &alice_program_id).unwrap(), true, - need_account_data_checked(&alice_program_id, &alice_program_id, true), + &alice_program_id, ); assert_eq!( - verify_account_changes(&alice_program_id, &pre, &post), + pre.verify(&alice_program_id, &post), Err(InstructionError::AccountDataSizeChanged), "non-system programs cannot change their data size" ); - let pre = PreInstructionAccount::new( + let pre = PreAccount::new( &Account::new_data(42, &[0], &system_program::id()).unwrap(), true, - need_account_data_checked(&system_program::id(), &system_program::id(), true), + &system_program::id(), ); assert_eq!( - verify_account_changes(&system_program::id(), &pre, &post), + pre.verify(&system_program::id(), &post), Ok(()), "system program should be able to change acount data size" );