Skip to content
This repository has been archived by the owner on Jan 22, 2025. It is now read-only.

Commit

Permalink
create separate structs for runtime in different state, add corespond…
Browse files Browse the repository at this point in the history
…ing traits for transacion_meta
  • Loading branch information
tao-stones committed Oct 2, 2023
1 parent 6eda794 commit 0ca1826
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 48 deletions.
143 changes: 98 additions & 45 deletions runtime-transaction/src/runtime_transaction.rs
Original file line number Diff line number Diff line change
@@ -1,72 +1,125 @@
use {
crate::{
simple_vote_transaction_checker::is_simple_vote_transaction, transaction_meta::TransactionMeta,
simple_vote_transaction_checker::is_simple_vote_transaction,
transaction_meta::{DynamicallyLoadedMeta, StaticallyLoadedMeta, TransactionMeta},
},
solana_sdk::{
hash::Hash,
message::{
v0::{self},
AddressLoader, LegacyMessage, SanitizedMessage, SanitizedVersionedMessage,
VersionedMessage,
AddressLoader, SanitizedMessage, SanitizedVersionedMessage,
},
signature::Signature,
transaction::{MessageHash, Result, SanitizedVersionedTransaction},
transaction::{Result, SanitizedVersionedTransaction},
},
};

/// RuntimeTransaction is runtime face representation of transaction, as
/// SanitizedTransaction is client facing rep.
/// RuntimeTransaction is `runtime` facing representation of transaction, while
/// solana_sdk::SanitizedTransaction is client facing representation.
///
/// It has two states:
/// 1. Statically Loaded: after receiving `packet` from sigverify and deserializing
/// it into `solana_sdk::VersioedTransaction`, then sanitizing into
/// `solana_sdk::SanitizedVersionedTransaction`, `RuntimeTransactionStaticallyLoaded`
/// can be created from it with static transaction metadata extracted.
/// 2. Dynamically Loaded: after successfully loaded account addresses from onchain
/// ALT, RuntimeTransaction transits into DynamicallyLoaded state, with
/// its dynamic metadata loaded.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct RuntimeTransaction {
message: SanitizedMessage,
message_hash: Hash,
pub struct RuntimeTransactionStaticallyLoaded {
// sanitized signatures
signatures: Vec<Signature>,
transaction_meta: TransactionMeta,

// sanitized message
message: SanitizedVersionedMessage,

// transaction meta is a collection of fields, it is updated
// during message state transition
meta: TransactionMeta,
}

impl RuntimeTransaction {
/// Create a runtime transaction from a sanitized versioend transaction,
/// then load account addresses from address-lookup-table if apply, and
/// populate transaction metadata.
pub fn try_new(
// Note: transaction sanitization is a function of `sdk` that is shared
// by both runtime and client.
impl StaticallyLoadedMeta for RuntimeTransactionStaticallyLoaded {
fn message_hash(&self) -> &Hash { &self.meta.message_hash }
fn is_simple_vote_tx(&self) -> bool { self.meta.is_simple_vote_tx }
}

impl RuntimeTransactionStaticallyLoaded{
pub fn try_from(
sanitized_versioned_tx: SanitizedVersionedTransaction,
message_hash: impl Into<MessageHash>,
message_hash: Option<Hash>,
is_simple_vote_tx: Option<bool>,
address_loader: impl AddressLoader,
) -> Result<Self> {
// metadata can be lazily updated alone transaction's execution path
let mut transaction_meta = TransactionMeta::default();
transaction_meta.set_is_simple_vote_tx(is_simple_vote_tx.unwrap_or_else(|| {
is_simple_vote_transaction(&sanitized_versioned_tx)
let meta = Self::load_static_metadata(&sanitized_versioned_tx, message_hash, is_simple_vote_tx)?;

Ok(Self {
signatures: sanitized_versioned_tx.signatures,
message: sanitized_versioned_tx.message,
meta,
})
}

// private helpers
fn load_static_metadata(
sanitized_versioned_tx: &SanitizedVersionedTransaction,
message_hash: Option<Hash>,
is_simple_vote_tx: Option<bool>,
) ->Result<TransactionMeta> {
let mut meta = TransactionMeta::default();
meta.set_is_simple_vote_tx(is_simple_vote_tx.unwrap_or_else(|| {
is_simple_vote_transaction(sanitized_versioned_tx)
}));
meta.set_message_hash(message_hash.unwrap_or_else(|| {
sanitized_versioned_tx.message.message.hash()
}));

let signatures = sanitized_versioned_tx.signatures;
Ok(meta)
}

let SanitizedVersionedMessage { message } = sanitized_versioned_tx.message;
}

let message_hash = match message_hash.into() {
MessageHash::Compute => message.hash(),
MessageHash::Precomputed(hash) => hash,
};

let message = match message {
VersionedMessage::Legacy(message) => {
SanitizedMessage::Legacy(LegacyMessage::new(message))
}
VersionedMessage::V0(message) => {
let loaded_addresses =
address_loader.load_addresses(&message.address_table_lookups)?;
SanitizedMessage::V0(v0::LoadedMessage::new(message, loaded_addresses))
}
/// Statically Loaded transaction can transit to Dynamically Loaded with supplied
/// address_loader, to load accounts from on-chain ALT, then resolve dynamic metadata
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct RuntimeTransactionDynamicallyLoaded {
// sanitized signatures
signatures: Vec<Signature>,

// sanitized message
message: SanitizedMessage,

// transaction meta is a collection of fields, it is updated
// during message state transition
meta: TransactionMeta,
}

impl DynamicallyLoadedMeta for RuntimeTransactionDynamicallyLoaded {
}

impl StaticallyLoadedMeta for RuntimeTransactionDynamicallyLoaded {
fn message_hash(&self) -> &Hash { &self.meta.message_hash }
fn is_simple_vote_tx(&self) -> bool { self.meta.is_simple_vote_tx }
}

impl RuntimeTransactionDynamicallyLoaded{
pub fn try_from(
statically_loaded_runtime_tx: RuntimeTransactionStaticallyLoaded,
address_loader: impl AddressLoader,
) -> Result<Self> {
let mut tx = Self {
signatures: statically_loaded_runtime_tx.signatures,
message: SanitizedMessage::try_new(statically_loaded_runtime_tx.message, address_loader)?,
meta: statically_loaded_runtime_tx.meta,
};
tx.load_dynamic_metadata()?;

Ok(Self {
message,
message_hash,
signatures,
transaction_meta,
})
Ok(tx)
}

// private helpers
fn load_dynamic_metadata(
&mut self,
) -> Result<()> {
Ok(())
}
}
32 changes: 29 additions & 3 deletions runtime-transaction/src/transaction_meta.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,42 @@
//! Transaction Meta contains data that follows a transaction through the
//! execution pipeline in runtime. Metadata can include limits specified by
//! compute-budget instructions, simple-vote flag, transactino costs,
//! durable nonce account etc; Metadata can be lazily populated as
//! transaction goes through execution path.
//! compute-budget instructions, simple-vote flag, transaction costs,
//! durable nonce account etc;
//!
//! The premiss is if anything qualifies as metadata, then it must be valid
//! and available as long as the transaction itself is valid and available.
//! Hence they are not Option<T> type. Their visibility are defined in traits.
//!
use {
solana_sdk::hash::Hash,
};

/// metadata can be extracted statically from sanitized transaction,
/// for example: message hash, simple-vote-tx flag, compute budget limits,
pub trait StaticallyLoadedMeta {
fn message_hash(&self) -> &Hash;
fn is_simple_vote_tx(&self) -> bool;
}

/// Statically loaded meta is a supertrait of Dynamically loaded meta, when
/// transaction transited successfully into dynamically loaded, it should
/// have both meta data populated and available.
/// Dynamic metadata available after accounts addresses are loaded from
/// on-chain ALT, examples are: transaction usage costs, nonce account.
pub trait DynamicallyLoadedMeta: StaticallyLoadedMeta {
}

#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct TransactionMeta {
pub message_hash: Hash,
pub is_simple_vote_tx: bool,
}

impl TransactionMeta {
pub fn set_message_hash(&mut self, message_hash: Hash) {
self.message_hash = message_hash;
}

pub fn set_is_simple_vote_tx(&mut self, is_simple_vote_tx: bool) {
self.is_simple_vote_tx = is_simple_vote_tx;
}
Expand Down

0 comments on commit 0ca1826

Please sign in to comment.