iuna

iuna

iuna - experimental devnet protocol
git clone https://getiuna.org/git/iuna.git
Log | Files | Refs | README | LICENSE

ledger_mempool.rs (4511B)


      1 use anyhow::{Result, bail};
      2 
      3 use super::ledger_ops::{
      4     apply_transaction, ensure_blinded_transaction_fits_empty_block,
      5     ensure_transaction_fits_empty_block, spend_blinded_inputs, spend_inputs,
      6     transaction_has_missing_inputs,
      7 };
      8 use super::transaction::{
      9     BlindedReveal, BlindedTransaction, Transaction, blinded_transaction_inputs_spent_by,
     10     transaction_inputs_spent_by, transaction_inputs_spent_by_inputs,
     11 };
     12 use super::{Ledger, MAX_ORPHAN_TRANSACTIONS, MAX_PENDING_TRANSACTIONS, TransactionSubmitOutcome};
     13 
     14 impl Ledger {
     15     pub fn submit_transaction(&mut self, transaction: Transaction) -> Result<bool> {
     16         Ok(self.submit_transaction_with_outcome(transaction)?.added())
     17     }
     18 
     19     pub(crate) fn reserve_transaction_inputs(&mut self, transaction: &Transaction) -> Result<()> {
     20         self.validate_new_transaction(transaction)?;
     21         let mut utxos = self.utxos.clone();
     22         spend_inputs(transaction, &mut utxos)?;
     23         self.utxos = utxos;
     24         Ok(())
     25     }
     26 
     27     pub fn submit_blinded_transaction(&mut self, transaction: BlindedTransaction) -> Result<bool> {
     28         if self.has_blinded_transaction(&transaction.commitment) {
     29             return Ok(false);
     30         }
     31         self.validate_blinded_transaction(&transaction)?;
     32         ensure_blinded_transaction_fits_empty_block(
     33             &transaction,
     34             self.launch_profile.max_block_bytes,
     35         )?;
     36         if blinded_transaction_inputs_spent_by(&transaction, &self.pending_blinded)
     37             || transaction_inputs_spent_by_inputs(&transaction.inputs, &self.pending)
     38             || transaction_inputs_spent_by_inputs(&transaction.inputs, &self.orphans)
     39         {
     40             bail!("blinded transaction conflicts with pending inputs");
     41         }
     42         let mut utxos = self.utxos_after_valid_pending_and_blinded()?;
     43         spend_blinded_inputs(&transaction, &mut utxos)?;
     44         if self.pending_blinded.len() >= MAX_PENDING_TRANSACTIONS {
     45             bail!("blinded mempool is full");
     46         }
     47         self.pending_blinded.push(transaction);
     48         Ok(true)
     49     }
     50 
     51     pub fn submit_blinded_reveal(&mut self, reveal: BlindedReveal) -> Result<bool> {
     52         if self.has_blinded_reveal(&reveal.commitment) {
     53             return Ok(false);
     54         }
     55         self.validate_blinded_reveal_terms(&reveal)?;
     56         if self.pending_reveals.len() >= MAX_PENDING_TRANSACTIONS
     57             && (!self.has_active_blinded_transaction(&reveal.commitment)
     58                 || !self.drop_one_invalid_pending_blinded_reveal())
     59         {
     60             bail!("blinded reveal pool is full");
     61         }
     62         self.pending_reveals.push(reveal);
     63         Ok(true)
     64     }
     65 
     66     fn drop_one_invalid_pending_blinded_reveal(&mut self) -> bool {
     67         let Some(index) = self
     68             .pending_reveals
     69             .iter()
     70             .position(|reveal| self.pending_reveal_transaction(reveal).is_err())
     71         else {
     72             return false;
     73         };
     74         self.pending_reveals.remove(index);
     75         true
     76     }
     77 
     78     pub fn submit_transaction_with_outcome(
     79         &mut self,
     80         transaction: Transaction,
     81     ) -> Result<TransactionSubmitOutcome> {
     82         if self.has_transaction(transaction.signature()) {
     83             return Ok(TransactionSubmitOutcome::AlreadyKnown);
     84         }
     85 
     86         transaction.verify_signature()?;
     87         self.validate_transaction_terms(&transaction)?;
     88         ensure_transaction_fits_empty_block(&transaction, self.launch_profile.max_block_bytes)?;
     89         self.validate_mine_anchor_available(&transaction)?;
     90 
     91         if transaction_inputs_spent_by(&transaction, &self.pending) {
     92             return Ok(TransactionSubmitOutcome::ConflictsWithPending);
     93         }
     94         if transaction_inputs_spent_by(&transaction, &self.orphans) {
     95             return Ok(TransactionSubmitOutcome::ConflictsWithPending);
     96         }
     97 
     98         if self.pending.len() >= MAX_PENDING_TRANSACTIONS {
     99             bail!("mempool is full");
    100         }
    101 
    102         let mut utxos = self.utxos_after_valid_pending_and_blinded()?;
    103         if transaction_has_missing_inputs(&transaction, &utxos) {
    104             if self.orphans.len() >= MAX_ORPHAN_TRANSACTIONS {
    105                 bail!("orphan transaction pool is full");
    106             }
    107             self.orphans.push(transaction);
    108             return Ok(TransactionSubmitOutcome::Added);
    109         }
    110         apply_transaction(&transaction, &mut utxos)?;
    111         self.pending.push(transaction);
    112         self.promote_orphan_transactions()?;
    113         Ok(TransactionSubmitOutcome::Added)
    114     }
    115 }