Bank::get_fee_for_message is now nonce aware

This commit is contained in:
Michael Vines
2022-01-13 13:06:03 -08:00
parent 4ab7d6c23e
commit 4c577d7f8c
6 changed files with 98 additions and 45 deletions

View File

@ -38,6 +38,7 @@ pub mod program_memory;
pub mod program_option;
pub mod program_pack;
pub mod program_stubs;
pub mod program_utils;
pub mod pubkey;
pub mod rent;
pub mod sanitize;

View File

@ -7,9 +7,12 @@ use {
v0::{self, LoadedAddresses},
MessageHeader,
},
nonce::NONCED_TX_MARKER_IX_INDEX,
program_utils::limited_deserialize,
pubkey::Pubkey,
sanitize::{Sanitize, SanitizeError},
serialize_utils::{append_slice, append_u16, append_u8},
solana_program::{system_instruction::SystemInstruction, system_program},
},
bitflags::bitflags,
std::convert::TryFrom,
@ -292,6 +295,34 @@ impl SanitizedMessage {
Self::V0(message) => message.is_upgradeable_loader_present(),
}
}
/// If the message uses a durable nonce, return the pubkey of the nonce account
pub fn get_durable_nonce(&self, nonce_must_be_writable: bool) -> Option<&Pubkey> {
self.instructions()
.get(NONCED_TX_MARKER_IX_INDEX as usize)
.filter(
|ix| match self.get_account_key(ix.program_id_index as usize) {
Some(program_id) => system_program::check_id(program_id),
_ => false,
},
)
.filter(|ix| {
matches!(
limited_deserialize(&ix.data, 4 /* serialized size of AdvanceNonceAccount */),
Ok(SystemInstruction::AdvanceNonceAccount)
)
})
.and_then(|ix| {
ix.accounts.get(0).and_then(|idx| {
let idx = *idx as usize;
if nonce_must_be_writable && !self.is_writable(idx) {
None
} else {
self.get_account_key(idx)
}
})
})
}
}
#[cfg(test)]

View File

@ -0,0 +1,38 @@
use {crate::instruction::InstructionError, bincode::config::Options};
/// Deserialize with a limit based the maximum amount of data a program can expect to get.
/// This function should be used in place of direct deserialization to help prevent OOM errors
pub fn limited_deserialize<T>(instruction_data: &[u8], limit: u64) -> Result<T, InstructionError>
where
T: serde::de::DeserializeOwned,
{
bincode::options()
.with_limit(limit)
.with_fixint_encoding() // As per https://github.com/servo/bincode/issues/333, these two options are needed
.allow_trailing_bytes() // to retain the behavior of bincode::deserialize with the new `options()` method
.deserialize_from(instruction_data)
.map_err(|_| InstructionError::InvalidInstructionData)
}
#[cfg(test)]
pub mod tests {
use {super::*, solana_program::system_instruction::SystemInstruction};
#[test]
fn test_limited_deserialize_advance_nonce_account() {
let item = SystemInstruction::AdvanceNonceAccount;
let serialized = bincode::serialize(&item).unwrap();
assert_eq!(
serialized.len(),
4,
"`SanitizedMessage::get_durable_nonce()` may need a change"
);
assert_eq!(
limited_deserialize::<SystemInstruction>(&serialized, 4).as_ref(),
Ok(&item)
);
assert!(limited_deserialize::<SystemInstruction>(&serialized, 3).is_err());
}
}