Add batch acquiring txs from RPC
MODIFY
WalletWasabi.Tests/UnitTests/BitcoinCore/RpcBasedTests.cs
WalletWasabi.Tests/UnitTests/BitcoinCore/RpcBasedTests.cs
using NBitcoin;
using NBitcoin.RPC;
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -273,5 +274,48 @@ namespace WalletWasabi.Tests.UnitTests.BitcoinCore
Assert.Equal(RpcPubkeyType.TxPubkeyhash, blockInfo.Transactions.ElementAt(1).Outputs.ElementAt(0).PubkeyType);
Assert.Equal(RpcPubkeyType.TxPubkeyhash, blockInfo.Transactions.ElementAt(1).Outputs.ElementAt(1).PubkeyType);
}
+
+ [Fact]
+ public async Task GetRawTransactionsAsync()
+ {
+ var coreNode = await TestNodeBuilder.CreateAsync();
+ try
+ {
+ var rpc = coreNode.RpcClient;
+ var txs = await rpc.GetRawTransactionsAsync(new[] { BitcoinFactory.CreateUint256(), BitcoinFactory.CreateUint256() }, CancellationToken.None);
+ Assert.Empty(txs);
+
+ await rpc.CreateWalletAsync("wallet");
+ await rpc.GenerateAsync(101);
+ var txid = await rpc.SendToAddressAsync(BitcoinFactory.CreateScript().GetDestinationAddress(Network.RegTest), Money.Coins(1));
+
+ txs = await rpc.GetRawTransactionsAsync(new[] { txid }, CancellationToken.None);
+ Assert.Single(txs);
+
+ List<uint256> txids = new();
+ for (int i = 0; i < 2; i++)
+ {
+ var txid2 = await rpc.SendToAddressAsync(BitcoinFactory.CreateScript().GetDestinationAddress(Network.RegTest), Money.Coins(1));
+ txids.Add(txid2);
+ }
+
+ txs = await rpc.GetRawTransactionsAsync(txids, CancellationToken.None);
+ Assert.Equal(2, txs.Count());
+
+ txids = new();
+ for (int i = 0; i < 20; i++)
+ {
+ var txid2 = await rpc.SendToAddressAsync(BitcoinFactory.CreateScript().GetDestinationAddress(Network.RegTest), Money.Coins(1));
+ txids.Add(txid2);
+ }
+
+ txs = await rpc.GetRawTransactionsAsync(txids, CancellationToken.None);
+ Assert.Equal(20, txs.Count());
+ }
+ finally
+ {
+ await coreNode.TryStopAsync();
+ }
+ }
}
}

MODIFY
WalletWasabi.Tests/UnitTests/MockRpcClient.cs
WalletWasabi.Tests/UnitTests/MockRpcClient.cs
using System;
+using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using NBitcoin;
@@ -90,6 +91,11 @@ namespace WalletWasabi.Tests.UnitTests
throw new NotImplementedException();
}
+ public Task<IEnumerable<Transaction>> GetRawTransactionsAsync(IEnumerable<uint256> txids, CancellationToken cancel)
+ {
+ throw new NotImplementedException();
+ }
+
public Task<GetTxOutResponse?> GetTxOutAsync(uint256 txid, int index, bool includeMempool = true)
{
var resp = OnGetTxOutAsync(txid, index, includeMempool);

MODIFY
WalletWasabi/BitcoinCore/Rpc/IRPCClient.cs
WalletWasabi/BitcoinCore/Rpc/IRPCClient.cs
using NBitcoin;
using NBitcoin.RPC;
using System;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using WalletWasabi.BitcoinCore.Rpc.Models;
@@ -58,6 +60,8 @@ namespace WalletWasabi.BitcoinCore.Rpc
Task<Transaction> GetRawTransactionAsync(uint256 txid, bool throwIfNotFound = true);
+ Task<IEnumerable<Transaction>> GetRawTransactionsAsync(IEnumerable<uint256> txids, CancellationToken cancel);
+
Task<int> GetBlockCountAsync();
Task<BitcoinAddress> GetNewAddressAsync();

MODIFY
WalletWasabi/BitcoinCore/Rpc/RpcClientBase.cs
WalletWasabi/BitcoinCore/Rpc/RpcClientBase.cs
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
+using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using WalletWasabi.BitcoinCore.Rpc.Models;
@@ -189,6 +190,34 @@ namespace WalletWasabi.BitcoinCore.Rpc
return await Rpc.GetRawTransactionAsync(txid, throwIfNotFound).ConfigureAwait(false);
}
+ public virtual async Task<IEnumerable<Transaction>> GetRawTransactionsAsync(IEnumerable<uint256> txids, CancellationToken cancel)
+ {
+ // 8 is half of the default rpcworkqueue
+ List<Transaction> retList = new();
+ foreach (var txidsChunk in txids.ChunkBy(8))
+ {
+ IRPCClient batchingRpc = PrepareBatch();
+ List<Task<Transaction>> tasks = new();
+ foreach (var txid in txidsChunk)
+ {
+ tasks.Add(batchingRpc.GetRawTransactionAsync(txid, throwIfNotFound: false));
+ }
+
+ await batchingRpc.SendBatchAsync().ConfigureAwait(false);
+
+ foreach (var tx in await Task.WhenAll(tasks).ConfigureAwait(false))
+ {
+ if (tx is not null)
+ {
+ retList.Add(tx);
+ }
+ cancel.ThrowIfCancellationRequested();
+ }
+ }
+
+ return retList;
+ }
+
public virtual async Task<int> GetBlockCountAsync()
{
return await Rpc.GetBlockCountAsync().ConfigureAwait(false);

Add batch acquiring txs from RPC