Fetch FeeRates for specific confirmation targets
It request fee rates to the bitcoin node for confirmation in 7 time
frames: 20mins, 30mins, 1hr, 3hrs, 6hrs, 12hrs, 1day, 3days and
1week.
This reduces drastically the number of rpc requests performed against
the rpc interface. This will be improved in future commits.
MODIFY
WalletWasabi.Tests/UnitTests/BitcoinCore/RpcBasedTests.cs
WalletWasabi.Tests/UnitTests/BitcoinCore/RpcBasedTests.cs
@@ -159,12 +159,12 @@ namespace WalletWasabi.Tests.UnitTests.BitcoinCore
{
var rpc = coreNode.RpcClient;
var estimations = await rpc.EstimateAllFeeAsync(EstimateSmartFeeMode.Conservative, simulateIfRegTest: true);
- Assert.Equal(143, estimations.Estimations.Count);
+ Assert.Equal(7, estimations.Estimations.Count);
Assert.True(estimations.Estimations.First().Key < estimations.Estimations.Last().Key);
Assert.True(estimations.Estimations.First().Value > estimations.Estimations.Last().Value);
Assert.Equal(EstimateSmartFeeMode.Conservative, estimations.Type);
estimations = await rpc.EstimateAllFeeAsync(EstimateSmartFeeMode.Economical, simulateIfRegTest: true);
- Assert.Equal(143, estimations.Estimations.Count);
+ Assert.Equal(7, estimations.Estimations.Count);
Assert.True(estimations.Estimations.First().Key < estimations.Estimations.Last().Key);
Assert.True(estimations.Estimations.First().Value > estimations.Estimations.Last().Value);
Assert.Equal(EstimateSmartFeeMode.Economical, estimations.Type);

MODIFY
WalletWasabi/Extensions/RPCClientExtensions.cs
WalletWasabi/Extensions/RPCClientExtensions.cs
@@ -59,14 +59,24 @@ namespace NBitcoin.RPC
return null;
}
+ /// <summary>
+ /// Estimates fees for 1w, 3d, 1d, 12h, 6h, 3h, 1h, 30m, 20m.
+ /// </summary>
public static async Task<AllFeeEstimate> EstimateAllFeeAsync(this IRPCClient rpc, EstimateSmartFeeMode estimateMode = EstimateSmartFeeMode.Conservative, bool simulateIfRegTest = false)
{
var rpcStatus = await rpc.GetRpcStatusAsync(CancellationToken.None).ConfigureAwait(false);
var mempoolInfo = await rpc.GetMempoolInfoAsync().ConfigureAwait(false);
var sanityFeeRate = mempoolInfo.GetSanityFeeRate();
- var estimations = await rpc.EstimateHalfFeesAsync(new Dictionary<int, int>(), 2, 0, Constants.SevenDaysConfirmationTarget, 0, sanityFeeRate, estimateMode, simulateIfRegTest).ConfigureAwait(false);
- var allFeeEstimate = new AllFeeEstimate(estimateMode, estimations, rpcStatus.Synchronized);
- return allFeeEstimate;
+
+ var estimations = new Dictionary<int, int>();
+ foreach (var target in Constants.ConfirmationTargets)
+ {
+ var rate = await rpc.EstimateSmartFeeAsync(target, sanityFeeRate, estimateMode, simulateIfRegTest).ConfigureAwait(false);
+ estimations.Add(target, (int)Math.Ceiling(rate.FeeRate.SatoshiPerByte));
+ }
+
+ var bestFeeEstimates = new AllFeeEstimate(estimateMode, estimations, rpcStatus.Synchronized);
+ return bestFeeEstimates;
}
public static async Task<RpcStatus> GetRpcStatusAsync(this IRPCClient rpc, CancellationToken cancel)
@@ -86,64 +96,6 @@ namespace NBitcoin.RPC
}
}
- private static async Task<Dictionary<int, int>> EstimateHalfFeesAsync(this IRPCClient rpc, IDictionary<int, int> estimations, int smallTarget, int smallTargetFee, int largeTarget, int largeTargetFee, FeeRate sanityFeeRate, EstimateSmartFeeMode estimateMode = EstimateSmartFeeMode.Conservative, bool simulateIfRegTest = false)
- {
- var newEstimations = new Dictionary<int, int>();
- foreach (var est in estimations)
- {
- newEstimations.TryAdd(est.Key, est.Value);
- }
-
- if (Math.Abs(smallTarget - largeTarget) <= 1)
- {
- return newEstimations;
- }
-
- if (smallTargetFee == 0)
- {
- var smallTargetFeeResult = await rpc.EstimateSmartFeeAsync(smallTarget, sanityFeeRate, estimateMode, simulateIfRegTest).ConfigureAwait(false);
- smallTargetFee = (int)Math.Ceiling(smallTargetFeeResult.FeeRate.SatoshiPerByte);
- newEstimations.TryAdd(smallTarget, smallTargetFee);
- }
-
- if (largeTargetFee == 0)
- {
- var largeTargetFeeResult = await rpc.EstimateSmartFeeAsync(largeTarget, sanityFeeRate, estimateMode, simulateIfRegTest).ConfigureAwait(false);
- largeTargetFee = (int)Math.Ceiling(largeTargetFeeResult.FeeRate.SatoshiPerByte);
-
- // Blocks should never be larger than the target that we asked for, so it's just a sanity check.
- largeTarget = Math.Min(largeTarget, largeTargetFeeResult.Blocks);
- newEstimations.TryAdd(largeTarget, largeTargetFee);
- }
-
- int halfTarget = (smallTarget + largeTarget) / 2;
- var halfFeeResult = await rpc.EstimateSmartFeeAsync(halfTarget, sanityFeeRate, estimateMode, simulateIfRegTest).ConfigureAwait(false);
- int halfTargetFee = (int)Math.Ceiling(halfFeeResult.FeeRate.SatoshiPerByte);
-
- // Blocks should never be larger than the target that we asked for, so it's just a sanity check.
- halfTarget = Math.Min(halfTarget, halfFeeResult.Blocks);
- newEstimations.TryAdd(halfTarget, halfTargetFee);
-
- if (smallTargetFee > halfTargetFee)
- {
- var smallEstimations = await rpc.EstimateHalfFeesAsync(newEstimations, smallTarget, smallTargetFee, halfTarget, halfTargetFee, sanityFeeRate, estimateMode, simulateIfRegTest).ConfigureAwait(false);
- foreach (var est in smallEstimations)
- {
- newEstimations.TryAdd(est.Key, est.Value);
- }
- }
- if (largeTargetFee < halfTargetFee)
- {
- var largeEstimations = await rpc.EstimateHalfFeesAsync(newEstimations, halfTarget, halfTargetFee, largeTarget, largeTargetFee, sanityFeeRate, estimateMode, simulateIfRegTest).ConfigureAwait(false);
- foreach (var est in largeEstimations)
- {
- newEstimations.TryAdd(est.Key, est.Value);
- }
- }
-
- return newEstimations;
- }
-
public static async Task<(bool accept, string rejectReason)> TestMempoolAcceptAsync(this IRPCClient rpc, IEnumerable<Coin> coins, int fakeOutputCount, Money feePerInputs, Money feePerOutputs)
{
// Check if mempool would accept a fake transaction created with the registered inputs.

MODIFY
WalletWasabi/Helpers/Constants.cs
WalletWasabi/Helpers/Constants.cs
@@ -92,6 +92,19 @@ namespace WalletWasabi.Helpers
"/Satoshi:0.16.0/",
};
+ public static readonly int[] ConfirmationTargets = new[]
+ {
+ 2, // Twenty Minutes
+ 3, // Thirty Minutes
+ 6, // One Hour
+ 18, // Three Hours
+ 36, // Six Hours
+ 72, // Twelve Hours
+ 144, // One Day
+ 432, // Three Days
+ 1008, // Seven Days
+ };
+
public static readonly int RangeProofWidth = (int)Math.Log2(MaximumNumberOfSatoshis);
public static Money MinimumCredentailAmount = Money.Satoshis(10_000);

Fetch FeeRates for specific confirmation targets

It request fee rates to the bitcoin node for confirmation in 7 time
frames: 20mins, 30mins, 1hr, 3hrs, 6hrs, 12hrs, 1day, 3days and
1week.

This reduces drastically the number of rpc requests performed against
the rpc interface. This will be improved in future commits.