/// Select which unspent transaction outputs to use to send a transaction of the specified amount. Use the specified
/// selection strategy to choose the outputs. It also determines if a change output is required.
Select which unspent transaction outputs to use to send a transaction of the specified amount. Use the specified
selection strategy to choose the outputs. It also determines if a change output is required.
Select which unspent transaction outputs to use to send a transaction of the specified amount . Use the specified selection strategy to choose the outputs . It also determines if a change output is required .
async fn select_utxos(
        &mut self,
        amount: MicroTari,
        fee_per_gram: MicroTari,
        output_count: usize,
        strategy: Option<UTXOSelectionStrategy>,
    ) -> Result<(Vec<DbUnblindedOutput>, bool), OutputManagerError>
    {
        let mut utxos = Vec::new();
        let mut total = MicroTari::from(0);
        let mut fee_without_change = MicroTari::from(0);
        let mut fee_with_change = MicroTari::from(0);
        let uo = self.resources.db.fetch_sorted_unspent_outputs().await?;
        // Heuristic for selecting strategy: Default to MaturityThenSmallest, but if amount >
        // alpha * largest UTXO, use Largest
        let strategy = match (strategy, uo.is_empty()) {
            (Some(s), _) => s,
            (None, true) => UTXOSelectionStrategy::Smallest,
            (None, false) => {
                let largest_utxo = &uo[uo.len() - 1];
                if amount > largest_utxo.unblinded_output.value {
                    UTXOSelectionStrategy::Largest
                } else {
                    UTXOSelectionStrategy::MaturityThenSmallest
                }
            },
        };
        let uo = match strategy {
            UTXOSelectionStrategy::Smallest => uo,
            // TODO: We should pass in the current height and group
            // all funds less than the current height as maturity 0
            UTXOSelectionStrategy::MaturityThenSmallest => {
                let mut new_uo = uo;
                new_uo.sort_by(|a, b| {
                    match a
                        .unblinded_output
                        .features
                        .maturity
                        .cmp(&b.unblinded_output.features.maturity)
                    {
                        Ordering::Equal => a.unblinded_output.value.cmp(&b.unblinded_output.value),
                        Ordering::Less => Ordering::Less,
                        Ordering::Greater => Ordering::Greater,
                    }
                });
                new_uo
            },
            UTXOSelectionStrategy::Largest => uo.into_iter().rev().collect(),
        };
        let mut require_change_output = false;
        for o in uo.iter() {
            utxos.push(o.clone());
            total += o.unblinded_output.value;
            // I am assuming that the only output will be the payment output and change if required
            fee_without_change = Fee::calculate(fee_per_gram, 1, utxos.len(), output_count);
            if total == amount + fee_without_change {
                break;
            }
            fee_with_change = Fee::calculate(fee_per_gram, 1, utxos.len(), output_count + 1);
            if total >= amount + fee_with_change {
                require_change_output = true;
                break;
            }
        }
        if (total != amount + fee_without_change) && (total < amount + fee_with_change) {
            return Err(OutputManagerError::NotEnoughFunds);
        }
        Ok((utxos, require_change_output))
    }
async fn select_utxos ( & mut self , amount : MicroTari , fee_per_gram : MicroTari , output_count : usize , strategy : Option < UTXOSelectionStrategy > , ) -> Result < ( Vec < DbUnblindedOutput > , bool ) , OutputManagerError > { let mut utxos = Vec :: new ( ) ; let mut total = MicroTari :: from ( 0 ) ; let mut fee_without_change = MicroTari :: from ( 0 ) ; let mut fee_with_change = MicroTari :: from ( 0 ) ; let uo = self . resources . db . fetch_sorted_unspent_outputs ( ) . await ? ; // Heuristic for selecting strategy: Default to MaturityThenSmallest, but if amount > // alpha * largest UTXO, use Largest let strategy = match ( strategy , uo . is_empty ( ) ) { ( Some ( s ) , _ ) => s , ( None , true ) => UTXOSelectionStrategy :: Smallest , ( None , false ) => { let largest_utxo = & uo [ uo . len ( ) - 1 ] ; if amount > largest_utxo . unblinded_output . value { UTXOSelectionStrategy :: Largest } else { UTXOSelectionStrategy :: MaturityThenSmallest } } , } ; let uo = match strategy { UTXOSelectionStrategy :: Smallest => uo , // TODO: We should pass in the current height and group // all funds less than the current height as maturity 0 UTXOSelectionStrategy :: MaturityThenSmallest => { let mut new_uo = uo ; new_uo . sort_by ( | a , b | { match a . unblinded_output . features . maturity . cmp ( & b . unblinded_output . features . maturity ) { Ordering :: Equal => a . unblinded_output . value . cmp ( & b . unblinded_output . value ) , Ordering :: Less => Ordering :: Less , Ordering :: Greater => Ordering :: Greater , } } ) ; new_uo } , UTXOSelectionStrategy :: Largest => uo . into_iter ( ) . rev ( ) . collect ( ) , } ; let mut require_change_output = false ; for o in uo . iter ( ) { utxos . push ( o . clone ( ) ) ; total += o . unblinded_output . value ; // I am assuming that the only output will be the payment output and change if required fee_without_change = Fee :: calculate ( fee_per_gram , 1 , utxos . len ( ) , output_count ) ; if total == amount + fee_without_change { break ; } fee_with_change = Fee :: calculate ( fee_per_gram , 1 , utxos . len ( ) , output_count + 1 ) ; if total >= amount + fee_with_change { require_change_output = true ; break ; } } if ( total != amount + fee_without_change ) && ( total < amount + fee_with_change ) { return Err ( OutputManagerError :: NotEnoughFunds ) ; } Ok ( ( utxos , require_change_output ) ) }
Select which unspent transaction outputs to use to send a transaction of the specified amount.
Select which unspent transaction outputs to use to send a transaction of the specified amount .
&mut self
amount
MicroTari
fee_per_gram
MicroTari
output_count
usize
strategy
Option<UTXOSelectionStrategy>