pub mod confirmed;
pub use confirmed::*;
pub mod rejected;
pub use rejected::*;
mod bytes;
mod merkle;
mod serialize;
mod string;
use crate::{Transaction, Transition};
use console::{
network::prelude::*,
program::{
Ciphertext,
ProgramOwner,
Record,
TransactionsPath,
TransactionsTree,
FINALIZE_OPERATIONS_DEPTH,
TRANSACTIONS_DEPTH,
},
types::{Field, Group, U64},
};
use synthesizer_program::FinalizeOperation;
use indexmap::IndexMap;
#[cfg(not(feature = "serial"))]
use rayon::prelude::*;
#[derive(Clone, PartialEq, Eq)]
pub struct Transactions<N: Network> {
transactions: IndexMap<N::TransactionID, ConfirmedTransaction<N>>,
}
impl<N: Network> Transactions<N> {
pub fn from(transactions: &[ConfirmedTransaction<N>]) -> Self {
Self::from_iter(transactions.iter())
}
}
impl<N: Network> FromIterator<ConfirmedTransaction<N>> for Transactions<N> {
fn from_iter<T: IntoIterator<Item = ConfirmedTransaction<N>>>(iter: T) -> Self {
Self { transactions: iter.into_iter().map(|transaction| (transaction.id(), transaction)).collect() }
}
}
impl<'a, N: Network> FromIterator<&'a ConfirmedTransaction<N>> for Transactions<N> {
fn from_iter<T: IntoIterator<Item = &'a ConfirmedTransaction<N>>>(iter: T) -> Self {
Self::from_iter(iter.into_iter().cloned())
}
}
impl<N: Network> Transactions<N> {
pub fn get(&self, transaction_id: &N::TransactionID) -> Option<&ConfirmedTransaction<N>> {
self.transactions.get(transaction_id)
}
pub fn is_empty(&self) -> bool {
self.transactions.is_empty()
}
pub fn len(&self) -> usize {
self.transactions.len()
}
pub fn num_accepted(&self) -> usize {
cfg_values!(self.transactions).filter(|tx| tx.is_accepted()).count()
}
pub fn num_rejected(&self) -> usize {
cfg_values!(self.transactions).filter(|tx| tx.is_rejected()).count()
}
pub fn num_finalize(&self) -> usize {
cfg_values!(self.transactions).map(|tx| tx.num_finalize()).sum()
}
}
impl<N: Network> Transactions<N> {
pub fn contains_transition(&self, transition_id: &N::TransitionID) -> bool {
cfg_values!(self.transactions).any(|tx| tx.contains_transition(transition_id))
}
pub fn contains_serial_number(&self, serial_number: &Field<N>) -> bool {
cfg_values!(self.transactions).any(|tx| tx.contains_serial_number(serial_number))
}
pub fn contains_commitment(&self, commitment: &Field<N>) -> bool {
cfg_values!(self.transactions).any(|tx| tx.contains_commitment(commitment))
}
}
impl<N: Network> Transactions<N> {
pub fn find_confirmed_transaction_for_unconfirmed_transaction_id(
&self,
unconfirmed_transaction_id: &N::TransactionID,
) -> Option<&ConfirmedTransaction<N>> {
cfg_find!(self.transactions, unconfirmed_transaction_id, contains_unconfirmed_transaction_id)
}
pub fn find_transaction_for_transition_id(&self, transition_id: &N::TransitionID) -> Option<&Transaction<N>> {
cfg_find!(self.transactions, transition_id, contains_transition).map(|tx| tx.transaction())
}
pub fn find_transaction_for_serial_number(&self, serial_number: &Field<N>) -> Option<&Transaction<N>> {
cfg_find!(self.transactions, serial_number, contains_serial_number).map(|tx| tx.transaction())
}
pub fn find_transaction_for_commitment(&self, commitment: &Field<N>) -> Option<&Transaction<N>> {
cfg_find!(self.transactions, commitment, contains_commitment).map(|tx| tx.transaction())
}
pub fn find_transition(&self, transition_id: &N::TransitionID) -> Option<&Transition<N>> {
cfg_find_map!(self.transactions, transition_id, find_transition)
}
pub fn find_transition_for_serial_number(&self, serial_number: &Field<N>) -> Option<&Transition<N>> {
cfg_find_map!(self.transactions, serial_number, find_transition_for_serial_number)
}
pub fn find_transition_for_commitment(&self, commitment: &Field<N>) -> Option<&Transition<N>> {
cfg_find_map!(self.transactions, commitment, find_transition_for_commitment)
}
pub fn find_record(&self, commitment: &Field<N>) -> Option<&Record<N, Ciphertext<N>>> {
cfg_find_map!(self.transactions, commitment, find_record)
}
}
impl<N: Network> Transactions<N> {
pub const MAX_TRANSACTIONS: usize = usize::pow(2, TRANSACTIONS_DEPTH as u32);
pub fn iter(&self) -> impl '_ + ExactSizeIterator<Item = &ConfirmedTransaction<N>> {
self.transactions.values()
}
#[cfg(not(feature = "serial"))]
pub fn par_iter(&self) -> impl '_ + ParallelIterator<Item = &ConfirmedTransaction<N>> {
self.transactions.par_values()
}
pub fn transaction_ids(&self) -> impl '_ + ExactSizeIterator<Item = &N::TransactionID> {
self.transactions.keys()
}
pub fn deployments(&self) -> impl '_ + Iterator<Item = &ConfirmedTransaction<N>> {
self.iter().filter(|tx| tx.is_accepted() && tx.is_deploy())
}
pub fn executions(&self) -> impl '_ + Iterator<Item = &ConfirmedTransaction<N>> {
self.iter().filter(|tx| tx.is_accepted() && tx.is_execute())
}
pub fn transitions(&self) -> impl '_ + Iterator<Item = &Transition<N>> {
self.iter().flat_map(|tx| tx.transitions())
}
pub fn transition_ids(&self) -> impl '_ + Iterator<Item = &N::TransitionID> {
self.iter().flat_map(|tx| tx.transition_ids())
}
pub fn transition_public_keys(&self) -> impl '_ + Iterator<Item = &Group<N>> {
self.iter().flat_map(|tx| tx.transition_public_keys())
}
pub fn transition_commitments(&self) -> impl '_ + Iterator<Item = &Field<N>> {
self.iter().flat_map(|tx| tx.transition_commitments())
}
pub fn tags(&self) -> impl '_ + Iterator<Item = &Field<N>> {
self.iter().flat_map(|tx| tx.tags())
}
pub fn input_ids(&self) -> impl '_ + Iterator<Item = &Field<N>> {
self.iter().flat_map(|tx| tx.input_ids())
}
pub fn serial_numbers(&self) -> impl '_ + Iterator<Item = &Field<N>> {
self.iter().flat_map(|tx| tx.serial_numbers())
}
pub fn output_ids(&self) -> impl '_ + Iterator<Item = &Field<N>> {
self.iter().flat_map(|tx| tx.output_ids())
}
pub fn commitments(&self) -> impl '_ + Iterator<Item = &Field<N>> {
self.iter().flat_map(|tx| tx.commitments())
}
pub fn records(&self) -> impl '_ + Iterator<Item = (&Field<N>, &Record<N, Ciphertext<N>>)> {
self.iter().flat_map(|tx| tx.records())
}
pub fn nonces(&self) -> impl '_ + Iterator<Item = &Group<N>> {
self.iter().flat_map(|tx| tx.nonces())
}
pub fn transaction_fee_amounts(&self) -> impl '_ + Iterator<Item = Result<U64<N>>> {
self.iter().map(|tx| tx.fee_amount())
}
pub fn finalize_operations(&self) -> impl '_ + Iterator<Item = &FinalizeOperation<N>> {
self.iter().flat_map(|tx| tx.finalize_operations())
}
}
impl<N: Network> IntoIterator for Transactions<N> {
type IntoIter = indexmap::map::IntoValues<N::TransactionID, Self::Item>;
type Item = ConfirmedTransaction<N>;
fn into_iter(self) -> Self::IntoIter {
self.transactions.into_values()
}
}
impl<N: Network> Transactions<N> {
pub fn into_transaction_ids(self) -> impl ExactSizeIterator<Item = N::TransactionID> {
self.transactions.into_keys()
}
pub fn into_deployments(self) -> impl Iterator<Item = ConfirmedTransaction<N>> {
self.into_iter().filter(|tx| tx.is_accepted() && tx.is_deploy())
}
pub fn into_executions(self) -> impl Iterator<Item = ConfirmedTransaction<N>> {
self.into_iter().filter(|tx| tx.is_accepted() && tx.is_execute())
}
pub fn into_transitions(self) -> impl Iterator<Item = Transition<N>> {
self.into_iter().flat_map(|tx| tx.into_transaction().into_transitions())
}
pub fn into_transition_ids(self) -> impl Iterator<Item = N::TransitionID> {
self.into_iter().flat_map(|tx| tx.into_transaction().into_transition_ids())
}
pub fn into_transition_public_keys(self) -> impl Iterator<Item = Group<N>> {
self.into_iter().flat_map(|tx| tx.into_transaction().into_transition_public_keys())
}
pub fn into_tags(self) -> impl Iterator<Item = Field<N>> {
self.into_iter().flat_map(|tx| tx.into_transaction().into_tags())
}
pub fn into_serial_numbers(self) -> impl Iterator<Item = Field<N>> {
self.into_iter().flat_map(|tx| tx.into_transaction().into_serial_numbers())
}
pub fn into_commitments(self) -> impl Iterator<Item = Field<N>> {
self.into_iter().flat_map(|tx| tx.into_transaction().into_commitments())
}
pub fn into_records(self) -> impl Iterator<Item = (Field<N>, Record<N, Ciphertext<N>>)> {
self.into_iter().flat_map(|tx| tx.into_transaction().into_records())
}
pub fn into_nonces(self) -> impl Iterator<Item = Group<N>> {
self.into_iter().flat_map(|tx| tx.into_transaction().into_nonces())
}
}
#[cfg(test)]
pub mod test_helpers {
use super::*;
type CurrentNetwork = console::network::Testnet3;
pub(crate) fn sample_block_transactions(rng: &mut TestRng) -> Transactions<CurrentNetwork> {
crate::test_helpers::sample_genesis_block(rng).transactions().clone()
}
}
#[cfg(test)]
mod tests {
use super::*;
type CurrentNetwork = console::network::Testnet3;
#[test]
fn test_max_transactions() {
assert_eq!(
Transactions::<CurrentNetwork>::MAX_TRANSACTIONS,
ledger_narwhal_batch_header::BatchHeader::<CurrentNetwork>::MAX_TRANSACTIONS
);
}
}