Create RpcParser and add one more verbose test
MODIFY
WalletWasabi.Tests/UnitTests/BitcoinCore/RpcBasedTests.cs
WalletWasabi.Tests/UnitTests/BitcoinCore/RpcBasedTests.cs
using NBitcoin;
using NBitcoin.RPC;
-using System.IO;
using System.Linq;
-using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using WalletWasabi.BitcoinCore;
using WalletWasabi.Services;
using WalletWasabi.Tests.Helpers;
using Xunit;
@@ -48,14 +47,26 @@ namespace WalletWasabi.Tests.UnitTests.BitcoinCore
[Fact]
public async Task VerboseBlockInfoAsync()
{
- var rpc = new MockRpcClient();
- rpc.OnSendCommandAsync = (op, p) =>
+ using var services = new HostedServices();
+ var coreNode = await TestNodeBuilder.CreateAsync(services);
+ await services.StartAllAsync(CancellationToken.None);
+ try
{
- var byteArray = Encoding.ASCII.GetBytes(RpcOutput);
- var stream = new MemoryStream(byteArray);
- return Task.FromResult(RPCResponse.Load(stream));
- };
- var blockInfo = await rpc.GetVerboseBlockAsync(uint256.One);
+ var rpc = coreNode.RpcClient;
+ var blockInfo = await rpc.GetVerboseBlockAsync(coreNode.Network.GenesisHash);
+ Assert.NotNull(blockInfo.Transactions.ElementAt(0).Inputs.ElementAt(0).Coinbase);
+ }
+ finally
+ {
+ await services.StopAllAsync(CancellationToken.None);
+ await coreNode.TryStopAsync();
+ }
+ }
+
+ [Fact]
+ public async Task ParseVerboseBlockInfoAsync()
+ {
+ var blockInfo = RpcParser.ParseVerboseBlockResponse(RpcOutput);
Assert.Equal(2, blockInfo.Transactions.Count());
Assert.Equal(1, blockInfo.Transactions.ElementAt(0).Inputs.Count());
Assert.Equal(2, blockInfo.Transactions.ElementAt(0).Outputs.Count());
@@ -72,8 +83,6 @@ namespace WalletWasabi.Tests.UnitTests.BitcoinCore
#region Mocked RPC response
public const string RpcOutput = @"
- {
- 'result':
{
'hash': '27cac34bec2bfc3422c352d558b4db29e6d7e8114db2dbc955df06a63cda82fe',
'confirmations': 1,
@@ -203,7 +212,6 @@ namespace WalletWasabi.Tests.UnitTests.BitcoinCore
'chainwork': '00000000000000000000000000000000000000000000000000000000000000ce',
'nTx': 2,
'previousblockhash': '1d434df0cdd3fe26535ebe9734ef013b036441be38921606a9336ce74ab1cf04'
- }
}";
#endregion Mocked RPC response

MODIFY
WalletWasabi.Tests/UnitTests/MockRpcClient.cs
WalletWasabi.Tests/UnitTests/MockRpcClient.cs
@@ -12,8 +12,6 @@ namespace WalletWasabi.Tests.UnitTests
public Func<uint256, Task<Block>> OnGetBlockAsync { get; set; }
public Func<uint256, Task<BlockHeader>> OnGetBlockHeaderAsync { get; set; }
- public Func<RPCOperations, object[], Task<RPCResponse>> OnSendCommandAsync { get; set; }
-
public Network Network => Network.RegTest;
public RPCCredentialString CredentialString => new RPCCredentialString();
@@ -113,6 +111,11 @@ namespace WalletWasabi.Tests.UnitTests
throw new NotImplementedException();
}
+ public Task<VerboseBlockInfo> GetVerboseBlockAsync(uint256 blockId)
+ {
+ throw new NotImplementedException();
+ }
+
public Task<uint256> SendRawTransactionAsync(Transaction transaction)
{
throw new NotImplementedException();
@@ -162,10 +165,5 @@ namespace WalletWasabi.Tests.UnitTests
{
throw new NotImplementedException();
}
-
- public Task<RPCResponse> SendCommandAsync(RPCOperations operation, params object[] p)
- {
- return OnSendCommandAsync(operation, p);
- }
}
}

MODIFY
WalletWasabi/BitcoinCore/IRPCClient.cs
WalletWasabi/BitcoinCore/IRPCClient.cs
@@ -68,6 +68,6 @@ namespace WalletWasabi.BitcoinCore
Task<EstimateSmartFeeResponse> TryEstimateSmartFeeAsync(int confirmationTarget, EstimateSmartFeeMode estimateMode = EstimateSmartFeeMode.Conservative);
- Task<RPCResponse> SendCommandAsync(RPCOperations operations, params object[] parameters);
+ Task<VerboseBlockInfo> GetVerboseBlockAsync(uint256 blockId);
}
}

MODIFY
WalletWasabi/BitcoinCore/RpcClientBase.cs
WalletWasabi/BitcoinCore/RpcClientBase.cs
@@ -99,9 +99,10 @@ namespace WalletWasabi.BitcoinCore
return new RpcClientBase(Rpc.PrepareBatch());
}
- public virtual Task<RPCResponse> SendCommandAsync(RPCOperations operations, params object[] parameters)
+ public async Task<VerboseBlockInfo> GetVerboseBlockAsync(uint256 blockId)
{
- return Rpc.SendCommandAsync(operations, parameters);
+ var resp = await Rpc.SendCommandAsync(RPCOperations.getblock, blockId, 3).ConfigureAwait(false);
+ return RpcParser.ParseVerboseBlockResponse(resp.Result.ToString());
}
#region For Testing Only

ADD
WalletWasabi/BitcoinCore/RpcParser.cs
+using System;
+using System.Collections.Generic;
+using System.Text;
+using NBitcoin;
+using NBitcoin.RPC;
+using Newtonsoft.Json.Linq;
+
+namespace WalletWasabi.BitcoinCore
+{
+ public class RpcParser
+ {
+ public static VerboseBlockInfo ParseVerboseBlockResponse(string getBlockResponse)
+ {
+ var blockInfoJson = JObject.Parse(getBlockResponse);
+ var previousBlockHash = blockInfoJson.Value<string>("previousblockhash");
+ var transaction = new List<VerboseTransactionInfo>();
+
+ var blockInfo = new VerboseBlockInfo(
+ hash: uint256.Parse(blockInfoJson.Value<string>("hash")),
+ prevBlockHash: previousBlockHash is { } ? uint256.Parse(previousBlockHash) : uint256.Zero,
+ confirmations: blockInfoJson.Value<ulong>("confirmations"),
+ height: blockInfoJson.Value<ulong>("height"),
+ blockTime: Utils.UnixTimeToDateTime(blockInfoJson.Value<uint>("time")),
+ transactions: transaction
+ );
+
+ foreach (var txJson in blockInfoJson["tx"])
+ {
+ var inputs = new List<VerboseInputInfo>();
+ var outputs = new List<VerboseOutputInfo>();
+ var tx = new VerboseTransactionInfo(uint256.Parse(txJson.Value<string>("txid")), inputs, outputs);
+
+ foreach (var txinJson in txJson["vin"])
+ {
+ VerboseInputInfo input = null;
+
+ if (txinJson["coinbase"] is { })
+ {
+ input = new VerboseInputInfo(txinJson["coinbase"].Value<string>());
+ }
+ else
+ {
+ input = new VerboseInputInfo(
+ outPoint: new OutPoint(uint256.Parse(txinJson.Value<string>("txid")), txinJson.Value<uint>("vout")),
+ prevOutput: new VerboseOutputInfo(
+ value: Money.Coins(txinJson["prevout"].Value<decimal>("value")),
+ scriptPubKey: Script.FromHex(txinJson["prevout"]["scriptPubKey"].Value<string>("hex")))
+ );
+ }
+
+ inputs.Add(input);
+ }
+
+ foreach (var txoutJson in txJson["vout"])
+ {
+ var output = new VerboseOutputInfo(
+ value: Money.Coins(txoutJson.Value<decimal>("value")),
+ scriptPubKey: Script.FromHex(txoutJson["scriptPubKey"].Value<string>("hex"))
+ );
+
+ outputs.Add(output);
+ }
+
+ transaction.Add(tx);
+ }
+
+ return blockInfo;
+ }
+ }
+}

MODIFY
WalletWasabi/Extensions/RPCClientExtensions.cs
WalletWasabi/Extensions/RPCClientExtensions.cs
@@ -285,65 +285,5 @@ namespace NBitcoin.RPC
return hashSet;
}
-
- public static async Task<VerboseBlockInfo> GetVerboseBlockAsync(this IRPCClient rpc, uint256 blockId)
- {
- var resp = await rpc.SendCommandAsync(RPCOperations.getblock, blockId, 3).ConfigureAwait(false);
- var blockInfoStr = resp.Result.ToString();
- var blockInfoJson = JObject.Parse(blockInfoStr);
- var previousBlockHash = blockInfoJson.Value<string>("previousblockhash");
- var transaction = new List<VerboseTransactionInfo>();
-
- var blockInfo = new VerboseBlockInfo(
- hash: uint256.Parse(blockInfoJson.Value<string>("hash")),
- prevBlockHash: previousBlockHash is { } ? uint256.Parse(previousBlockHash) : uint256.Zero,
- confirmations: blockInfoJson.Value<ulong>("confirmations"),
- height: blockInfoJson.Value<ulong>("height"),
- blockTime: Utils.UnixTimeToDateTime(blockInfoJson.Value<uint>("time")),
- transactions: transaction
- );
-
- foreach (var txJson in blockInfoJson["tx"])
- {
- var inputs = new List<VerboseInputInfo>();
- var outputs = new List<VerboseOutputInfo>();
- var tx = new VerboseTransactionInfo(uint256.Parse(txJson.Value<string>("txid")), inputs, outputs);
-
- foreach (var txinJson in txJson["vin"])
- {
- VerboseInputInfo input = null;
-
- if (txinJson["coinbase"] is { })
- {
- input = new VerboseInputInfo(txinJson["coinbase"].Value<string>());
- }
- else
- {
- input = new VerboseInputInfo(
- outPoint: new OutPoint(uint256.Parse(txinJson.Value<string>("txid")), txinJson.Value<uint>("vout")),
- prevOutput: new VerboseOutputInfo(
- value: Money.Coins(txinJson["prevout"].Value<decimal>("value")),
- scriptPubKey: Script.FromHex(txinJson["prevout"]["scriptPubKey"].Value<string>("hex")))
- );
- }
-
- inputs.Add(input);
- }
-
- foreach (var txoutJson in txJson["vout"])
- {
- var output = new VerboseOutputInfo(
- value: Money.Coins(txoutJson.Value<decimal>("value")),
- scriptPubKey: Script.FromHex(txoutJson["scriptPubKey"].Value<string>("hex"))
- );
-
- outputs.Add(output);
- }
-
- transaction.Add(tx);
- }
-
- return blockInfo;
- }
}
}

Create RpcParser and add one more verbose test