Nonce accounts must be writeable (#21260)
* Nonce accounts must be writeable * feedback * feedback
This commit is contained in:
@ -237,6 +237,10 @@ pub mod reject_deployment_of_unresolved_syscalls {
|
||||
solana_sdk::declare_id!("DqniU3MfvdpU3yhmNF1RKeaM5TZQELZuyFGosASRVUoy");
|
||||
}
|
||||
|
||||
pub mod nonce_must_be_writable {
|
||||
solana_sdk::declare_id!("BiCU7M5w8ZCMykVSyhZ7Q3m2SWoR2qrEQ86ERcDX77ME");
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
/// Map of feature identifiers to user-visible description
|
||||
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
|
||||
@ -291,6 +295,7 @@ lazy_static! {
|
||||
(disable_fee_calculator::id(), "deprecate fee calculator"),
|
||||
(add_compute_budget_program::id(), "Add compute_budget_program"),
|
||||
(reject_deployment_of_unresolved_syscalls::id(), "Reject deployment of programs with unresolved syscall symbols"),
|
||||
(nonce_must_be_writable::id(), "nonce must be writable"),
|
||||
/*************** ADD NEW FEATURES HERE ***************/
|
||||
]
|
||||
.iter()
|
||||
|
@ -502,14 +502,23 @@ pub fn uses_durable_nonce(tx: &Transaction) -> Option<&CompiledInstruction> {
|
||||
message
|
||||
.instructions
|
||||
.get(NONCED_TX_MARKER_IX_INDEX as usize)
|
||||
.filter(|maybe_ix| {
|
||||
let prog_id_idx = maybe_ix.program_id_index as usize;
|
||||
match message.account_keys.get(prog_id_idx) {
|
||||
Some(program_id) => system_program::check_id(program_id),
|
||||
_ => false,
|
||||
}
|
||||
} && matches!(limited_deserialize(&maybe_ix.data), Ok(SystemInstruction::AdvanceNonceAccount))
|
||||
)
|
||||
.filter(|instruction| {
|
||||
// Is system program
|
||||
matches!(
|
||||
message.account_keys.get(instruction.program_id_index as usize),
|
||||
Some(program_id) if system_program::check_id(program_id)
|
||||
)
|
||||
// Is a nonce advance instruction
|
||||
&& matches!(
|
||||
limited_deserialize(&instruction.data),
|
||||
Ok(SystemInstruction::AdvanceNonceAccount)
|
||||
)
|
||||
// Nonce account is writable
|
||||
&& matches!(
|
||||
instruction.accounts.get(0),
|
||||
Some(index) if message.is_writable(*index as usize, true)
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
#[deprecated]
|
||||
@ -532,7 +541,7 @@ mod tests {
|
||||
hash::hash,
|
||||
instruction::AccountMeta,
|
||||
signature::{Keypair, Presigner, Signer},
|
||||
system_instruction,
|
||||
system_instruction, sysvar,
|
||||
};
|
||||
use bincode::{deserialize, serialize, serialized_size};
|
||||
use std::mem::size_of;
|
||||
@ -993,6 +1002,32 @@ mod tests {
|
||||
assert!(uses_durable_nonce(&tx).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tx_uses_ro_nonce_account() {
|
||||
let from_keypair = Keypair::new();
|
||||
let from_pubkey = from_keypair.pubkey();
|
||||
let nonce_keypair = Keypair::new();
|
||||
let nonce_pubkey = nonce_keypair.pubkey();
|
||||
let account_metas = vec![
|
||||
AccountMeta::new_readonly(nonce_pubkey, false),
|
||||
#[allow(deprecated)]
|
||||
AccountMeta::new_readonly(sysvar::recent_blockhashes::id(), false),
|
||||
AccountMeta::new_readonly(nonce_pubkey, true),
|
||||
];
|
||||
let nonce_instruction = Instruction::new_with_bincode(
|
||||
system_program::id(),
|
||||
&system_instruction::SystemInstruction::AdvanceNonceAccount,
|
||||
account_metas,
|
||||
);
|
||||
let tx = Transaction::new_signed_with_payer(
|
||||
&[nonce_instruction],
|
||||
Some(&from_pubkey),
|
||||
&[&from_keypair, &nonce_keypair],
|
||||
Hash::default(),
|
||||
);
|
||||
assert!(uses_durable_nonce(&tx).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tx_uses_nonce_wrong_first_nonce_ix_fail() {
|
||||
let from_keypair = Keypair::new();
|
||||
|
@ -161,7 +161,7 @@ impl SanitizedTransaction {
|
||||
}
|
||||
|
||||
/// If the transaction uses a durable nonce, return the pubkey of the nonce account
|
||||
pub fn get_durable_nonce(&self) -> Option<&Pubkey> {
|
||||
pub fn get_durable_nonce(&self, nonce_must_be_writable: bool) -> Option<&Pubkey> {
|
||||
self.message
|
||||
.instructions()
|
||||
.get(NONCED_TX_MARKER_IX_INDEX as usize)
|
||||
@ -180,7 +180,11 @@ impl SanitizedTransaction {
|
||||
.and_then(|ix| {
|
||||
ix.accounts.get(0).and_then(|idx| {
|
||||
let idx = *idx as usize;
|
||||
self.message.get_account_key(idx)
|
||||
if nonce_must_be_writable && !self.message.is_writable(idx, true) {
|
||||
None
|
||||
} else {
|
||||
self.message.get_account_key(idx)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
Reference in New Issue
Block a user