Never Nonce
Prevent the use of durable nonces in a transaction using pinocchio-never-nonce
Pinocchio Never Nonce
The pinocchio-never-nonce crate provides a simple way to prevent the use of durable nonces in a transaction. This is useful when you want to ensure that a program instruction is never executed as part of a durable nonce transaction.
Why Prevent Durable Nonces?
Durable nonce transactions can be held indefinitely before submission. In some cases, you may want to guarantee that a transaction is submitted promptly with a recent blockhash — for example:
- Time-sensitive operations — where delayed execution could be exploited
- Oracle-dependent programs — where stale data could lead to incorrect results
- Security-critical instructions — where transaction replay or delayed submission poses risks
Installation
cargo add p-never-nonce
Usage
Add a call to ensure_never_nonce in your program's instruction handler. It checks that the first instruction in the transaction is not an advance nonce instruction:
use p_never_nonce::ensure_never_nonce;
use pinocchio::{
ProgramResult,
entrypoint::{InstructionContext, MaybeAccount},
error::ProgramError,
lazy_program_entrypoint, no_allocator, nostd_panic_handler,
};
no_allocator!();
nostd_panic_handler!();
lazy_program_entrypoint!(process_instruction);
pub fn process_instruction(mut context: InstructionContext) -> ProgramResult {
let MaybeAccount::Account(instructions_sysvar) = context.next_account()? else {
return Err(ProgramError::NotEnoughAccountKeys);
};
// Fails if the first instruction is an advance nonce.
ensure_never_nonce(&instructions_sysvar, ProgramError::InvalidArgument)
}
The program requires the Instructions sysvar (Sysvar1nstructions1111111111111111111111111) to be passed as an account so it can inspect the transaction's instruction list.