`Bank::get_fee_for_message` is now nonce aware
This commit is contained in:
parent
4ab7d6c23e
commit
4c577d7f8c
|
@ -3073,9 +3073,17 @@ impl Bank {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_fee_for_message(&self, message: &SanitizedMessage) -> Option<u64> {
|
pub fn get_fee_for_message(&self, message: &SanitizedMessage) -> Option<u64> {
|
||||||
|
let lamports_per_signature = {
|
||||||
let blockhash_queue = self.blockhash_queue.read().unwrap();
|
let blockhash_queue = self.blockhash_queue.read().unwrap();
|
||||||
let lamports_per_signature =
|
blockhash_queue.get_lamports_per_signature(message.recent_blockhash())
|
||||||
blockhash_queue.get_lamports_per_signature(message.recent_blockhash())?;
|
}
|
||||||
|
.or_else(|| {
|
||||||
|
self.check_message_for_nonce(message)
|
||||||
|
.and_then(|(address, account)| {
|
||||||
|
NoncePartial::new(address, account).lamports_per_signature()
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
|
||||||
Some(Self::calculate_fee(message, lamports_per_signature))
|
Some(Self::calculate_fee(message, lamports_per_signature))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3438,20 +3446,25 @@ impl Bank {
|
||||||
.check_hash_age(hash, max_age)
|
.check_hash_age(hash, max_age)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_transaction_for_nonce(
|
fn check_message_for_nonce(&self, message: &SanitizedMessage) -> Option<TransactionAccount> {
|
||||||
&self,
|
message
|
||||||
tx: &SanitizedTransaction,
|
.get_durable_nonce(self.feature_set.is_active(&nonce_must_be_writable::id()))
|
||||||
) -> Option<TransactionAccount> {
|
|
||||||
tx.get_durable_nonce(self.feature_set.is_active(&nonce_must_be_writable::id()))
|
|
||||||
.and_then(|nonce_address| {
|
.and_then(|nonce_address| {
|
||||||
self.get_account_with_fixed_root(nonce_address)
|
self.get_account_with_fixed_root(nonce_address)
|
||||||
.map(|nonce_account| (*nonce_address, nonce_account))
|
.map(|nonce_account| (*nonce_address, nonce_account))
|
||||||
})
|
})
|
||||||
.filter(|(_, nonce_account)| {
|
.filter(|(_, nonce_account)| {
|
||||||
nonce_account::verify_nonce_account(nonce_account, tx.message().recent_blockhash())
|
nonce_account::verify_nonce_account(nonce_account, message.recent_blockhash())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn check_transaction_for_nonce(
|
||||||
|
&self,
|
||||||
|
tx: &SanitizedTransaction,
|
||||||
|
) -> Option<TransactionAccount> {
|
||||||
|
self.check_message_for_nonce(tx.message())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn check_transactions(
|
pub fn check_transactions(
|
||||||
&self,
|
&self,
|
||||||
sanitized_txs: &[SanitizedTransaction],
|
sanitized_txs: &[SanitizedTransaction],
|
||||||
|
|
|
@ -38,6 +38,7 @@ pub mod program_memory;
|
||||||
pub mod program_option;
|
pub mod program_option;
|
||||||
pub mod program_pack;
|
pub mod program_pack;
|
||||||
pub mod program_stubs;
|
pub mod program_stubs;
|
||||||
|
pub mod program_utils;
|
||||||
pub mod pubkey;
|
pub mod pubkey;
|
||||||
pub mod rent;
|
pub mod rent;
|
||||||
pub mod sanitize;
|
pub mod sanitize;
|
||||||
|
|
|
@ -7,9 +7,12 @@ use {
|
||||||
v0::{self, LoadedAddresses},
|
v0::{self, LoadedAddresses},
|
||||||
MessageHeader,
|
MessageHeader,
|
||||||
},
|
},
|
||||||
|
nonce::NONCED_TX_MARKER_IX_INDEX,
|
||||||
|
program_utils::limited_deserialize,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
sanitize::{Sanitize, SanitizeError},
|
sanitize::{Sanitize, SanitizeError},
|
||||||
serialize_utils::{append_slice, append_u16, append_u8},
|
serialize_utils::{append_slice, append_u16, append_u8},
|
||||||
|
solana_program::{system_instruction::SystemInstruction, system_program},
|
||||||
},
|
},
|
||||||
bitflags::bitflags,
|
bitflags::bitflags,
|
||||||
std::convert::TryFrom,
|
std::convert::TryFrom,
|
||||||
|
@ -292,6 +295,34 @@ impl SanitizedMessage {
|
||||||
Self::V0(message) => message.is_upgradeable_loader_present(),
|
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)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
use {crate::instruction::InstructionError, bincode::config::Options};
|
use crate::instruction::InstructionError;
|
||||||
|
|
||||||
/// Deserialize with a limit based the maximum amount of data a program can expect to get.
|
/// 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
|
/// This function should be used in place of direct deserialization to help prevent OOM errors
|
||||||
|
@ -6,13 +6,10 @@ pub fn limited_deserialize<T>(instruction_data: &[u8]) -> Result<T, InstructionE
|
||||||
where
|
where
|
||||||
T: serde::de::DeserializeOwned,
|
T: serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
let limit = crate::packet::PACKET_DATA_SIZE as u64;
|
solana_program::program_utils::limited_deserialize(
|
||||||
bincode::options()
|
instruction_data,
|
||||||
.with_limit(limit)
|
crate::packet::PACKET_DATA_SIZE as u64,
|
||||||
.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)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -6,16 +6,13 @@ use {
|
||||||
v0::{self, LoadedAddresses, MessageAddressTableLookup},
|
v0::{self, LoadedAddresses, MessageAddressTableLookup},
|
||||||
SanitizedMessage, VersionedMessage,
|
SanitizedMessage, VersionedMessage,
|
||||||
},
|
},
|
||||||
nonce::NONCED_TX_MARKER_IX_INDEX,
|
|
||||||
precompiles::verify_if_precompile,
|
precompiles::verify_if_precompile,
|
||||||
program_utils::limited_deserialize,
|
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
sanitize::Sanitize,
|
sanitize::Sanitize,
|
||||||
signature::Signature,
|
signature::Signature,
|
||||||
solana_sdk::feature_set,
|
solana_sdk::feature_set,
|
||||||
transaction::{Result, Transaction, TransactionError, VersionedTransaction},
|
transaction::{Result, Transaction, TransactionError, VersionedTransaction},
|
||||||
},
|
},
|
||||||
solana_program::{system_instruction::SystemInstruction, system_program},
|
|
||||||
std::sync::Arc,
|
std::sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -181,31 +178,7 @@ impl SanitizedTransaction {
|
||||||
|
|
||||||
/// If the transaction uses a durable nonce, return the pubkey of the nonce account
|
/// If the transaction uses a durable nonce, return the pubkey of the nonce account
|
||||||
pub fn get_durable_nonce(&self, nonce_must_be_writable: bool) -> Option<&Pubkey> {
|
pub fn get_durable_nonce(&self, nonce_must_be_writable: bool) -> Option<&Pubkey> {
|
||||||
self.message
|
self.message.get_durable_nonce(nonce_must_be_writable)
|
||||||
.instructions()
|
|
||||||
.get(NONCED_TX_MARKER_IX_INDEX as usize)
|
|
||||||
.filter(
|
|
||||||
|ix| match self.message.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),
|
|
||||||
Ok(SystemInstruction::AdvanceNonceAccount)
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.and_then(|ix| {
|
|
||||||
ix.accounts.get(0).and_then(|idx| {
|
|
||||||
let idx = *idx as usize;
|
|
||||||
if nonce_must_be_writable && !self.message.is_writable(idx) {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
self.message.get_account_key(idx)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the serialized message data to sign.
|
/// Return the serialized message data to sign.
|
||||||
|
|
Loading…
Reference in New Issue