Upgradeable programs called same as non-upgradeable (#14239)
* Upgradeable programs called same as non-upgradeable * nudge
This commit is contained in:
@ -2,8 +2,8 @@
|
|||||||
//! uses the instruction data provided and all the accounts
|
//! uses the instruction data provided and all the accounts
|
||||||
|
|
||||||
use solana_program::{
|
use solana_program::{
|
||||||
account_info::AccountInfo, bpf_loader_upgradeable, entrypoint, entrypoint::ProgramResult,
|
account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, instruction::AccountMeta,
|
||||||
instruction::AccountMeta, instruction::Instruction, program::invoke, pubkey::Pubkey,
|
instruction::Instruction, program::invoke, pubkey::Pubkey,
|
||||||
};
|
};
|
||||||
|
|
||||||
entrypoint!(process_instruction);
|
entrypoint!(process_instruction);
|
||||||
@ -15,13 +15,8 @@ fn process_instruction(
|
|||||||
) -> ProgramResult {
|
) -> ProgramResult {
|
||||||
let to_call = accounts[0].key;
|
let to_call = accounts[0].key;
|
||||||
let infos = accounts;
|
let infos = accounts;
|
||||||
let last = if bpf_loader_upgradeable::check_id(accounts[0].owner) {
|
|
||||||
accounts.len() - 1
|
|
||||||
} else {
|
|
||||||
accounts.len()
|
|
||||||
};
|
|
||||||
let instruction = Instruction {
|
let instruction = Instruction {
|
||||||
accounts: accounts[1..last]
|
accounts: accounts[1..]
|
||||||
.iter()
|
.iter()
|
||||||
.map(|acc| AccountMeta {
|
.map(|acc| AccountMeta {
|
||||||
pubkey: *acc.key,
|
pubkey: *acc.key,
|
||||||
|
@ -21,9 +21,7 @@ use solana_runtime::{
|
|||||||
};
|
};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::Account,
|
account::Account,
|
||||||
account_utils::StateMut,
|
|
||||||
bpf_loader, bpf_loader_deprecated,
|
bpf_loader, bpf_loader_deprecated,
|
||||||
bpf_loader_upgradeable::UpgradeableLoaderState,
|
|
||||||
client::SyncClient,
|
client::SyncClient,
|
||||||
clock::{DEFAULT_SLOTS_PER_EPOCH, MAX_PROCESSING_AGE},
|
clock::{DEFAULT_SLOTS_PER_EPOCH, MAX_PROCESSING_AGE},
|
||||||
entrypoint::{MAX_PERMITTED_DATA_INCREASE, SUCCESS},
|
entrypoint::{MAX_PERMITTED_DATA_INCREASE, SUCCESS},
|
||||||
@ -1479,11 +1477,11 @@ fn test_program_bpf_upgrade() {
|
|||||||
bank.add_builtin(&name, id, entrypoint);
|
bank.add_builtin(&name, id, entrypoint);
|
||||||
let bank_client = BankClient::new(bank);
|
let bank_client = BankClient::new(bank);
|
||||||
|
|
||||||
// deploy upgrade program
|
// Deploy upgrade program
|
||||||
let (program_id, authority_keypair) =
|
let (program_id, authority_keypair) =
|
||||||
load_upgradeable_bpf_program(&bank_client, &mint_keypair, "solana_bpf_rust_upgradeable");
|
load_upgradeable_bpf_program(&bank_client, &mint_keypair, "solana_bpf_rust_upgradeable");
|
||||||
|
|
||||||
// call upgrade program
|
// Call upgrade program
|
||||||
nonce += 1;
|
nonce += 1;
|
||||||
let instruction = Instruction::new(
|
let instruction = Instruction::new(
|
||||||
program_id,
|
program_id,
|
||||||
@ -1499,7 +1497,7 @@ fn test_program_bpf_upgrade() {
|
|||||||
TransactionError::InstructionError(0, InstructionError::Custom(42))
|
TransactionError::InstructionError(0, InstructionError::Custom(42))
|
||||||
);
|
);
|
||||||
|
|
||||||
// upgrade program
|
// Upgrade program
|
||||||
upgrade_bpf_program(
|
upgrade_bpf_program(
|
||||||
&bank_client,
|
&bank_client,
|
||||||
&mint_keypair,
|
&mint_keypair,
|
||||||
@ -1508,7 +1506,7 @@ fn test_program_bpf_upgrade() {
|
|||||||
"solana_bpf_rust_upgraded",
|
"solana_bpf_rust_upgraded",
|
||||||
);
|
);
|
||||||
|
|
||||||
// call upgraded program
|
// Call upgraded program
|
||||||
nonce += 1;
|
nonce += 1;
|
||||||
let instruction = Instruction::new(
|
let instruction = Instruction::new(
|
||||||
program_id,
|
program_id,
|
||||||
@ -1524,7 +1522,7 @@ fn test_program_bpf_upgrade() {
|
|||||||
TransactionError::InstructionError(0, InstructionError::Custom(43))
|
TransactionError::InstructionError(0, InstructionError::Custom(43))
|
||||||
);
|
);
|
||||||
|
|
||||||
// upgrade back to the original program
|
// Set a new authority
|
||||||
let new_authority_keypair = Keypair::new();
|
let new_authority_keypair = Keypair::new();
|
||||||
set_upgrade_authority(
|
set_upgrade_authority(
|
||||||
&bank_client,
|
&bank_client,
|
||||||
@ -1534,7 +1532,7 @@ fn test_program_bpf_upgrade() {
|
|||||||
Some(&new_authority_keypair.pubkey()),
|
Some(&new_authority_keypair.pubkey()),
|
||||||
);
|
);
|
||||||
|
|
||||||
// upgrade back to the original program
|
// Upgrade back to the original program
|
||||||
upgrade_bpf_program(
|
upgrade_bpf_program(
|
||||||
&bank_client,
|
&bank_client,
|
||||||
&mint_keypair,
|
&mint_keypair,
|
||||||
@ -1543,7 +1541,7 @@ fn test_program_bpf_upgrade() {
|
|||||||
"solana_bpf_rust_upgradeable",
|
"solana_bpf_rust_upgradeable",
|
||||||
);
|
);
|
||||||
|
|
||||||
// call original program
|
// Call original program
|
||||||
nonce += 1;
|
nonce += 1;
|
||||||
let instruction = Instruction::new(
|
let instruction = Instruction::new(
|
||||||
program_id,
|
program_id,
|
||||||
@ -1562,9 +1560,10 @@ fn test_program_bpf_upgrade() {
|
|||||||
|
|
||||||
#[cfg(feature = "bpf_rust")]
|
#[cfg(feature = "bpf_rust")]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_program_bpf_invoke_upgradeable() {
|
fn test_program_bpf_invoke_upgradeable_via_cpi() {
|
||||||
solana_logger::setup();
|
solana_logger::setup();
|
||||||
|
|
||||||
|
let mut nonce = 0;
|
||||||
let GenesisConfigInfo {
|
let GenesisConfigInfo {
|
||||||
genesis_config,
|
genesis_config,
|
||||||
mint_keypair,
|
mint_keypair,
|
||||||
@ -1583,29 +1582,81 @@ fn test_program_bpf_invoke_upgradeable() {
|
|||||||
"solana_bpf_rust_invoke_and_return",
|
"solana_bpf_rust_invoke_and_return",
|
||||||
);
|
);
|
||||||
|
|
||||||
// deploy upgrade program
|
// Deploy upgrade program
|
||||||
let (program_id, _) =
|
let (program_id, authority_keypair) =
|
||||||
load_upgradeable_bpf_program(&bank_client, &mint_keypair, "solana_bpf_rust_upgradeable");
|
load_upgradeable_bpf_program(&bank_client, &mint_keypair, "solana_bpf_rust_upgradeable");
|
||||||
|
|
||||||
let data = bank_client.get_account(&program_id).unwrap().unwrap();
|
// Call invoker program to invoke the upgradeable program
|
||||||
let programdata_address = if let UpgradeableLoaderState::Program {
|
nonce += 1;
|
||||||
programdata_address,
|
|
||||||
} = data.state().unwrap()
|
|
||||||
{
|
|
||||||
programdata_address
|
|
||||||
} else {
|
|
||||||
panic!("Not a program");
|
|
||||||
};
|
|
||||||
|
|
||||||
// call invoker program to invoke the upgradeable program
|
|
||||||
let instruction = Instruction::new(
|
let instruction = Instruction::new(
|
||||||
invoke_and_return,
|
invoke_and_return,
|
||||||
&[0],
|
&[nonce],
|
||||||
|
vec![
|
||||||
|
AccountMeta::new(program_id, false),
|
||||||
|
AccountMeta::new(clock::id(), false),
|
||||||
|
AccountMeta::new(fees::id(), false),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||||
|
assert_eq!(
|
||||||
|
result.unwrap_err().unwrap(),
|
||||||
|
TransactionError::InstructionError(0, InstructionError::Custom(42))
|
||||||
|
);
|
||||||
|
|
||||||
|
// Upgrade program
|
||||||
|
upgrade_bpf_program(
|
||||||
|
&bank_client,
|
||||||
|
&mint_keypair,
|
||||||
|
&program_id,
|
||||||
|
&authority_keypair,
|
||||||
|
"solana_bpf_rust_upgraded",
|
||||||
|
);
|
||||||
|
|
||||||
|
// Call the upgraded program
|
||||||
|
nonce += 1;
|
||||||
|
let instruction = Instruction::new(
|
||||||
|
invoke_and_return,
|
||||||
|
&[nonce],
|
||||||
|
vec![
|
||||||
|
AccountMeta::new(program_id, false),
|
||||||
|
AccountMeta::new(clock::id(), false),
|
||||||
|
AccountMeta::new(fees::id(), false),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||||
|
assert_eq!(
|
||||||
|
result.unwrap_err().unwrap(),
|
||||||
|
TransactionError::InstructionError(0, InstructionError::Custom(43))
|
||||||
|
);
|
||||||
|
|
||||||
|
// Set a new authority
|
||||||
|
let new_authority_keypair = Keypair::new();
|
||||||
|
set_upgrade_authority(
|
||||||
|
&bank_client,
|
||||||
|
&mint_keypair,
|
||||||
|
&program_id,
|
||||||
|
&authority_keypair,
|
||||||
|
Some(&new_authority_keypair.pubkey()),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Upgrade back to the original program
|
||||||
|
upgrade_bpf_program(
|
||||||
|
&bank_client,
|
||||||
|
&mint_keypair,
|
||||||
|
&program_id,
|
||||||
|
&new_authority_keypair,
|
||||||
|
"solana_bpf_rust_upgradeable",
|
||||||
|
);
|
||||||
|
|
||||||
|
// Call original program
|
||||||
|
nonce += 1;
|
||||||
|
let instruction = Instruction::new(
|
||||||
|
invoke_and_return,
|
||||||
|
&[nonce],
|
||||||
vec![
|
vec![
|
||||||
AccountMeta::new(program_id, false),
|
AccountMeta::new(program_id, false),
|
||||||
AccountMeta::new(clock::id(), false),
|
AccountMeta::new(clock::id(), false),
|
||||||
AccountMeta::new(fees::id(), false),
|
AccountMeta::new(fees::id(), false),
|
||||||
AccountMeta::new(programdata_address, false),
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
let result = bank_client.send_and_confirm_instruction(&mint_keypair, instruction);
|
||||||
|
@ -993,6 +993,7 @@ mod tests {
|
|||||||
Rent::default(),
|
Rent::default(),
|
||||||
vec![],
|
vec![],
|
||||||
&[],
|
&[],
|
||||||
|
&[],
|
||||||
None,
|
None,
|
||||||
BpfComputeBudget {
|
BpfComputeBudget {
|
||||||
max_units: 1,
|
max_units: 1,
|
||||||
|
@ -1389,18 +1389,19 @@ fn call<'a>(
|
|||||||
.ok_or(SyscallError::InstructionError(
|
.ok_or(SyscallError::InstructionError(
|
||||||
InstructionError::MissingAccount,
|
InstructionError::MissingAccount,
|
||||||
))?;
|
))?;
|
||||||
if !program_account.executable {
|
if !program_account.borrow().executable {
|
||||||
return Err(SyscallError::InstructionError(InstructionError::AccountNotExecutable).into());
|
return Err(SyscallError::InstructionError(InstructionError::AccountNotExecutable).into());
|
||||||
}
|
}
|
||||||
let programdata_executable = if program_account.owner == bpf_loader_upgradeable::id() {
|
let programdata_executable = if program_account.borrow().owner == bpf_loader_upgradeable::id() {
|
||||||
if let UpgradeableLoaderState::Program {
|
if let UpgradeableLoaderState::Program {
|
||||||
programdata_address,
|
programdata_address,
|
||||||
} = program_account
|
} = program_account
|
||||||
|
.borrow()
|
||||||
.state()
|
.state()
|
||||||
.map_err(SyscallError::InstructionError)?
|
.map_err(SyscallError::InstructionError)?
|
||||||
{
|
{
|
||||||
if let Some(account) = invoke_context.get_account(&programdata_address) {
|
if let Some(account) = invoke_context.get_account(&programdata_address) {
|
||||||
Some((programdata_address, RefCell::new(account)))
|
Some((programdata_address, account))
|
||||||
} else {
|
} else {
|
||||||
return Err(
|
return Err(
|
||||||
SyscallError::InstructionError(InstructionError::MissingAccount).into(),
|
SyscallError::InstructionError(InstructionError::MissingAccount).into(),
|
||||||
@ -1412,7 +1413,7 @@ fn call<'a>(
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let mut executable_accounts = vec![(callee_program_id, RefCell::new(program_account))];
|
let mut executable_accounts = vec![(callee_program_id, program_account)];
|
||||||
if let Some(programdata) = programdata_executable {
|
if let Some(programdata) = programdata_executable {
|
||||||
executable_accounts.push(programdata);
|
executable_accounts.push(programdata);
|
||||||
}
|
}
|
||||||
|
@ -61,11 +61,17 @@ pub struct Accounts {
|
|||||||
|
|
||||||
// for the load instructions
|
// for the load instructions
|
||||||
pub type TransactionAccounts = Vec<Account>;
|
pub type TransactionAccounts = Vec<Account>;
|
||||||
|
pub type TransactionAccountDeps = Vec<(Pubkey, Account)>;
|
||||||
pub type TransactionRent = u64;
|
pub type TransactionRent = u64;
|
||||||
pub type TransactionLoaders = Vec<Vec<(Pubkey, Account)>>;
|
pub type TransactionLoaders = Vec<Vec<(Pubkey, Account)>>;
|
||||||
|
|
||||||
pub type TransactionLoadResult = (
|
pub type TransactionLoadResult = (
|
||||||
Result<(TransactionAccounts, TransactionLoaders, TransactionRent)>,
|
Result<(
|
||||||
|
TransactionAccounts,
|
||||||
|
TransactionAccountDeps,
|
||||||
|
TransactionLoaders,
|
||||||
|
TransactionRent,
|
||||||
|
)>,
|
||||||
Option<NonceRollbackFull>,
|
Option<NonceRollbackFull>,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -137,7 +143,7 @@ impl Accounts {
|
|||||||
error_counters: &mut ErrorCounters,
|
error_counters: &mut ErrorCounters,
|
||||||
rent_collector: &RentCollector,
|
rent_collector: &RentCollector,
|
||||||
feature_set: &FeatureSet,
|
feature_set: &FeatureSet,
|
||||||
) -> Result<(TransactionAccounts, TransactionRent)> {
|
) -> Result<(TransactionAccounts, TransactionAccountDeps, TransactionRent)> {
|
||||||
// Copy all the accounts
|
// Copy all the accounts
|
||||||
let message = tx.message();
|
let message = tx.message();
|
||||||
if tx.signatures.is_empty() && fee != 0 {
|
if tx.signatures.is_empty() && fee != 0 {
|
||||||
@ -148,6 +154,7 @@ impl Accounts {
|
|||||||
let mut payer_index = None;
|
let mut payer_index = None;
|
||||||
let mut tx_rent: TransactionRent = 0;
|
let mut tx_rent: TransactionRent = 0;
|
||||||
let mut accounts = Vec::with_capacity(message.account_keys.len());
|
let mut accounts = Vec::with_capacity(message.account_keys.len());
|
||||||
|
let mut account_deps = Vec::with_capacity(message.account_keys.len());
|
||||||
let rent_fix_enabled = feature_set.cumulative_rent_related_fixes_enabled();
|
let rent_fix_enabled = feature_set.cumulative_rent_related_fixes_enabled();
|
||||||
|
|
||||||
for (i, key) in message.account_keys.iter().enumerate() {
|
for (i, key) in message.account_keys.iter().enumerate() {
|
||||||
@ -181,6 +188,28 @@ impl Accounts {
|
|||||||
})
|
})
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
if account.executable && bpf_loader_upgradeable::check_id(&account.owner) {
|
||||||
|
// The upgradeable loader requires the derived ProgramData account
|
||||||
|
if let Ok(UpgradeableLoaderState::Program {
|
||||||
|
programdata_address,
|
||||||
|
}) = account.state()
|
||||||
|
{
|
||||||
|
if let Some(account) = self
|
||||||
|
.accounts_db
|
||||||
|
.load(ancestors, &programdata_address)
|
||||||
|
.map(|(account, _)| account)
|
||||||
|
{
|
||||||
|
account_deps.push((programdata_address, account));
|
||||||
|
} else {
|
||||||
|
error_counters.account_not_found += 1;
|
||||||
|
return Err(TransactionError::ProgramAccountNotFound);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error_counters.invalid_program_for_execution += 1;
|
||||||
|
return Err(TransactionError::InvalidProgramForExecution);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tx_rent += rent;
|
tx_rent += rent;
|
||||||
account
|
account
|
||||||
}
|
}
|
||||||
@ -216,7 +245,7 @@ impl Accounts {
|
|||||||
Err(TransactionError::InsufficientFundsForFee)
|
Err(TransactionError::InsufficientFundsForFee)
|
||||||
} else {
|
} else {
|
||||||
accounts[payer_index].lamports -= fee;
|
accounts[payer_index].lamports -= fee;
|
||||||
Ok((accounts, tx_rent))
|
Ok((accounts, account_deps, tx_rent))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -357,8 +386,8 @@ impl Accounts {
|
|||||||
rent_collector,
|
rent_collector,
|
||||||
feature_set,
|
feature_set,
|
||||||
);
|
);
|
||||||
let (accounts, rents) = match load_res {
|
let (accounts, account_deps, rents) = match load_res {
|
||||||
Ok((a, r)) => (a, r),
|
Ok((a, d, r)) => (a, d, r),
|
||||||
Err(e) => return (Err(e), None),
|
Err(e) => return (Err(e), None),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -382,7 +411,7 @@ impl Accounts {
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
(Ok((accounts, loaders, rents)), nonce_rollback)
|
(Ok((accounts, account_deps, loaders, rents)), nonce_rollback)
|
||||||
}
|
}
|
||||||
(_, (Err(e), _nonce_rollback)) => (Err(e), None),
|
(_, (Err(e), _nonce_rollback)) => (Err(e), None),
|
||||||
})
|
})
|
||||||
@ -885,7 +914,7 @@ impl Accounts {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if account.rent_epoch == 0 {
|
if account.rent_epoch == 0 {
|
||||||
acc.2 += rent_collector.collect_from_created_account(
|
acc.3 += rent_collector.collect_from_created_account(
|
||||||
&key,
|
&key,
|
||||||
account,
|
account,
|
||||||
rent_fix_enabled,
|
rent_fix_enabled,
|
||||||
@ -1226,7 +1255,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(loaded_accounts.len(), 1);
|
assert_eq!(loaded_accounts.len(), 1);
|
||||||
let (load_res, _nonce_rollback) = &loaded_accounts[0];
|
let (load_res, _nonce_rollback) = &loaded_accounts[0];
|
||||||
let (tx_accounts, _loaders, _rents) = load_res.as_ref().unwrap();
|
let (tx_accounts, _account_deps, _loaders, _rents) = load_res.as_ref().unwrap();
|
||||||
assert_eq!(tx_accounts[0].lamports, min_balance);
|
assert_eq!(tx_accounts[0].lamports, min_balance);
|
||||||
|
|
||||||
// Fee leaves zero balance fails
|
// Fee leaves zero balance fails
|
||||||
@ -1288,7 +1317,12 @@ mod tests {
|
|||||||
assert_eq!(loaded_accounts.len(), 1);
|
assert_eq!(loaded_accounts.len(), 1);
|
||||||
match &loaded_accounts[0] {
|
match &loaded_accounts[0] {
|
||||||
(
|
(
|
||||||
Ok((transaction_accounts, transaction_loaders, _transaction_rents)),
|
Ok((
|
||||||
|
transaction_accounts,
|
||||||
|
_transaction_account_deps,
|
||||||
|
transaction_loaders,
|
||||||
|
_transaction_rents,
|
||||||
|
)),
|
||||||
_nonce_rollback,
|
_nonce_rollback,
|
||||||
) => {
|
) => {
|
||||||
assert_eq!(transaction_accounts.len(), 3);
|
assert_eq!(transaction_accounts.len(), 3);
|
||||||
@ -1514,7 +1548,12 @@ mod tests {
|
|||||||
assert_eq!(loaded_accounts.len(), 1);
|
assert_eq!(loaded_accounts.len(), 1);
|
||||||
match &loaded_accounts[0] {
|
match &loaded_accounts[0] {
|
||||||
(
|
(
|
||||||
Ok((transaction_accounts, transaction_loaders, _transaction_rents)),
|
Ok((
|
||||||
|
transaction_accounts,
|
||||||
|
_transaction_account_deps,
|
||||||
|
transaction_loaders,
|
||||||
|
_transaction_rents,
|
||||||
|
)),
|
||||||
_nonce_rollback,
|
_nonce_rollback,
|
||||||
) => {
|
) => {
|
||||||
assert_eq!(transaction_accounts.len(), 3);
|
assert_eq!(transaction_accounts.len(), 3);
|
||||||
@ -1811,6 +1850,7 @@ mod tests {
|
|||||||
let loaded0 = (
|
let loaded0 = (
|
||||||
Ok((
|
Ok((
|
||||||
transaction_accounts0,
|
transaction_accounts0,
|
||||||
|
vec![],
|
||||||
transaction_loaders0,
|
transaction_loaders0,
|
||||||
transaction_rent0,
|
transaction_rent0,
|
||||||
)),
|
)),
|
||||||
@ -1823,6 +1863,7 @@ mod tests {
|
|||||||
let loaded1 = (
|
let loaded1 = (
|
||||||
Ok((
|
Ok((
|
||||||
transaction_accounts1,
|
transaction_accounts1,
|
||||||
|
vec![],
|
||||||
transaction_loaders1,
|
transaction_loaders1,
|
||||||
transaction_rent1,
|
transaction_rent1,
|
||||||
)),
|
)),
|
||||||
@ -2193,7 +2234,12 @@ mod tests {
|
|||||||
let transaction_loaders = vec![];
|
let transaction_loaders = vec![];
|
||||||
let transaction_rent = 0;
|
let transaction_rent = 0;
|
||||||
let loaded = (
|
let loaded = (
|
||||||
Ok((transaction_accounts, transaction_loaders, transaction_rent)),
|
Ok((
|
||||||
|
transaction_accounts,
|
||||||
|
vec![],
|
||||||
|
transaction_loaders,
|
||||||
|
transaction_rent,
|
||||||
|
)),
|
||||||
nonce_rollback,
|
nonce_rollback,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -2298,7 +2344,12 @@ mod tests {
|
|||||||
let transaction_loaders = vec![];
|
let transaction_loaders = vec![];
|
||||||
let transaction_rent = 0;
|
let transaction_rent = 0;
|
||||||
let loaded = (
|
let loaded = (
|
||||||
Ok((transaction_accounts, transaction_loaders, transaction_rent)),
|
Ok((
|
||||||
|
transaction_accounts,
|
||||||
|
vec![],
|
||||||
|
transaction_loaders,
|
||||||
|
transaction_rent,
|
||||||
|
)),
|
||||||
nonce_rollback,
|
nonce_rollback,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
//! already been signed and verified.
|
//! already been signed and verified.
|
||||||
use crate::{
|
use crate::{
|
||||||
accounts::{
|
accounts::{
|
||||||
AccountAddressFilter, Accounts, TransactionAccounts, TransactionLoadResult,
|
AccountAddressFilter, Accounts, TransactionAccountDeps, TransactionAccounts,
|
||||||
TransactionLoaders,
|
TransactionLoadResult, TransactionLoaders,
|
||||||
},
|
},
|
||||||
accounts_db::{ErrorCounters, SnapshotStorages},
|
accounts_db::{ErrorCounters, SnapshotStorages},
|
||||||
accounts_index::Ancestors,
|
accounts_index::Ancestors,
|
||||||
@ -117,6 +117,7 @@ type BankStatusCache = StatusCache<Result<()>>;
|
|||||||
#[frozen_abi(digest = "GSPuprru1pomsgvopKG7XRWiXdqdXJdLPkgJ2arPbkXM")]
|
#[frozen_abi(digest = "GSPuprru1pomsgvopKG7XRWiXdqdXJdLPkgJ2arPbkXM")]
|
||||||
pub type BankSlotDelta = SlotDelta<Result<()>>;
|
pub type BankSlotDelta = SlotDelta<Result<()>>;
|
||||||
type TransactionAccountRefCells = Vec<Rc<RefCell<Account>>>;
|
type TransactionAccountRefCells = Vec<Rc<RefCell<Account>>>;
|
||||||
|
type TransactionAccountDepRefCells = Vec<(Pubkey, RefCell<Account>)>;
|
||||||
type TransactionLoaderRefCells = Vec<Vec<(Pubkey, RefCell<Account>)>>;
|
type TransactionLoaderRefCells = Vec<Vec<(Pubkey, RefCell<Account>)>>;
|
||||||
|
|
||||||
// Eager rent collection repeats in cyclic manner.
|
// Eager rent collection repeats in cyclic manner.
|
||||||
@ -2699,12 +2700,21 @@ impl Bank {
|
|||||||
/// ownership by draining the source
|
/// ownership by draining the source
|
||||||
fn accounts_to_refcells(
|
fn accounts_to_refcells(
|
||||||
accounts: &mut TransactionAccounts,
|
accounts: &mut TransactionAccounts,
|
||||||
|
account_deps: &mut TransactionAccountDeps,
|
||||||
loaders: &mut TransactionLoaders,
|
loaders: &mut TransactionLoaders,
|
||||||
) -> (TransactionAccountRefCells, TransactionLoaderRefCells) {
|
) -> (
|
||||||
|
TransactionAccountRefCells,
|
||||||
|
TransactionAccountDepRefCells,
|
||||||
|
TransactionLoaderRefCells,
|
||||||
|
) {
|
||||||
let account_refcells: Vec<_> = accounts
|
let account_refcells: Vec<_> = accounts
|
||||||
.drain(..)
|
.drain(..)
|
||||||
.map(|account| Rc::new(RefCell::new(account)))
|
.map(|account| Rc::new(RefCell::new(account)))
|
||||||
.collect();
|
.collect();
|
||||||
|
let account_dep_refcells: Vec<_> = account_deps
|
||||||
|
.drain(..)
|
||||||
|
.map(|(pubkey, account_dep)| (pubkey, RefCell::new(account_dep)))
|
||||||
|
.collect();
|
||||||
let loader_refcells: Vec<Vec<_>> = loaders
|
let loader_refcells: Vec<Vec<_>> = loaders
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.map(|v| {
|
.map(|v| {
|
||||||
@ -2713,7 +2723,7 @@ impl Bank {
|
|||||||
.collect()
|
.collect()
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
(account_refcells, loader_refcells)
|
(account_refcells, account_dep_refcells, loader_refcells)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts back from RefCell<Account> to Account, this involves moving
|
/// Converts back from RefCell<Account> to Account, this involves moving
|
||||||
@ -2865,13 +2875,13 @@ impl Bank {
|
|||||||
.zip(OrderedIterator::new(txs, batch.iteration_order()))
|
.zip(OrderedIterator::new(txs, batch.iteration_order()))
|
||||||
.map(|(accs, (_, tx))| match accs {
|
.map(|(accs, (_, tx))| match accs {
|
||||||
(Err(e), _nonce_rollback) => (Err(e.clone()), None),
|
(Err(e), _nonce_rollback) => (Err(e.clone()), None),
|
||||||
(Ok((accounts, loaders, _rents)), nonce_rollback) => {
|
(Ok((accounts, account_deps, loaders, _rents)), nonce_rollback) => {
|
||||||
signature_count += u64::from(tx.message().header.num_required_signatures);
|
signature_count += u64::from(tx.message().header.num_required_signatures);
|
||||||
|
|
||||||
let executors = self.get_executors(&tx.message, &loaders);
|
let executors = self.get_executors(&tx.message, &loaders);
|
||||||
|
|
||||||
let (account_refcells, loader_refcells) =
|
let (account_refcells, account_dep_refcells, loader_refcells) =
|
||||||
Self::accounts_to_refcells(accounts, loaders);
|
Self::accounts_to_refcells(accounts, account_deps, loaders);
|
||||||
|
|
||||||
let instruction_recorders = if enable_cpi_recording {
|
let instruction_recorders = if enable_cpi_recording {
|
||||||
let ix_count = tx.message.instructions.len();
|
let ix_count = tx.message.instructions.len();
|
||||||
@ -2892,6 +2902,7 @@ impl Bank {
|
|||||||
tx.message(),
|
tx.message(),
|
||||||
&loader_refcells,
|
&loader_refcells,
|
||||||
&account_refcells,
|
&account_refcells,
|
||||||
|
&account_dep_refcells,
|
||||||
&self.rent_collector,
|
&self.rent_collector,
|
||||||
log_collector.clone(),
|
log_collector.clone(),
|
||||||
executors.clone(),
|
executors.clone(),
|
||||||
@ -3308,7 +3319,7 @@ impl Bank {
|
|||||||
|
|
||||||
let acc = raccs.as_ref().unwrap();
|
let acc = raccs.as_ref().unwrap();
|
||||||
|
|
||||||
collected_rent += acc.2;
|
collected_rent += acc.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.collected_rent.fetch_add(collected_rent, Relaxed);
|
self.collected_rent.fetch_add(collected_rent, Relaxed);
|
||||||
|
@ -207,6 +207,7 @@ pub struct ThisInvokeContext<'a> {
|
|||||||
program_ids: Vec<Pubkey>,
|
program_ids: Vec<Pubkey>,
|
||||||
rent: Rent,
|
rent: Rent,
|
||||||
pre_accounts: Vec<PreAccount>,
|
pre_accounts: Vec<PreAccount>,
|
||||||
|
account_deps: &'a [(Pubkey, RefCell<Account>)],
|
||||||
programs: &'a [(Pubkey, ProcessInstructionWithContext)],
|
programs: &'a [(Pubkey, ProcessInstructionWithContext)],
|
||||||
logger: Rc<RefCell<dyn Logger>>,
|
logger: Rc<RefCell<dyn Logger>>,
|
||||||
bpf_compute_budget: BpfComputeBudget,
|
bpf_compute_budget: BpfComputeBudget,
|
||||||
@ -216,10 +217,12 @@ pub struct ThisInvokeContext<'a> {
|
|||||||
feature_set: Arc<FeatureSet>,
|
feature_set: Arc<FeatureSet>,
|
||||||
}
|
}
|
||||||
impl<'a> ThisInvokeContext<'a> {
|
impl<'a> ThisInvokeContext<'a> {
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
program_id: &Pubkey,
|
program_id: &Pubkey,
|
||||||
rent: Rent,
|
rent: Rent,
|
||||||
pre_accounts: Vec<PreAccount>,
|
pre_accounts: Vec<PreAccount>,
|
||||||
|
account_deps: &'a [(Pubkey, RefCell<Account>)],
|
||||||
programs: &'a [(Pubkey, ProcessInstructionWithContext)],
|
programs: &'a [(Pubkey, ProcessInstructionWithContext)],
|
||||||
log_collector: Option<Rc<LogCollector>>,
|
log_collector: Option<Rc<LogCollector>>,
|
||||||
bpf_compute_budget: BpfComputeBudget,
|
bpf_compute_budget: BpfComputeBudget,
|
||||||
@ -233,6 +236,7 @@ impl<'a> ThisInvokeContext<'a> {
|
|||||||
program_ids,
|
program_ids,
|
||||||
rent,
|
rent,
|
||||||
pre_accounts,
|
pre_accounts,
|
||||||
|
account_deps,
|
||||||
programs,
|
programs,
|
||||||
logger: Rc::new(RefCell::new(ThisLogger { log_collector })),
|
logger: Rc::new(RefCell::new(ThisLogger { log_collector })),
|
||||||
bpf_compute_budget,
|
bpf_compute_budget,
|
||||||
@ -312,16 +316,25 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> {
|
|||||||
fn is_feature_active(&self, feature_id: &Pubkey) -> bool {
|
fn is_feature_active(&self, feature_id: &Pubkey) -> bool {
|
||||||
self.feature_set.is_active(feature_id)
|
self.feature_set.is_active(feature_id)
|
||||||
}
|
}
|
||||||
fn get_account(&self, pubkey: &Pubkey) -> Option<Account> {
|
fn get_account(&self, pubkey: &Pubkey) -> Option<RefCell<Account>> {
|
||||||
|
if let Some(account) = self.account_deps.iter().find_map(|(key, account)| {
|
||||||
|
if key == pubkey {
|
||||||
|
Some(account.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
return Some(account);
|
||||||
|
}
|
||||||
self.pre_accounts.iter().find_map(|pre| {
|
self.pre_accounts.iter().find_map(|pre| {
|
||||||
if pre.key == *pubkey {
|
if pre.key == *pubkey {
|
||||||
Some(Account {
|
Some(RefCell::new(Account {
|
||||||
lamports: pre.lamports,
|
lamports: pre.lamports,
|
||||||
data: pre.data.clone(),
|
data: pre.data.clone(),
|
||||||
owner: pre.owner,
|
owner: pre.owner,
|
||||||
executable: pre.is_executable,
|
executable: pre.is_executable,
|
||||||
rent_epoch: pre.rent_epoch,
|
rent_epoch: pre.rent_epoch,
|
||||||
})
|
}))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -641,16 +654,17 @@ impl MessageProcessor {
|
|||||||
let program_account = invoke_context
|
let program_account = invoke_context
|
||||||
.get_account(&callee_program_id)
|
.get_account(&callee_program_id)
|
||||||
.ok_or(InstructionError::MissingAccount)?;
|
.ok_or(InstructionError::MissingAccount)?;
|
||||||
if !program_account.executable {
|
if !program_account.borrow().executable {
|
||||||
return Err(InstructionError::AccountNotExecutable);
|
return Err(InstructionError::AccountNotExecutable);
|
||||||
}
|
}
|
||||||
let programdata_executable = if program_account.owner == bpf_loader_upgradeable::id() {
|
let programdata_executable =
|
||||||
|
if program_account.borrow().owner == bpf_loader_upgradeable::id() {
|
||||||
if let UpgradeableLoaderState::Program {
|
if let UpgradeableLoaderState::Program {
|
||||||
programdata_address,
|
programdata_address,
|
||||||
} = program_account.state()?
|
} = program_account.borrow().state()?
|
||||||
{
|
{
|
||||||
if let Some(account) = invoke_context.get_account(&programdata_address) {
|
if let Some(account) = invoke_context.get_account(&programdata_address) {
|
||||||
Some((programdata_address, RefCell::new(account)))
|
Some((programdata_address, account))
|
||||||
} else {
|
} else {
|
||||||
return Err(InstructionError::MissingAccount);
|
return Err(InstructionError::MissingAccount);
|
||||||
}
|
}
|
||||||
@ -660,7 +674,7 @@ impl MessageProcessor {
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let mut executable_accounts = vec![(callee_program_id, RefCell::new(program_account))];
|
let mut executable_accounts = vec![(callee_program_id, program_account)];
|
||||||
if let Some(programdata) = programdata_executable {
|
if let Some(programdata) = programdata_executable {
|
||||||
executable_accounts.push(programdata);
|
executable_accounts.push(programdata);
|
||||||
}
|
}
|
||||||
@ -859,6 +873,7 @@ impl MessageProcessor {
|
|||||||
instruction: &CompiledInstruction,
|
instruction: &CompiledInstruction,
|
||||||
executable_accounts: &[(Pubkey, RefCell<Account>)],
|
executable_accounts: &[(Pubkey, RefCell<Account>)],
|
||||||
accounts: &[Rc<RefCell<Account>>],
|
accounts: &[Rc<RefCell<Account>>],
|
||||||
|
account_deps: &[(Pubkey, RefCell<Account>)],
|
||||||
rent_collector: &RentCollector,
|
rent_collector: &RentCollector,
|
||||||
log_collector: Option<Rc<LogCollector>>,
|
log_collector: Option<Rc<LogCollector>>,
|
||||||
executors: Rc<RefCell<Executors>>,
|
executors: Rc<RefCell<Executors>>,
|
||||||
@ -887,6 +902,7 @@ impl MessageProcessor {
|
|||||||
instruction.program_id(&message.account_keys),
|
instruction.program_id(&message.account_keys),
|
||||||
rent_collector.rent,
|
rent_collector.rent,
|
||||||
pre_accounts,
|
pre_accounts,
|
||||||
|
account_deps,
|
||||||
&self.programs,
|
&self.programs,
|
||||||
log_collector,
|
log_collector,
|
||||||
bpf_compute_budget,
|
bpf_compute_budget,
|
||||||
@ -917,6 +933,7 @@ impl MessageProcessor {
|
|||||||
message: &Message,
|
message: &Message,
|
||||||
loaders: &[Vec<(Pubkey, RefCell<Account>)>],
|
loaders: &[Vec<(Pubkey, RefCell<Account>)>],
|
||||||
accounts: &[Rc<RefCell<Account>>],
|
accounts: &[Rc<RefCell<Account>>],
|
||||||
|
account_deps: &[(Pubkey, RefCell<Account>)],
|
||||||
rent_collector: &RentCollector,
|
rent_collector: &RentCollector,
|
||||||
log_collector: Option<Rc<LogCollector>>,
|
log_collector: Option<Rc<LogCollector>>,
|
||||||
executors: Rc<RefCell<Executors>>,
|
executors: Rc<RefCell<Executors>>,
|
||||||
@ -933,6 +950,7 @@ impl MessageProcessor {
|
|||||||
instruction,
|
instruction,
|
||||||
&loaders[instruction_index],
|
&loaders[instruction_index],
|
||||||
accounts,
|
accounts,
|
||||||
|
account_deps,
|
||||||
rent_collector,
|
rent_collector,
|
||||||
log_collector.clone(),
|
log_collector.clone(),
|
||||||
executors.clone(),
|
executors.clone(),
|
||||||
@ -988,6 +1006,7 @@ mod tests {
|
|||||||
Rent::default(),
|
Rent::default(),
|
||||||
pre_accounts,
|
pre_accounts,
|
||||||
&[],
|
&[],
|
||||||
|
&[],
|
||||||
None,
|
None,
|
||||||
BpfComputeBudget::default(),
|
BpfComputeBudget::default(),
|
||||||
Rc::new(RefCell::new(Executors::default())),
|
Rc::new(RefCell::new(Executors::default())),
|
||||||
@ -1540,6 +1559,7 @@ mod tests {
|
|||||||
&message,
|
&message,
|
||||||
&loaders,
|
&loaders,
|
||||||
&accounts,
|
&accounts,
|
||||||
|
&[],
|
||||||
&rent_collector,
|
&rent_collector,
|
||||||
None,
|
None,
|
||||||
executors.clone(),
|
executors.clone(),
|
||||||
@ -1564,6 +1584,7 @@ mod tests {
|
|||||||
&message,
|
&message,
|
||||||
&loaders,
|
&loaders,
|
||||||
&accounts,
|
&accounts,
|
||||||
|
&[],
|
||||||
&rent_collector,
|
&rent_collector,
|
||||||
None,
|
None,
|
||||||
executors.clone(),
|
executors.clone(),
|
||||||
@ -1592,6 +1613,7 @@ mod tests {
|
|||||||
&message,
|
&message,
|
||||||
&loaders,
|
&loaders,
|
||||||
&accounts,
|
&accounts,
|
||||||
|
&[],
|
||||||
&rent_collector,
|
&rent_collector,
|
||||||
None,
|
None,
|
||||||
executors,
|
executors,
|
||||||
@ -1704,6 +1726,7 @@ mod tests {
|
|||||||
&message,
|
&message,
|
||||||
&loaders,
|
&loaders,
|
||||||
&accounts,
|
&accounts,
|
||||||
|
&[],
|
||||||
&rent_collector,
|
&rent_collector,
|
||||||
None,
|
None,
|
||||||
executors.clone(),
|
executors.clone(),
|
||||||
@ -1732,6 +1755,7 @@ mod tests {
|
|||||||
&message,
|
&message,
|
||||||
&loaders,
|
&loaders,
|
||||||
&accounts,
|
&accounts,
|
||||||
|
&[],
|
||||||
&rent_collector,
|
&rent_collector,
|
||||||
None,
|
None,
|
||||||
executors.clone(),
|
executors.clone(),
|
||||||
@ -1757,6 +1781,7 @@ mod tests {
|
|||||||
&message,
|
&message,
|
||||||
&loaders,
|
&loaders,
|
||||||
&accounts,
|
&accounts,
|
||||||
|
&[],
|
||||||
&rent_collector,
|
&rent_collector,
|
||||||
None,
|
None,
|
||||||
executors,
|
executors,
|
||||||
@ -1842,6 +1867,7 @@ mod tests {
|
|||||||
not_owned_preaccount,
|
not_owned_preaccount,
|
||||||
executable_preaccount,
|
executable_preaccount,
|
||||||
],
|
],
|
||||||
|
&[],
|
||||||
programs.as_slice(),
|
programs.as_slice(),
|
||||||
None,
|
None,
|
||||||
BpfComputeBudget::default(),
|
BpfComputeBudget::default(),
|
||||||
|
@ -62,7 +62,7 @@ pub trait InvokeContext {
|
|||||||
/// Get the bank's active feature set
|
/// Get the bank's active feature set
|
||||||
fn is_feature_active(&self, feature_id: &Pubkey) -> bool;
|
fn is_feature_active(&self, feature_id: &Pubkey) -> bool;
|
||||||
/// Get an account from a pre-account
|
/// Get an account from a pre-account
|
||||||
fn get_account(&self, pubkey: &Pubkey) -> Option<Account>;
|
fn get_account(&self, pubkey: &Pubkey) -> Option<RefCell<Account>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, AbiExample)]
|
#[derive(Clone, Copy, Debug, AbiExample)]
|
||||||
@ -342,7 +342,7 @@ impl InvokeContext for MockInvokeContext {
|
|||||||
fn is_feature_active(&self, _feature_id: &Pubkey) -> bool {
|
fn is_feature_active(&self, _feature_id: &Pubkey) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
fn get_account(&self, _pubkey: &Pubkey) -> Option<Account> {
|
fn get_account(&self, _pubkey: &Pubkey) -> Option<RefCell<Account>> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user