Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: fee estimate #4656

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
23 changes: 21 additions & 2 deletions base_layer/wallet/src/output_manager_service/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -865,15 +865,34 @@ where
Covenant::new().consensus_encode_exact_size(),
);

let utxo_selection = self
let utxo_selection = match self
.select_utxos(
amount,
selection_criteria,
fee_per_gram,
num_outputs,
metadata_byte_size * num_outputs,
)
.await?;
.await
{
Ok(v) => Ok(v),
Err(OutputManagerError::FundsPending | OutputManagerError::NotEnoughFunds) => {
debug!(
target: LOG_TARGET,
"We dont have enough funds available to make a fee estimate, so we estimate 1 input, no change"
);
let fee_calc = self.get_fee_calc();
let output_features_estimate = OutputFeatures::default();
let default_metadata_size = fee_calc.weighting().round_up_metadata_size(
output_features_estimate.consensus_encode_exact_size() +
Covenant::new().consensus_encode_exact_size() +
script![Nop].consensus_encode_exact_size(),
);
let fee = fee_calc.calculate(fee_per_gram, 1, 1, num_outputs, default_metadata_size);
return Ok(Fee::normalize(fee));
},
Err(e) => Err(e),
}?;

debug!(target: LOG_TARGET, "{} utxos selected.", utxo_selection.utxos.len());

Expand Down
30 changes: 12 additions & 18 deletions base_layer/wallet/tests/output_manager_service_tests/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ async fn fee_estimate() {
}

// not enough funds
let err = oms
let fee = oms
.output_manager_handle
.fee_estimate(
MicroTari::from(2750),
Expand All @@ -407,8 +407,8 @@ async fn fee_estimate() {
1,
)
.await
.unwrap_err();
assert!(matches!(err, OutputManagerError::NotEnoughFunds));
.unwrap();
assert_eq!(fee, MicroTari::from(360));
}

#[allow(clippy::identity_op)]
Expand Down Expand Up @@ -496,23 +496,19 @@ async fn test_utxo_selection_no_chain_metadata() {
let expected_fee = fee_calc.calculate(fee_per_gram, 1, 1, 3, default_metadata_byte_size() * 3);
assert_eq!(fee, expected_fee);

// test if a fee estimate would be possible with pending funds included
// at this point 52000 uT is still spendable, with pending change incoming of 1690 uT
// so instead of returning "not enough funds".to_string(), return "funds pending"
let spendable_amount = (3..=10).sum::<u64>() * amount;
let err = oms
let fee = oms
.fee_estimate(spendable_amount, UtxoSelectionCriteria::default(), fee_per_gram, 1, 2)
.await
.unwrap_err();
assert!(matches!(err, OutputManagerError::FundsPending));
.unwrap();
assert_eq!(fee, MicroTari::from(250));

// test not enough funds
let broke_amount = spendable_amount + MicroTari::from(2000);
let err = oms
let fee = oms
.fee_estimate(broke_amount, UtxoSelectionCriteria::default(), fee_per_gram, 1, 2)
.await
.unwrap_err();
assert!(matches!(err, OutputManagerError::NotEnoughFunds));
.unwrap();
assert_eq!(fee, MicroTari::from(250));

// coin split uses the "Largest" selection strategy
let (_, tx, utxos_total_value) = oms.create_coin_split(vec![], amount, 5, fee_per_gram).await.unwrap();
Expand Down Expand Up @@ -593,14 +589,12 @@ async fn test_utxo_selection_with_chain_metadata() {
let expected_fee = fee_calc.calculate(fee_per_gram, 1, 2, 3, default_metadata_byte_size() * 3);
assert_eq!(fee, expected_fee);

// test fee estimates are maturity aware
// even though we have utxos for the fee, they can't be spent because they are not mature yet
let spendable_amount = (1..=6).sum::<u64>() * amount;
let err = oms
let fee = oms
.fee_estimate(spendable_amount, UtxoSelectionCriteria::default(), fee_per_gram, 1, 2)
.await
.unwrap_err();
assert!(matches!(err, OutputManagerError::NotEnoughFunds));
.unwrap();
assert_eq!(fee, MicroTari::from(250));

// test coin split is maturity aware
let (_, tx, utxos_total_value) = oms.create_coin_split(vec![], amount, 5, fee_per_gram).await.unwrap();
Expand Down