Store address table lookups in blockstore and bigtable (#22402)

This commit is contained in:
Justin Starry
2022-01-14 15:24:41 +08:00
committed by GitHub
parent 4c577d7f8c
commit f804ccdece
28 changed files with 836 additions and 199 deletions

View File

@ -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()
}

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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 {