Store address table lookups in blockstore and bigtable (#22402)
This commit is contained in:
@ -71,6 +71,24 @@ impl VersionedMessage {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn total_account_keys_len(&self) -> usize {
|
||||
match self {
|
||||
Self::Legacy(message) => message.account_keys.len(),
|
||||
Self::V0(message) => message.account_keys.len().saturating_add(
|
||||
message
|
||||
.address_table_lookups
|
||||
.iter()
|
||||
.map(|lookup| {
|
||||
lookup
|
||||
.writable_indexes
|
||||
.len()
|
||||
.saturating_add(lookup.readonly_indexes.len())
|
||||
})
|
||||
.sum(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn recent_blockhash(&self) -> &Hash {
|
||||
match self {
|
||||
Self::Legacy(message) => &message.recent_blockhash,
|
||||
@ -85,6 +103,13 @@ impl VersionedMessage {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn instructions(&self) -> &[CompiledInstruction] {
|
||||
match self {
|
||||
Self::Legacy(message) => &message.instructions,
|
||||
Self::V0(message) => &message.instructions,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn serialize(&self) -> Vec<u8> {
|
||||
bincode::serialize(self).unwrap()
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use {
|
||||
pubkey::Pubkey,
|
||||
sysvar,
|
||||
},
|
||||
std::{collections::HashSet, convert::TryFrom, ops::Deref},
|
||||
std::{collections::HashSet, ops::Deref},
|
||||
};
|
||||
|
||||
/// Combination of a version #0 message and its loaded addresses
|
||||
@ -47,6 +47,30 @@ impl FromIterator<LoadedAddresses> for LoadedAddresses {
|
||||
}
|
||||
}
|
||||
|
||||
impl LoadedAddresses {
|
||||
/// Checks if there are no writable or readonly addresses
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
/// Combined length of loaded writable and readonly addresses
|
||||
pub fn len(&self) -> usize {
|
||||
self.writable.len().saturating_add(self.readonly.len())
|
||||
}
|
||||
|
||||
/// Iterate over loaded addresses in the order that they are used
|
||||
/// as account indexes
|
||||
pub fn ordered_iter(&self) -> impl Iterator<Item = &Pubkey> {
|
||||
self.writable.iter().chain(self.readonly.iter())
|
||||
}
|
||||
|
||||
/// Iterate over loaded addresses in the order that they are used
|
||||
/// as account indexes
|
||||
pub fn into_ordered_iter(self) -> impl Iterator<Item = Pubkey> {
|
||||
self.writable.into_iter().chain(self.readonly.into_iter())
|
||||
}
|
||||
}
|
||||
|
||||
impl LoadedMessage {
|
||||
/// Returns an iterator of account key segments. The ordering of segments
|
||||
/// affects how account indexes from compiled instructions are resolved and
|
||||
|
@ -48,6 +48,9 @@ pub enum SignerError {
|
||||
|
||||
#[error("{0}")]
|
||||
UserCancel(String),
|
||||
|
||||
#[error("too many signers")]
|
||||
TooManySigners,
|
||||
}
|
||||
|
||||
/// The `Signer` trait declares operations that all digital signature providers
|
||||
|
@ -176,6 +176,14 @@ impl SanitizedTransaction {
|
||||
account_locks
|
||||
}
|
||||
|
||||
/// Return the list of addresses loaded from on-chain address lookup tables
|
||||
pub fn get_loaded_addresses(&self) -> LoadedAddresses {
|
||||
match &self.message {
|
||||
SanitizedMessage::Legacy(_) => LoadedAddresses::default(),
|
||||
SanitizedMessage::V0(message) => message.loaded_addresses.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
/// 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> {
|
||||
self.message.get_durable_nonce(nonce_must_be_writable)
|
||||
|
@ -9,6 +9,8 @@ use {
|
||||
sanitize::{Sanitize, SanitizeError},
|
||||
short_vec,
|
||||
signature::Signature,
|
||||
signer::SignerError,
|
||||
signers::Signers,
|
||||
transaction::{Result, Transaction, TransactionError},
|
||||
},
|
||||
serde::Serialize,
|
||||
@ -57,6 +59,40 @@ impl From<Transaction> for VersionedTransaction {
|
||||
}
|
||||
|
||||
impl VersionedTransaction {
|
||||
/// Signs a versioned message and if successful, returns a signed
|
||||
/// transaction.
|
||||
pub fn try_new<T: Signers>(
|
||||
message: VersionedMessage,
|
||||
keypairs: &T,
|
||||
) -> std::result::Result<Self, SignerError> {
|
||||
let static_account_keys = message.static_account_keys();
|
||||
if static_account_keys.len() < message.header().num_required_signatures as usize {
|
||||
return Err(SignerError::InvalidInput("invalid message".to_string()));
|
||||
}
|
||||
|
||||
let signer_keys = keypairs.pubkeys();
|
||||
let expected_signer_keys =
|
||||
&static_account_keys[0..message.header().num_required_signatures as usize];
|
||||
|
||||
match signer_keys.len().cmp(&expected_signer_keys.len()) {
|
||||
Ordering::Greater => Err(SignerError::TooManySigners),
|
||||
Ordering::Less => Err(SignerError::NotEnoughSigners),
|
||||
Ordering::Equal => Ok(()),
|
||||
}?;
|
||||
|
||||
if signer_keys != expected_signer_keys {
|
||||
return Err(SignerError::KeypairPubkeyMismatch);
|
||||
}
|
||||
|
||||
let message_data = message.serialize();
|
||||
let signatures = keypairs.try_sign_message(&message_data)?;
|
||||
|
||||
Ok(Self {
|
||||
signatures,
|
||||
message,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns a legacy transaction if the transaction message is legacy.
|
||||
pub fn into_legacy_transaction(self) -> Option<Transaction> {
|
||||
match self.message {
|
||||
|
Reference in New Issue
Block a user