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 }