Prevent the invoke and upgrade of programs in the same tx batch (#14653)
* Prevent the invoke and upgrade of programs in the same tx batch * Pass program address as writable in the upgrade instruction
This commit is contained in:
parent
4964b0fe61
commit
e3bd9e5300
File diff suppressed because it is too large
Load Diff
|
@ -22,14 +22,18 @@ walkdir = "2"
|
|||
bincode = "1.1.4"
|
||||
byteorder = "1.3.2"
|
||||
elf = "0.0.10"
|
||||
itertools = "0.10.0"
|
||||
miow = "0.2.2"
|
||||
net2 = "0.2.37"
|
||||
solana-bpf-loader-program = { path = "../bpf_loader", version = "1.6.0" }
|
||||
solana-cli-output = { path = "../../cli-output", version = "1.6.0" }
|
||||
solana-logger = { path = "../../logger", version = "1.6.0" }
|
||||
solana-measure = { path = "../../measure", version = "1.6.0" }
|
||||
solana_rbpf = "=0.2.3"
|
||||
solana-runtime = { path = "../../runtime", version = "1.6.0" }
|
||||
solana-sdk = { path = "../../sdk", version = "1.6.0" }
|
||||
solana_rbpf = "=0.2.3"
|
||||
solana-transaction-status = { path = "../../transaction-status", version = "1.6.0" }
|
||||
|
||||
|
||||
[[bench]]
|
||||
name = "bpf_loader"
|
||||
|
|
|
@ -3,15 +3,17 @@
|
|||
#[macro_use]
|
||||
extern crate solana_bpf_loader_program;
|
||||
|
||||
use itertools::izip;
|
||||
use solana_bpf_loader_program::{
|
||||
create_vm,
|
||||
serialization::{deserialize_parameters, serialize_parameters},
|
||||
syscalls::register_syscalls,
|
||||
ThisInstructionMeter,
|
||||
};
|
||||
use solana_cli_output::display::println_transaction;
|
||||
use solana_rbpf::vm::{Config, Executable, Tracer};
|
||||
use solana_runtime::{
|
||||
bank::{Bank, ExecuteTimings},
|
||||
bank::{Bank, ExecuteTimings, NonceRollbackInfo, TransactionBalancesSet, TransactionResults},
|
||||
bank_client::BankClient,
|
||||
genesis_utils::{create_genesis_config, GenesisConfigInfo},
|
||||
loader_utils::{
|
||||
|
@ -30,11 +32,16 @@ use solana_sdk::{
|
|||
message::Message,
|
||||
process_instruction::{InvokeContext, MockInvokeContext},
|
||||
pubkey::Pubkey,
|
||||
signature::{Keypair, Signer},
|
||||
signature::{keypair_from_seed, Keypair, Signer},
|
||||
system_instruction,
|
||||
sysvar::{clock, fees, rent, slot_hashes, stake_history},
|
||||
transaction::{Transaction, TransactionError},
|
||||
};
|
||||
use std::{cell::RefCell, env, fs::File, io::Read, path::PathBuf, sync::Arc};
|
||||
use solana_transaction_status::{
|
||||
token_balances::collect_token_balances, ConfirmedTransaction, InnerInstructions,
|
||||
TransactionStatusMeta, TransactionWithStatusMeta, UiTransactionEncoding,
|
||||
};
|
||||
use std::{cell::RefCell, collections::HashMap, env, fs::File, io::Read, path::PathBuf, sync::Arc};
|
||||
|
||||
/// BPF program file extension
|
||||
const PLATFORM_FILE_EXTENSION_BPF: &str = "so";
|
||||
|
@ -100,20 +107,31 @@ fn write_bpf_program(
|
|||
fn load_upgradeable_bpf_program(
|
||||
bank_client: &BankClient,
|
||||
payer_keypair: &Keypair,
|
||||
buffer_keypair: &Keypair,
|
||||
executable_keypair: &Keypair,
|
||||
authority_keypair: &Keypair,
|
||||
name: &str,
|
||||
) -> (Pubkey, Keypair) {
|
||||
) {
|
||||
let path = create_bpf_path(name);
|
||||
let mut file = File::open(&path).unwrap_or_else(|err| {
|
||||
panic!("Failed to open {}: {}", path.display(), err);
|
||||
});
|
||||
let mut elf = Vec::new();
|
||||
file.read_to_end(&mut elf).unwrap();
|
||||
load_upgradeable_program(bank_client, payer_keypair, elf)
|
||||
load_upgradeable_program(
|
||||
bank_client,
|
||||
payer_keypair,
|
||||
buffer_keypair,
|
||||
executable_keypair,
|
||||
authority_keypair,
|
||||
elf,
|
||||
);
|
||||
}
|
||||
|
||||
fn upgrade_bpf_program(
|
||||
bank_client: &BankClient,
|
||||
payer_keypair: &Keypair,
|
||||
buffer_keypair: &Keypair,
|
||||
executable_pubkey: &Pubkey,
|
||||
authority_keypair: &Keypair,
|
||||
name: &str,
|
||||
|
@ -124,15 +142,15 @@ fn upgrade_bpf_program(
|
|||
});
|
||||
let mut elf = Vec::new();
|
||||
file.read_to_end(&mut elf).unwrap();
|
||||
let buffer_pubkey = load_buffer_account(bank_client, payer_keypair, &elf);
|
||||
load_buffer_account(bank_client, payer_keypair, &buffer_keypair, &elf);
|
||||
upgrade_program(
|
||||
bank_client,
|
||||
payer_keypair,
|
||||
executable_pubkey,
|
||||
&buffer_pubkey,
|
||||
&buffer_keypair.pubkey(),
|
||||
&authority_keypair,
|
||||
&payer_keypair.pubkey(),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
fn run_program(
|
||||
|
@ -242,6 +260,108 @@ fn process_transaction_and_record_inner(
|
|||
)
|
||||
}
|
||||
|
||||
fn execute_transactions(bank: &Bank, txs: &[Transaction]) -> Vec<ConfirmedTransaction> {
|
||||
let batch = bank.prepare_batch(txs, None);
|
||||
let mut timings = ExecuteTimings::default();
|
||||
let mut mint_decimals = HashMap::new();
|
||||
let tx_pre_token_balances = collect_token_balances(&bank, &batch, &mut mint_decimals);
|
||||
let (
|
||||
TransactionResults {
|
||||
execution_results, ..
|
||||
},
|
||||
TransactionBalancesSet {
|
||||
pre_balances,
|
||||
post_balances,
|
||||
..
|
||||
},
|
||||
mut inner_instructions,
|
||||
mut transaction_logs,
|
||||
) = bank.load_execute_and_commit_transactions(
|
||||
&batch,
|
||||
std::usize::MAX,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
&mut timings,
|
||||
);
|
||||
let tx_post_token_balances = collect_token_balances(&bank, &batch, &mut mint_decimals);
|
||||
|
||||
for _ in 0..(txs.len() - transaction_logs.len()) {
|
||||
transaction_logs.push(vec![]);
|
||||
}
|
||||
for _ in 0..(txs.len() - inner_instructions.len()) {
|
||||
inner_instructions.push(None);
|
||||
}
|
||||
|
||||
izip!(
|
||||
txs.iter(),
|
||||
execution_results.into_iter(),
|
||||
inner_instructions.into_iter(),
|
||||
pre_balances.into_iter(),
|
||||
post_balances.into_iter(),
|
||||
tx_pre_token_balances.into_iter(),
|
||||
tx_post_token_balances.into_iter(),
|
||||
transaction_logs.into_iter(),
|
||||
)
|
||||
.map(
|
||||
|(
|
||||
tx,
|
||||
(execute_result, nonce_rollback),
|
||||
inner_instructions,
|
||||
pre_balances,
|
||||
post_balances,
|
||||
pre_token_balances,
|
||||
post_token_balances,
|
||||
log_messages,
|
||||
)| {
|
||||
let fee_calculator = nonce_rollback
|
||||
.map(|nonce_rollback| nonce_rollback.fee_calculator())
|
||||
.unwrap_or_else(|| bank.get_fee_calculator(&tx.message().recent_blockhash))
|
||||
.expect("FeeCalculator must exist");
|
||||
let fee = fee_calculator.calculate_fee(tx.message());
|
||||
|
||||
let inner_instructions = inner_instructions.map(|inner_instructions| {
|
||||
inner_instructions
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(index, instructions)| InnerInstructions {
|
||||
index: index as u8,
|
||||
instructions,
|
||||
})
|
||||
.filter(|i| !i.instructions.is_empty())
|
||||
.collect()
|
||||
});
|
||||
|
||||
let tx_status_meta = TransactionStatusMeta {
|
||||
status: execute_result,
|
||||
fee,
|
||||
pre_balances,
|
||||
post_balances,
|
||||
pre_token_balances: Some(pre_token_balances),
|
||||
post_token_balances: Some(post_token_balances),
|
||||
inner_instructions,
|
||||
log_messages: Some(log_messages),
|
||||
};
|
||||
|
||||
ConfirmedTransaction {
|
||||
slot: bank.slot(),
|
||||
transaction: TransactionWithStatusMeta {
|
||||
transaction: tx.clone(),
|
||||
meta: Some(tx_status_meta),
|
||||
},
|
||||
}
|
||||
},
|
||||
)
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn print_confirmed_tx(name: &str, confirmed_tx: ConfirmedTransaction) {
|
||||
let tx = confirmed_tx.transaction.transaction.clone();
|
||||
let encoded = confirmed_tx.encode(UiTransactionEncoding::JsonParsed);
|
||||
println!("EXECUTE {} (slot {})", name, encoded.slot);
|
||||
println_transaction(&tx, &encoded.transaction.meta, " ");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "bpf_c", feature = "bpf_rust"))]
|
||||
fn test_program_bpf_sanity() {
|
||||
|
@ -1572,8 +1692,18 @@ fn test_program_bpf_upgrade() {
|
|||
let bank_client = BankClient::new(bank);
|
||||
|
||||
// Deploy upgrade program
|
||||
let (program_id, authority_keypair) =
|
||||
load_upgradeable_bpf_program(&bank_client, &mint_keypair, "solana_bpf_rust_upgradeable");
|
||||
let buffer_keypair = Keypair::new();
|
||||
let program_keypair = Keypair::new();
|
||||
let program_id = program_keypair.pubkey();
|
||||
let authority_keypair = Keypair::new();
|
||||
load_upgradeable_bpf_program(
|
||||
&bank_client,
|
||||
&mint_keypair,
|
||||
&buffer_keypair,
|
||||
&program_keypair,
|
||||
&authority_keypair,
|
||||
"solana_bpf_rust_upgradeable",
|
||||
);
|
||||
|
||||
let mut instruction = Instruction::new(
|
||||
program_id,
|
||||
|
@ -1593,9 +1723,11 @@ fn test_program_bpf_upgrade() {
|
|||
);
|
||||
|
||||
// Upgrade program
|
||||
let buffer_keypair = Keypair::new();
|
||||
upgrade_bpf_program(
|
||||
&bank_client,
|
||||
&mint_keypair,
|
||||
&buffer_keypair,
|
||||
&program_id,
|
||||
&authority_keypair,
|
||||
"solana_bpf_rust_upgraded",
|
||||
|
@ -1620,9 +1752,11 @@ fn test_program_bpf_upgrade() {
|
|||
);
|
||||
|
||||
// Upgrade back to the original program
|
||||
let buffer_keypair = Keypair::new();
|
||||
upgrade_bpf_program(
|
||||
&bank_client,
|
||||
&mint_keypair,
|
||||
&buffer_keypair,
|
||||
&program_id,
|
||||
&new_authority_keypair,
|
||||
"solana_bpf_rust_upgradeable",
|
||||
|
@ -1661,8 +1795,18 @@ fn test_program_bpf_invoke_upgradeable_via_cpi() {
|
|||
);
|
||||
|
||||
// Deploy upgradeable program
|
||||
let (program_id, authority_keypair) =
|
||||
load_upgradeable_bpf_program(&bank_client, &mint_keypair, "solana_bpf_rust_upgradeable");
|
||||
let buffer_keypair = Keypair::new();
|
||||
let program_keypair = Keypair::new();
|
||||
let program_id = program_keypair.pubkey();
|
||||
let authority_keypair = Keypair::new();
|
||||
load_upgradeable_bpf_program(
|
||||
&bank_client,
|
||||
&mint_keypair,
|
||||
&buffer_keypair,
|
||||
&program_keypair,
|
||||
&authority_keypair,
|
||||
"solana_bpf_rust_upgradeable",
|
||||
);
|
||||
|
||||
let mut instruction = Instruction::new(
|
||||
invoke_and_return,
|
||||
|
@ -1684,9 +1828,11 @@ fn test_program_bpf_invoke_upgradeable_via_cpi() {
|
|||
);
|
||||
|
||||
// Upgrade program
|
||||
let buffer_keypair = Keypair::new();
|
||||
upgrade_bpf_program(
|
||||
&bank_client,
|
||||
&mint_keypair,
|
||||
&buffer_keypair,
|
||||
&program_id,
|
||||
&authority_keypair,
|
||||
"solana_bpf_rust_upgraded",
|
||||
|
@ -1711,9 +1857,11 @@ fn test_program_bpf_invoke_upgradeable_via_cpi() {
|
|||
);
|
||||
|
||||
// Upgrade back to the original program
|
||||
let buffer_keypair = Keypair::new();
|
||||
upgrade_bpf_program(
|
||||
&bank_client,
|
||||
&mint_keypair,
|
||||
&buffer_keypair,
|
||||
&program_id,
|
||||
&new_authority_keypair,
|
||||
"solana_bpf_rust_upgradeable",
|
||||
|
@ -1794,8 +1942,18 @@ fn test_program_bpf_upgrade_via_cpi() {
|
|||
);
|
||||
|
||||
// Deploy upgradeable program
|
||||
let (program_id, authority_keypair) =
|
||||
load_upgradeable_bpf_program(&bank_client, &mint_keypair, "solana_bpf_rust_upgradeable");
|
||||
let buffer_keypair = Keypair::new();
|
||||
let program_keypair = Keypair::new();
|
||||
let program_id = program_keypair.pubkey();
|
||||
let authority_keypair = Keypair::new();
|
||||
load_upgradeable_bpf_program(
|
||||
&bank_client,
|
||||
&mint_keypair,
|
||||
&buffer_keypair,
|
||||
&program_keypair,
|
||||
&authority_keypair,
|
||||
"solana_bpf_rust_upgradeable",
|
||||
);
|
||||
|
||||
let mut instruction = Instruction::new(
|
||||
invoke_and_return,
|
||||
|
@ -1823,12 +1981,13 @@ fn test_program_bpf_upgrade_via_cpi() {
|
|||
});
|
||||
let mut elf = Vec::new();
|
||||
file.read_to_end(&mut elf).unwrap();
|
||||
let buffer_pubkey = load_buffer_account(&bank_client, &mint_keypair, &elf);
|
||||
let buffer_keypair = Keypair::new();
|
||||
load_buffer_account(&bank_client, &mint_keypair, &buffer_keypair, &elf);
|
||||
|
||||
// Upgrade program via CPI
|
||||
let mut upgrade_instruction = bpf_loader_upgradeable::upgrade(
|
||||
&program_id,
|
||||
&buffer_pubkey,
|
||||
&buffer_keypair.pubkey(),
|
||||
&authority_keypair.pubkey(),
|
||||
&mint_keypair.pubkey(),
|
||||
);
|
||||
|
@ -1849,3 +2008,137 @@ fn test_program_bpf_upgrade_via_cpi() {
|
|||
TransactionError::InstructionError(0, InstructionError::Custom(43))
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "bpf_rust")]
|
||||
#[test]
|
||||
fn test_program_upgradeable_locks() {
|
||||
fn setup_program_upgradeable_locks(
|
||||
payer_keypair: &Keypair,
|
||||
buffer_keypair: &Keypair,
|
||||
program_keypair: &Keypair,
|
||||
) -> (Arc<Bank>, Transaction, Transaction) {
|
||||
solana_logger::setup();
|
||||
|
||||
let GenesisConfigInfo {
|
||||
genesis_config,
|
||||
mint_keypair,
|
||||
..
|
||||
} = create_genesis_config(2_000_000_000);
|
||||
let mut bank = Bank::new(&genesis_config);
|
||||
let (name, id, entrypoint) = solana_bpf_loader_upgradeable_program!();
|
||||
bank.add_builtin(&name, id, entrypoint);
|
||||
let bank = Arc::new(bank);
|
||||
let bank_client = BankClient::new_shared(&bank);
|
||||
|
||||
load_upgradeable_bpf_program(
|
||||
&bank_client,
|
||||
&mint_keypair,
|
||||
buffer_keypair,
|
||||
program_keypair,
|
||||
payer_keypair,
|
||||
"solana_bpf_rust_panic",
|
||||
);
|
||||
|
||||
// Load the buffer account
|
||||
let path = create_bpf_path("solana_bpf_rust_noop");
|
||||
let mut file = File::open(&path).unwrap_or_else(|err| {
|
||||
panic!("Failed to open {}: {}", path.display(), err);
|
||||
});
|
||||
let mut elf = Vec::new();
|
||||
file.read_to_end(&mut elf).unwrap();
|
||||
load_buffer_account(&bank_client, &mint_keypair, buffer_keypair, &elf);
|
||||
|
||||
bank_client
|
||||
.send_and_confirm_instruction(
|
||||
&mint_keypair,
|
||||
system_instruction::transfer(
|
||||
&mint_keypair.pubkey(),
|
||||
&payer_keypair.pubkey(),
|
||||
1_000_000_000,
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let invoke_tx = Transaction::new(
|
||||
&[payer_keypair],
|
||||
Message::new(
|
||||
&[Instruction::new(
|
||||
program_keypair.pubkey(),
|
||||
&[0u8; 0],
|
||||
vec![],
|
||||
)],
|
||||
Some(&payer_keypair.pubkey()),
|
||||
),
|
||||
bank.last_blockhash(),
|
||||
);
|
||||
let upgrade_tx = Transaction::new(
|
||||
&[payer_keypair],
|
||||
Message::new(
|
||||
&[bpf_loader_upgradeable::upgrade(
|
||||
&program_keypair.pubkey(),
|
||||
&buffer_keypair.pubkey(),
|
||||
&payer_keypair.pubkey(),
|
||||
&payer_keypair.pubkey(),
|
||||
)],
|
||||
Some(&payer_keypair.pubkey()),
|
||||
),
|
||||
bank.last_blockhash(),
|
||||
);
|
||||
|
||||
(bank, invoke_tx, upgrade_tx)
|
||||
}
|
||||
|
||||
let payer_keypair = keypair_from_seed(&[56u8; 32]).unwrap();
|
||||
let buffer_keypair = keypair_from_seed(&[11; 32]).unwrap();
|
||||
let program_keypair = keypair_from_seed(&[77u8; 32]).unwrap();
|
||||
|
||||
let results1 = {
|
||||
let (bank, invoke_tx, upgrade_tx) =
|
||||
setup_program_upgradeable_locks(&payer_keypair, &buffer_keypair, &program_keypair);
|
||||
execute_transactions(&bank, &[upgrade_tx, invoke_tx])
|
||||
};
|
||||
|
||||
let results2 = {
|
||||
let (bank, invoke_tx, upgrade_tx) =
|
||||
setup_program_upgradeable_locks(&payer_keypair, &buffer_keypair, &program_keypair);
|
||||
execute_transactions(&bank, &[invoke_tx, upgrade_tx])
|
||||
};
|
||||
|
||||
if false {
|
||||
println!("upgrade and invoke");
|
||||
for result in &results1 {
|
||||
print_confirmed_tx("result", result.clone());
|
||||
}
|
||||
println!("invoke and upgrade");
|
||||
for result in &results2 {
|
||||
print_confirmed_tx("result", result.clone());
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref meta) = results1[0].transaction.meta {
|
||||
assert_eq!(meta.status, Ok(()));
|
||||
} else {
|
||||
panic!("no meta");
|
||||
}
|
||||
if let Some(ref meta) = results1[1].transaction.meta {
|
||||
assert_eq!(meta.status, Err(TransactionError::AccountInUse));
|
||||
} else {
|
||||
panic!("no meta");
|
||||
}
|
||||
if let Some(ref meta) = results2[0].transaction.meta {
|
||||
assert_eq!(
|
||||
meta.status,
|
||||
Err(TransactionError::InstructionError(
|
||||
0,
|
||||
InstructionError::ProgramFailedToComplete
|
||||
))
|
||||
);
|
||||
} else {
|
||||
panic!("no meta");
|
||||
}
|
||||
if let Some(ref meta) = results2[1].transaction.meta {
|
||||
assert_eq!(meta.status, Err(TransactionError::AccountInUse));
|
||||
} else {
|
||||
panic!("no meta");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ use solana_sdk::{
|
|||
bpf_loader_upgradeable::{self, UpgradeableLoaderState},
|
||||
clock::Clock,
|
||||
entrypoint::SUCCESS,
|
||||
feature_set::bpf_compute_budget_balancing,
|
||||
feature_set::{bpf_compute_budget_balancing, prevent_upgrade_and_invoke},
|
||||
instruction::InstructionError,
|
||||
keyed_account::{from_keyed_account, next_keyed_account, KeyedAccount},
|
||||
loader_instruction::LoaderInstruction,
|
||||
|
@ -470,6 +470,12 @@ fn process_loader_upgradeable_instruction(
|
|||
log!(logger, "Program account not executable");
|
||||
return Err(InstructionError::AccountNotExecutable);
|
||||
}
|
||||
if !program.is_writable()
|
||||
&& invoke_context.is_feature_active(&prevent_upgrade_and_invoke::id())
|
||||
{
|
||||
log!(logger, "Program account not writeable");
|
||||
return Err(InstructionError::InvalidArgument);
|
||||
}
|
||||
if &program.owner()? != program_id {
|
||||
log!(logger, "Program account not owned by loader");
|
||||
return Err(InstructionError::IncorrectProgramId);
|
||||
|
@ -2000,7 +2006,7 @@ mod tests {
|
|||
&bpf_loader_upgradeable::id(),
|
||||
&[
|
||||
KeyedAccount::new(&programdata_address, false, &programdata_account),
|
||||
KeyedAccount::new_readonly(&program_address, false, &program_account),
|
||||
KeyedAccount::new(&program_address, false, &program_account),
|
||||
KeyedAccount::new(&buffer_address, false, &buffer_account),
|
||||
KeyedAccount::new(&spill_address, false, &spill_account),
|
||||
KeyedAccount::new_readonly(&sysvar::rent::id(), false, &rent_account),
|
||||
|
@ -2062,7 +2068,7 @@ mod tests {
|
|||
&bpf_loader_upgradeable::id(),
|
||||
&[
|
||||
KeyedAccount::new(&programdata_address, false, &programdata_account),
|
||||
KeyedAccount::new_readonly(&program_address, false, &program_account),
|
||||
KeyedAccount::new(&program_address, false, &program_account),
|
||||
KeyedAccount::new(&buffer_address, false, &buffer_account),
|
||||
KeyedAccount::new(&spill_address, false, &spill_account),
|
||||
KeyedAccount::new_readonly(&sysvar::rent::id(), false, &rent_account),
|
||||
|
@ -2095,7 +2101,7 @@ mod tests {
|
|||
&bpf_loader_upgradeable::id(),
|
||||
&[
|
||||
KeyedAccount::new(&programdata_address, false, &programdata_account),
|
||||
KeyedAccount::new_readonly(&program_address, false, &program_account),
|
||||
KeyedAccount::new(&program_address, false, &program_account),
|
||||
KeyedAccount::new(&buffer_address, false, &buffer_account),
|
||||
KeyedAccount::new(&spill_address, false, &spill_account),
|
||||
KeyedAccount::new_readonly(&sysvar::rent::id(), false, &rent_account),
|
||||
|
@ -2128,7 +2134,7 @@ mod tests {
|
|||
&bpf_loader_upgradeable::id(),
|
||||
&[
|
||||
KeyedAccount::new(&programdata_address, false, &programdata_account),
|
||||
KeyedAccount::new_readonly(&program_address, false, &program_account),
|
||||
KeyedAccount::new(&program_address, false, &program_account),
|
||||
KeyedAccount::new(&buffer_address, false, &buffer_account),
|
||||
KeyedAccount::new(&spill_address, false, &spill_account),
|
||||
KeyedAccount::new_readonly(&sysvar::rent::id(), false, &rent_account),
|
||||
|
@ -2162,7 +2168,7 @@ mod tests {
|
|||
&bpf_loader_upgradeable::id(),
|
||||
&[
|
||||
KeyedAccount::new(&programdata_address, false, &programdata_account),
|
||||
KeyedAccount::new_readonly(&program_address, false, &program_account),
|
||||
KeyedAccount::new(&program_address, false, &program_account),
|
||||
KeyedAccount::new(&buffer_address, false, &buffer_account),
|
||||
KeyedAccount::new(&spill_address, false, &spill_account),
|
||||
KeyedAccount::new_readonly(&sysvar::rent::id(), false, &rent_account),
|
||||
|
@ -2192,6 +2198,39 @@ mod tests {
|
|||
program_account.borrow_mut().owner = Pubkey::new_unique();
|
||||
assert_eq!(
|
||||
Err(InstructionError::IncorrectProgramId),
|
||||
process_instruction(
|
||||
&bpf_loader_upgradeable::id(),
|
||||
&[
|
||||
KeyedAccount::new(&programdata_address, false, &programdata_account),
|
||||
KeyedAccount::new(&program_address, false, &program_account),
|
||||
KeyedAccount::new(&buffer_address, false, &buffer_account),
|
||||
KeyedAccount::new(&spill_address, false, &spill_account),
|
||||
KeyedAccount::new_readonly(&sysvar::rent::id(), false, &rent_account),
|
||||
KeyedAccount::new_readonly(&sysvar::clock::id(), false, &clock_account),
|
||||
KeyedAccount::new_readonly(
|
||||
&upgrade_authority_address,
|
||||
true,
|
||||
&upgrade_authority_account
|
||||
)
|
||||
],
|
||||
&instruction,
|
||||
&mut MockInvokeContext::default()
|
||||
)
|
||||
);
|
||||
|
||||
// Case: Program account not writable
|
||||
let (buffer_account, program_account, programdata_account, spill_account) = get_accounts(
|
||||
&buffer_address,
|
||||
&programdata_address,
|
||||
&upgrade_authority_address,
|
||||
slot,
|
||||
&elf_orig,
|
||||
&elf_new,
|
||||
min_program_balance,
|
||||
min_programdata_balance,
|
||||
);
|
||||
assert_eq!(
|
||||
Err(InstructionError::InvalidArgument),
|
||||
process_instruction(
|
||||
&bpf_loader_upgradeable::id(),
|
||||
&[
|
||||
|
@ -2233,7 +2272,7 @@ mod tests {
|
|||
&bpf_loader_upgradeable::id(),
|
||||
&[
|
||||
KeyedAccount::new(&programdata_address, false, &programdata_account),
|
||||
KeyedAccount::new_readonly(&program_address, false, &program_account),
|
||||
KeyedAccount::new(&program_address, false, &program_account),
|
||||
KeyedAccount::new(&buffer_address, false, &buffer_account),
|
||||
KeyedAccount::new(&spill_address, false, &spill_account),
|
||||
KeyedAccount::new_readonly(&sysvar::rent::id(), false, &rent_account),
|
||||
|
@ -2270,7 +2309,7 @@ mod tests {
|
|||
&bpf_loader_upgradeable::id(),
|
||||
&[
|
||||
KeyedAccount::new(&programdata_address, false, &programdata_account),
|
||||
KeyedAccount::new_readonly(&program_address, false, &program_account),
|
||||
KeyedAccount::new(&program_address, false, &program_account),
|
||||
KeyedAccount::new(&buffer_address, false, &buffer_account),
|
||||
KeyedAccount::new(&spill_address, false, &spill_account),
|
||||
KeyedAccount::new_readonly(&sysvar::rent::id(), false, &rent_account),
|
||||
|
@ -2303,7 +2342,7 @@ mod tests {
|
|||
&bpf_loader_upgradeable::id(),
|
||||
&[
|
||||
KeyedAccount::new(&Pubkey::new_unique(), false, &programdata_account),
|
||||
KeyedAccount::new_readonly(&program_address, false, &program_account),
|
||||
KeyedAccount::new(&program_address, false, &program_account),
|
||||
KeyedAccount::new(&buffer_address, false, &buffer_account),
|
||||
KeyedAccount::new(&spill_address, false, &spill_account),
|
||||
KeyedAccount::new_readonly(&sysvar::rent::id(), false, &rent_account),
|
||||
|
@ -2340,7 +2379,7 @@ mod tests {
|
|||
&bpf_loader_upgradeable::id(),
|
||||
&[
|
||||
KeyedAccount::new(&programdata_address, false, &programdata_account),
|
||||
KeyedAccount::new_readonly(&program_address, false, &program_account),
|
||||
KeyedAccount::new(&program_address, false, &program_account),
|
||||
KeyedAccount::new(&buffer_address, false, &buffer_account),
|
||||
KeyedAccount::new(&spill_address, false, &spill_account),
|
||||
KeyedAccount::new_readonly(&sysvar::rent::id(), false, &rent_account),
|
||||
|
@ -2384,7 +2423,7 @@ mod tests {
|
|||
&bpf_loader_upgradeable::id(),
|
||||
&[
|
||||
KeyedAccount::new(&programdata_address, false, &programdata_account),
|
||||
KeyedAccount::new_readonly(&program_address, false, &program_account),
|
||||
KeyedAccount::new(&program_address, false, &program_account),
|
||||
KeyedAccount::new(&buffer_address, false, &buffer_account),
|
||||
KeyedAccount::new(&spill_address, false, &spill_account),
|
||||
KeyedAccount::new_readonly(&sysvar::rent::id(), false, &rent_account),
|
||||
|
@ -2419,7 +2458,7 @@ mod tests {
|
|||
&bpf_loader_upgradeable::id(),
|
||||
&[
|
||||
KeyedAccount::new(&programdata_address, false, &programdata_account),
|
||||
KeyedAccount::new_readonly(&program_address, false, &program_account),
|
||||
KeyedAccount::new(&program_address, false, &program_account),
|
||||
KeyedAccount::new(&buffer_address, false, &buffer_account),
|
||||
KeyedAccount::new(&spill_address, false, &spill_account),
|
||||
KeyedAccount::new_readonly(&sysvar::rent::id(), false, &rent_account),
|
||||
|
|
|
@ -57,9 +57,9 @@ pub fn load_program<T: Client>(
|
|||
pub fn load_buffer_account<T: Client>(
|
||||
bank_client: &T,
|
||||
from_keypair: &Keypair,
|
||||
buffer_keypair: &Keypair,
|
||||
program: &[u8],
|
||||
) -> Pubkey {
|
||||
let buffer_keypair = Keypair::new();
|
||||
) {
|
||||
let buffer_pubkey = buffer_keypair.pubkey();
|
||||
|
||||
bank_client
|
||||
|
@ -100,26 +100,26 @@ pub fn load_buffer_account<T: Client>(
|
|||
.unwrap();
|
||||
offset += chunk_size as u32;
|
||||
}
|
||||
buffer_keypair.pubkey()
|
||||
}
|
||||
|
||||
pub fn load_upgradeable_program<T: Client>(
|
||||
bank_client: &T,
|
||||
from_keypair: &Keypair,
|
||||
buffer_keypair: &Keypair,
|
||||
executable_keypair: &Keypair,
|
||||
authority_keypair: &Keypair,
|
||||
program: Vec<u8>,
|
||||
) -> (Pubkey, Keypair) {
|
||||
let executable_keypair = Keypair::new();
|
||||
) {
|
||||
let program_pubkey = executable_keypair.pubkey();
|
||||
let authority_keypair = Keypair::new();
|
||||
let authority_pubkey = authority_keypair.pubkey();
|
||||
|
||||
let buffer_pubkey = load_buffer_account(bank_client, &from_keypair, &program);
|
||||
load_buffer_account(bank_client, &from_keypair, buffer_keypair, &program);
|
||||
|
||||
let message = Message::new(
|
||||
&bpf_loader_upgradeable::deploy_with_max_program_len(
|
||||
&from_keypair.pubkey(),
|
||||
&program_pubkey,
|
||||
&buffer_pubkey,
|
||||
&buffer_keypair.pubkey(),
|
||||
Some(&authority_pubkey),
|
||||
1.max(
|
||||
bank_client
|
||||
|
@ -136,8 +136,6 @@ pub fn load_upgradeable_program<T: Client>(
|
|||
bank_client
|
||||
.send_and_confirm_message(&[from_keypair, &executable_keypair], message)
|
||||
.unwrap();
|
||||
|
||||
(executable_keypair.pubkey(), authority_keypair)
|
||||
}
|
||||
|
||||
pub fn upgrade_program<T: Client>(
|
||||
|
|
|
@ -182,7 +182,7 @@ pub fn upgrade(
|
|||
&UpgradeableLoaderInstruction::Upgrade,
|
||||
vec![
|
||||
AccountMeta::new(programdata_address, false),
|
||||
AccountMeta::new_readonly(*program_address, false),
|
||||
AccountMeta::new(*program_address, false),
|
||||
AccountMeta::new(*buffer_address, false),
|
||||
AccountMeta::new(*spill_address, false),
|
||||
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
||||
|
@ -250,4 +250,45 @@ mod tests {
|
|||
UpgradeableLoaderState::programdata_len(42).unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_upgrade_instruction() {
|
||||
assert_eq!(
|
||||
false,
|
||||
is_upgrade_instruction(
|
||||
&bincode::serialize(&UpgradeableLoaderInstruction::InitializeBuffer).unwrap()
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
false,
|
||||
is_upgrade_instruction(
|
||||
&bincode::serialize(&UpgradeableLoaderInstruction::Write {
|
||||
offset: 0,
|
||||
bytes: vec![],
|
||||
})
|
||||
.unwrap()
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
false,
|
||||
is_upgrade_instruction(
|
||||
&bincode::serialize(&UpgradeableLoaderInstruction::DeployWithMaxDataLen {
|
||||
max_data_len: 0,
|
||||
})
|
||||
.unwrap()
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
true,
|
||||
is_upgrade_instruction(
|
||||
&bincode::serialize(&UpgradeableLoaderInstruction::Upgrade).unwrap()
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
false,
|
||||
is_upgrade_instruction(
|
||||
&bincode::serialize(&UpgradeableLoaderInstruction::SetAuthority).unwrap()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ pub enum UpgradeableLoaderInstruction {
|
|||
///
|
||||
/// # Account references
|
||||
/// 0. [writable] The ProgramData account.
|
||||
/// 1. [] The Program account.
|
||||
/// 1. [writable] The Program account.
|
||||
/// 2. [Writable] The Buffer account where the program data has been
|
||||
/// written.
|
||||
/// 3. [writable] The spill account.
|
||||
|
|
|
@ -142,6 +142,10 @@ pub mod turbine_retransmit_peers_patch {
|
|||
solana_sdk::declare_id!("5Lu3JnWSFwRYpXzwDMkanWSk6XqSuF2i5fpnVhzB5CTc");
|
||||
}
|
||||
|
||||
pub mod prevent_upgrade_and_invoke {
|
||||
solana_sdk::declare_id!("BiNjYd8jCYDgAwMqP91uwZs6skWpuHtKrZbckuKESs8N");
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
/// Map of feature identifiers to user-visible description
|
||||
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
|
||||
|
@ -179,6 +183,7 @@ lazy_static! {
|
|||
(abort_on_all_cpi_failures::id(), "Abort on all CPI failures"),
|
||||
(use_loaded_executables::id(), "Use loaded executable accounts"),
|
||||
(turbine_retransmit_peers_patch::id(), "turbine retransmit peers patch #14631"),
|
||||
(prevent_upgrade_and_invoke::id(), "Prevent upgrade and invoke in same tx batch"),
|
||||
/*************** ADD NEW FEATURES HERE ***************/
|
||||
]
|
||||
.iter()
|
||||
|
|
|
@ -359,7 +359,7 @@ pub struct EncodedConfirmedBlock {
|
|||
pub block_time: Option<UnixTimestamp>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ConfirmedTransaction {
|
||||
pub slot: Slot,
|
||||
|
|
Loading…
Reference in New Issue