Credit-Only Accounts: Cache account balance for thread-safe load/store (#4691)
* Implement CreditOnlyLocks * Update credit-only atomic on account load * Update credit-only atomic after bank.freeze_lock; store credits if all credit-only lock references are dropped * Commit credit-only credits on bank freeze * Update core to CreditAccountLocks * Impl credit-only in System Transfer * Rework CreditAccountLocks, test, and fix bugs * Review comments: Pass CreditAccountLocks by reference; Tighten up insert block * Only store credits on completed slot * Check balance in bench_exchange funding to ensure commit_credits has completed * Add is_debitable info to KeyedAccount meta to pass into programs * Reinstate CreditOnlyLocks check on lock_account * Rework CreditAccountLocks to remove strong_count usage * Add multi-threaded credit-only locks test * Improve RwLocks usage * Review comments: panic if bad things happen; tighter code * Assert lock_accounts race does not happen * Revert panic if bad things happen; not a bad thing
This commit is contained in:
@ -1,7 +1,9 @@
|
||||
use crate::native_loader;
|
||||
use crate::system_instruction_processor;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use solana_sdk::account::{create_keyed_accounts, Account, KeyedAccount, LamportCredit};
|
||||
use solana_sdk::account::{
|
||||
create_keyed_credit_only_accounts, Account, KeyedAccount, LamportCredit,
|
||||
};
|
||||
use solana_sdk::instruction::{CompiledInstruction, InstructionError};
|
||||
use solana_sdk::instruction_processor_utils;
|
||||
use solana_sdk::message::Message;
|
||||
@ -139,17 +141,28 @@ impl MessageProcessor {
|
||||
) -> Result<(), InstructionError> {
|
||||
let program_id = instruction.program_id(&message.account_keys);
|
||||
|
||||
let mut keyed_accounts = create_keyed_accounts(executable_accounts);
|
||||
let mut keyed_accounts = create_keyed_credit_only_accounts(executable_accounts);
|
||||
let mut keyed_accounts2: Vec<_> = instruction
|
||||
.accounts
|
||||
.iter()
|
||||
.map(|&index| {
|
||||
let index = index as usize;
|
||||
let key = &message.account_keys[index];
|
||||
(key, index < message.header.num_required_signatures as usize)
|
||||
let is_debitable = message.is_debitable(index);
|
||||
(
|
||||
key,
|
||||
index < message.header.num_required_signatures as usize,
|
||||
is_debitable,
|
||||
)
|
||||
})
|
||||
.zip(program_accounts.iter_mut())
|
||||
.map(|((key, is_signer), account)| KeyedAccount::new(key, is_signer, account))
|
||||
.map(|((key, is_signer, is_debitable), account)| {
|
||||
if is_debitable {
|
||||
KeyedAccount::new(key, is_signer, account)
|
||||
} else {
|
||||
KeyedAccount::new_credit_only(key, is_signer, account)
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
keyed_accounts.append(&mut keyed_accounts2);
|
||||
|
||||
@ -184,6 +197,7 @@ impl MessageProcessor {
|
||||
credits: &mut [&mut LamportCredit],
|
||||
) -> Result<(), InstructionError> {
|
||||
let program_id = instruction.program_id(&message.account_keys);
|
||||
assert_eq!(instruction.accounts.len(), program_accounts.len());
|
||||
// TODO: the runtime should be checking read/write access to memory
|
||||
// we are trusting the hard-coded programs not to clobber or allocate
|
||||
let pre_total: u128 = program_accounts
|
||||
@ -202,7 +216,13 @@ impl MessageProcessor {
|
||||
program_accounts
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, program_account)| (i, program_account, message.is_debitable(i))),
|
||||
.map(|(i, program_account)| {
|
||||
(
|
||||
i,
|
||||
program_account,
|
||||
message.is_debitable(instruction.accounts[i] as usize),
|
||||
)
|
||||
}),
|
||||
)
|
||||
{
|
||||
verify_instruction(
|
||||
|
Reference in New Issue
Block a user