Optimize account verification (#8385)

This commit is contained in:
Jack May 2020-02-21 13:28:35 -08:00 committed by GitHub
parent 0e6aca5a7e
commit 0ace22d03f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 96 additions and 86 deletions

View File

@ -2593,7 +2593,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "solana-bpf-loader-program"
version = "0.24.0"
version = "1.0.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)",
@ -2601,28 +2601,28 @@ 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)",
"solana-logger 0.24.0",
"solana-sdk 0.24.0",
"solana-logger 1.0.0",
"solana-sdk 1.0.0",
"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]]
name = "solana-config-program"
version = "0.24.0"
version = "1.0.0"
dependencies = [
"bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.4.10 (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)",
"serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
"solana-logger 0.24.0",
"solana-sdk 0.24.0",
"solana-logger 1.0.0",
"solana-sdk 1.0.0",
]
[[package]]
name = "solana-crate-features"
version = "0.24.0"
version = "1.0.0"
dependencies = [
"backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)",
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2645,20 +2645,20 @@ dependencies = [
[[package]]
name = "solana-librapay"
version = "0.24.0"
version = "1.0.0"
dependencies = [
"bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"solana-logger 0.24.0",
"solana-move-loader-program 0.24.0",
"solana-runtime 0.24.0",
"solana-sdk 0.24.0",
"solana-logger 1.0.0",
"solana-move-loader-program 1.0.0",
"solana-runtime 1.0.0",
"solana-sdk 1.0.0",
"solana_libra_types 0.0.1-sol4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "solana-logger"
version = "0.24.0"
version = "1.0.0"
dependencies = [
"env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2667,30 +2667,30 @@ dependencies = [
[[package]]
name = "solana-measure"
version = "0.24.0"
version = "1.0.0"
dependencies = [
"jemalloc-ctl 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"jemallocator 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"solana-metrics 0.24.0",
"solana-sdk 0.24.0",
"solana-metrics 1.0.0",
"solana-sdk 1.0.0",
]
[[package]]
name = "solana-metrics"
version = "0.24.0"
version = "1.0.0"
dependencies = [
"env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"reqwest 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"solana-sdk 0.24.0",
"solana-sdk 1.0.0",
"sys-info 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "solana-move-loader-program"
version = "0.24.0"
version = "1.0.0"
dependencies = [
"bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2701,8 +2701,8 @@ dependencies = [
"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)",
"serde_json 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)",
"solana-logger 0.24.0",
"solana-sdk 0.24.0",
"solana-logger 1.0.0",
"solana-sdk 1.0.0",
"solana_libra_bytecode_verifier 0.0.1-sol4 (registry+https://github.com/rust-lang/crates.io-index)",
"solana_libra_canonical_serialization 0.0.1-sol4 (registry+https://github.com/rust-lang/crates.io-index)",
"solana_libra_compiler 0.0.1-sol4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2719,7 +2719,7 @@ dependencies = [
[[package]]
name = "solana-rayon-threadlimit"
version = "0.24.0"
version = "1.0.0"
dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"sys-info 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2727,7 +2727,7 @@ dependencies = [
[[package]]
name = "solana-runtime"
version = "0.24.0"
version = "1.0.0"
dependencies = [
"bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bv 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2745,15 +2745,15 @@ dependencies = [
"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)",
"solana-bpf-loader-program 0.24.0",
"solana-logger 0.24.0",
"solana-measure 0.24.0",
"solana-metrics 0.24.0",
"solana-rayon-threadlimit 0.24.0",
"solana-sdk 0.24.0",
"solana-stake-program 0.24.0",
"solana-storage-program 0.24.0",
"solana-vote-program 0.24.0",
"solana-bpf-loader-program 1.0.0",
"solana-logger 1.0.0",
"solana-measure 1.0.0",
"solana-metrics 1.0.0",
"solana-rayon-threadlimit 1.0.0",
"solana-sdk 1.0.0",
"solana-stake-program 1.0.0",
"solana-storage-program 1.0.0",
"solana-vote-program 1.0.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)",
@ -2761,7 +2761,7 @@ dependencies = [
[[package]]
name = "solana-sdk"
version = "0.24.0"
version = "1.0.0"
dependencies = [
"assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2785,15 +2785,15 @@ dependencies = [
"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)",
"sha2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"solana-crate-features 0.24.0",
"solana-logger 0.24.0",
"solana-sdk-macro 0.24.0",
"solana-crate-features 1.0.0",
"solana-logger 1.0.0",
"solana-sdk-macro 1.0.0",
"thiserror 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "solana-sdk-macro"
version = "0.24.0"
version = "1.0.0"
dependencies = [
"bs58 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2803,7 +2803,7 @@ dependencies = [
[[package]]
name = "solana-stake-program"
version = "0.24.0"
version = "1.0.0"
dependencies = [
"bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2811,17 +2811,17 @@ dependencies = [
"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_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
"solana-config-program 0.24.0",
"solana-logger 0.24.0",
"solana-metrics 0.24.0",
"solana-sdk 0.24.0",
"solana-vote-program 0.24.0",
"solana-config-program 1.0.0",
"solana-logger 1.0.0",
"solana-metrics 1.0.0",
"solana-sdk 1.0.0",
"solana-vote-program 1.0.0",
"thiserror 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "solana-storage-program"
version = "0.24.0"
version = "1.0.0"
dependencies = [
"bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2830,13 +2830,13 @@ dependencies = [
"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-logger 0.24.0",
"solana-sdk 0.24.0",
"solana-logger 1.0.0",
"solana-sdk 1.0.0",
]
[[package]]
name = "solana-vote-program"
version = "0.24.0"
version = "1.0.0"
dependencies = [
"bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2844,9 +2844,9 @@ dependencies = [
"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_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
"solana-logger 0.24.0",
"solana-metrics 0.24.0",
"solana-sdk 0.24.0",
"solana-logger 1.0.0",
"solana-metrics 1.0.0",
"solana-sdk 1.0.0",
"thiserror 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
]

View File

@ -19,7 +19,6 @@ use libloading::os::windows::*;
// The relevant state of an account before an Instruction executes, used
// to verify account integrity after the Instruction completes
#[derive(Clone, Debug, PartialEq)]
pub struct PreAccount {
pub is_writable: bool,
pub lamports: u64,
@ -54,8 +53,6 @@ impl PreAccount {
}
pub fn verify(&self, program_id: &Pubkey, 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
@ -221,6 +218,35 @@ impl MessageProcessor {
)
}
/// Record the initial state of the accounts so that it can be compared
// after the instruction is processed
pub fn create_pre_accounts(
// program_id: &Pubkey,
message: &Message,
instruction: &CompiledInstruction,
program_accounts: &[Rc<RefCell<Account>>],
) -> Vec<Option<PreAccount>> {
let program_id = instruction.program_id(&message.account_keys);
// Copy only what we need to verify after instruction processing
let mut pre_accounts = Vec::with_capacity(program_accounts.len());
'root: for (i, account) in program_accounts.iter().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) {
pre_accounts.push(None);
continue 'root; // don't verify duplicates
}
}
let is_writable = message.is_writable(instruction.accounts[i] as usize);
let account = account.borrow();
pre_accounts.push(Some(PreAccount::new(&account, is_writable, program_id)))
}
pre_accounts
}
/// Verify there are no outstanding borrows
pub fn verify_account_references(
executable_accounts: &[(Pubkey, RefCell<Account>)],
program_accounts: &[Rc<RefCell<Account>>],
@ -238,33 +264,30 @@ impl MessageProcessor {
Ok(())
}
/// Verify the results of an instruction
pub fn verify(
program_id: &Pubkey,
pre_accounts: &[PreAccount],
message: &Message,
instruction: &CompiledInstruction,
pre_accounts: &[Option<PreAccount>],
executable_accounts: &[(Pubkey, RefCell<Account>)],
program_accounts: &[Rc<RefCell<Account>>],
) -> Result<(), InstructionError> {
let program_id = instruction.program_id(&message.account_keys);
// 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
}
for (pre_account, account) in pre_accounts.iter().zip(program_accounts) {
if let Some(pre_account) = pre_account {
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);
}
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
@ -286,28 +309,15 @@ impl MessageProcessor {
program_accounts: &[Rc<RefCell<Account>>],
) -> Result<(), InstructionError> {
assert_eq!(instruction.accounts.len(), program_accounts.len());
let program_id = instruction.program_id(&message.account_keys);
// Copy only what we need to verify after instruction processing
let pre_accounts: Vec<_> = program_accounts
.iter()
.enumerate()
.map(|(i, account)| {
let is_writable = message.is_writable(instruction.accounts[i] as usize);
let account = account.borrow();
PreAccount::new(&account, is_writable, program_id)
})
.collect();
let pre_accounts = Self::create_pre_accounts(message, instruction, program_accounts);
self.process_instruction(message, instruction, executable_accounts, program_accounts)?;
// Verify the instruction results
Self::verify(
&program_id,
message,
instruction,
&pre_accounts,
executable_accounts,
program_accounts,
)?;
Ok(())
}