Make RPC EstimateAllFee cancellable
MODIFY
WalletWasabi.Backend/Controllers/BlockchainController.cs
WalletWasabi.Backend/Controllers/BlockchainController.cs
@@ -6,6 +6,7 @@ using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
+using System.Threading;
using System.Threading.Tasks;
using WalletWasabi.Backend.Models;
using WalletWasabi.Backend.Models.Responses;
@@ -72,7 +73,7 @@ namespace WalletWasabi.Backend.Controllers
return await Cache.AtomicGetOrCreateAsync(
cacheKey,
cacheOptions,
- () => RpcClient.EstimateAllFeeAsync(mode, simulateIfRegTest: true));
+ () => RpcClient.EstimateAllFeeAsync(new CancellationToken(), mode, simulateIfRegTest: true));
}
/// <summary>

MODIFY
WalletWasabi.Tests/UnitTests/AllFeeEstimateTests.cs
WalletWasabi.Tests/UnitTests/AllFeeEstimateTests.cs
@@ -13,6 +13,7 @@ using WalletWasabi.Helpers;
using WalletWasabi.Tests.Helpers;
using Xunit;
using Moq;
+using System.Threading;
namespace WalletWasabi.Tests.UnitTests
{
@@ -155,7 +156,7 @@ namespace WalletWasabi.Tests.UnitTests
.ThrowsAsync(new NoEstimationException(1));
mockRpc.Setup(rpc => rpc.PrepareBatch()).Returns(mockRpc.Object);
- await Assert.ThrowsAsync<NoEstimationException>(async () => await mockRpc.Object.EstimateAllFeeAsync(EstimateSmartFeeMode.Conservative));
+ await Assert.ThrowsAsync<NoEstimationException>(async () => await mockRpc.Object.EstimateAllFeeAsync(new CancellationToken(), EstimateSmartFeeMode.Conservative));
}
[Fact]
@@ -176,7 +177,7 @@ namespace WalletWasabi.Tests.UnitTests
mockRpc.Setup(rpc => rpc.PrepareBatch()).Returns(mockRpc.Object);
- var ex = await Assert.ThrowsAsync<RPCException>(async () => await mockRpc.Object.EstimateAllFeeAsync(EstimateSmartFeeMode.Conservative));
+ var ex = await Assert.ThrowsAsync<RPCException>(async () => await mockRpc.Object.EstimateAllFeeAsync(new CancellationToken(), EstimateSmartFeeMode.Conservative));
Assert.Equal(RPCErrorCode.RPC_CLIENT_NOT_CONNECTED, ex.RPCCode);
Assert.Equal("Error-EstimateSmartFee", ex.Message);
}
@@ -193,7 +194,7 @@ namespace WalletWasabi.Tests.UnitTests
mockRpc.Setup(rpc => rpc.EstimateSmartFeeAsync(8, any)).ReturnsAsync(FeeRateResponse(8, 70m));
mockRpc.Setup(rpc => rpc.EstimateSmartFeeAsync(It.IsNotIn<int>(2, 3, 5, 6, 8), any)).ThrowsAsync(new NoEstimationException(0));
- var allFee = await mockRpc.Object.EstimateAllFeeAsync(EstimateSmartFeeMode.Conservative);
+ var allFee = await mockRpc.Object.EstimateAllFeeAsync(new CancellationToken(), EstimateSmartFeeMode.Conservative);
Assert.Equal(2, allFee.Estimations.Count);
Assert.False(allFee.Estimations.ContainsKey(3));
Assert.False(allFee.Estimations.ContainsKey(5));
@@ -217,7 +218,7 @@ namespace WalletWasabi.Tests.UnitTests
mockRpc.Setup(rpc => rpc.EstimateSmartFeeAsync(1008, any)).ReturnsAsync(FeeRateResponse(1008, 31m));
mockRpc.Setup(rpc => rpc.EstimateSmartFeeAsync(It.IsNotIn<int>(2, 3, 5, 6, 8, 11, 13, 15, 1008), any)).ThrowsAsync(new NoEstimationException(0));
- var allFee = await mockRpc.Object.EstimateAllFeeAsync(EstimateSmartFeeMode.Conservative);
+ var allFee = await mockRpc.Object.EstimateAllFeeAsync(new CancellationToken(), EstimateSmartFeeMode.Conservative);
Assert.True(allFee.IsAccurate);
Assert.Equal(3, allFee.Estimations.Count);
Assert.Equal(99, allFee.Estimations[2]);
@@ -253,7 +254,7 @@ namespace WalletWasabi.Tests.UnitTests
mockRpc.Setup(rpc => rpc.EstimateSmartFeeAsync(1008, any)).ReturnsAsync(FeeRateResponse(1008, 1m));
mockRpc.Setup(rpc => rpc.EstimateSmartFeeAsync(It.IsNotIn<int>(2, 3, 5, 6, 8, 11, 13, 15, 1008), any)).ThrowsAsync(new NoEstimationException(0));
- var allFee = await mockRpc.Object.EstimateAllFeeAsync(EstimateSmartFeeMode.Conservative);
+ var allFee = await mockRpc.Object.EstimateAllFeeAsync(new CancellationToken(), EstimateSmartFeeMode.Conservative);
Assert.Equal(3_500, allFee.Estimations[2]);
Assert.True(allFee.Estimations[3] > 500);
Assert.True(allFee.Estimations[1008] > 1);
@@ -269,7 +270,7 @@ namespace WalletWasabi.Tests.UnitTests
mockRpc.Setup(rpc => rpc.EstimateSmartFeeAsync(It.IsNotIn<int>(2), any)).ThrowsAsync(new NoEstimationException(0));
// Do not throw exception
- await mockRpc.Object.EstimateAllFeeAsync(EstimateSmartFeeMode.Conservative);
+ await mockRpc.Object.EstimateAllFeeAsync(new CancellationToken(), EstimateSmartFeeMode.Conservative);
}
[Fact]
@@ -281,7 +282,7 @@ namespace WalletWasabi.Tests.UnitTests
var mempoolInfo = MempoolInfoGenerator.GenerateMempoolInfo();
mockRpc.Setup(rpc => rpc.GetMempoolInfoAsync()).ReturnsAsync(mempoolInfo);
mockRpc.Setup(rpc => rpc.EstimateSmartFeeAsync(It.IsAny<int>(), EstimateSmartFeeMode.Conservative)).ReturnsAsync(FeeRateResponse(2, 120m));
- var feeRates = await mockRpc.Object.EstimateAllFeeAsync(EstimateSmartFeeMode.Conservative);
+ var feeRates = await mockRpc.Object.EstimateAllFeeAsync(new CancellationToken(), EstimateSmartFeeMode.Conservative);
var estimations = feeRates.Estimations;
Assert.Subset(Constants.ConfirmationTargets.ToHashSet(), estimations.Keys.ToHashSet());

MODIFY
WalletWasabi.Tests/UnitTests/BitcoinCore/RpcBasedTests.cs
WalletWasabi.Tests/UnitTests/BitcoinCore/RpcBasedTests.cs
@@ -156,12 +156,12 @@ namespace WalletWasabi.Tests.UnitTests.BitcoinCore
try
{
var rpc = coreNode.RpcClient;
- var estimations = await rpc.EstimateAllFeeAsync(EstimateSmartFeeMode.Conservative, simulateIfRegTest: true);
+ var estimations = await rpc.EstimateAllFeeAsync(new CancellationToken(), EstimateSmartFeeMode.Conservative, simulateIfRegTest: true);
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);
+ estimations = await rpc.EstimateAllFeeAsync(new CancellationToken(), EstimateSmartFeeMode.Economical, simulateIfRegTest: true);
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);

MODIFY
WalletWasabi/BitcoinCore/Monitoring/RpcFeeProvider.cs
WalletWasabi/BitcoinCore/Monitoring/RpcFeeProvider.cs
@@ -29,7 +29,7 @@ namespace WalletWasabi.BitcoinCore.Monitoring
{
try
{
- var allFeeEstimate = await RpcClient.EstimateAllFeeAsync(EstimateSmartFeeMode.Conservative, true).ConfigureAwait(false);
+ var allFeeEstimate = await RpcClient.EstimateAllFeeAsync(cancel, EstimateSmartFeeMode.Conservative, true).ConfigureAwait(false);
// If Core was running for a day already && it's synchronized, then we can be pretty sure that the estimate is accurate.
// It could also be accurate if Core was only shut down for a few minutes, but that's hard to figure out.

MODIFY
WalletWasabi/Extensions/RPCClientExtensions.cs
WalletWasabi/Extensions/RPCClientExtensions.cs
@@ -68,7 +68,7 @@ namespace NBitcoin.RPC
/// <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)
+ public static async Task<AllFeeEstimate> EstimateAllFeeAsync(this IRPCClient rpc, CancellationToken cancel, EstimateSmartFeeMode estimateMode = EstimateSmartFeeMode.Conservative, bool simulateIfRegTest = false)
{
var smartEstimations = (simulateIfRegTest && rpc.Network == Network.RegTest)
? SimulateRegTestFeeEstimation(estimateMode)

Make RPC EstimateAllFee cancellable