Skip to content

Commit 7e99384

Browse files
Added gettxoutproof RPC (#160)
* Added gettxoutproof RPC * Code Cleanup. * Use consensus manager to get the block * Cleanup unused using.
1 parent 48b2bd9 commit 7e99384

7 files changed

Lines changed: 127 additions & 13 deletions

File tree

src/Features/Blockcore.Features.BlockStore/Controllers/BlockStoreClient.cs renamed to src/Features/Blockcore.Features.BlockStore/Api/BlockStoreClient.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
using System.Threading.Tasks;
55
using Blockcore.Controllers;
66
using Blockcore.Controllers.Models;
7+
using Blockcore.Features.BlockStore.Api.Contollers;
8+
using Blockcore.Features.BlockStore.Api.Models;
79
using Microsoft.Extensions.Logging;
810

9-
namespace Blockcore.Features.BlockStore.Controllers
11+
namespace Blockcore.Features.BlockStore.Api
1012
{
1113
/// <summary>Rest client for <see cref="BlockStoreController"/>.</summary>
1214
public interface IBlockStoreClient : IRestApiClientBase

src/Features/Blockcore.Features.BlockStore/Controllers/BlockStoreController.cs renamed to src/Features/Blockcore.Features.BlockStore/Api/Controllers/BlockStoreController.cs

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using Blockcore.Base;
44
using Blockcore.Controllers.Models;
55
using Blockcore.Features.BlockStore.AddressIndexing;
6+
using Blockcore.Features.BlockStore.Api.Models;
67
using Blockcore.Features.BlockStore.Models;
78
using Blockcore.Interfaces;
89
using Blockcore.Utilities;
@@ -12,16 +13,8 @@
1213
using Microsoft.Extensions.Logging;
1314
using NBitcoin;
1415

15-
namespace Blockcore.Features.BlockStore.Controllers
16+
namespace Blockcore.Features.BlockStore.Api.Contollers
1617
{
17-
public static class BlockStoreRouteEndPoint
18-
{
19-
public const string GetAddressesBalances = "getaddressesbalances";
20-
public const string GetVerboseAddressesBalances = "getverboseaddressesbalances";
21-
public const string GetAddressIndexerTip = "addressindexertip";
22-
public const string GetBlock = "block";
23-
public const string GetBlockCount = "GetBlockCount";
24-
}
2518

2619
/// <summary>Controller providing operations on a blockstore.</summary>
2720
[ApiController]
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
using System.Collections.Generic;
2+
using Blockcore.Consensus;
3+
using Blockcore.Controllers;
4+
using Blockcore.Features.RPC;
5+
using Blockcore.Features.RPC.Exceptions;
6+
using Blockcore.Interfaces;
7+
using Blockcore.Primitives;
8+
using Microsoft.AspNetCore.Mvc;
9+
using NBitcoin;
10+
11+
namespace Blockcore.Features.BlockStore.Api.Controllers
12+
{
13+
/// <summary>
14+
/// Controller providing RPC operations on a watch-only wallet.
15+
/// </summary>
16+
public class BlockStoreRPCController : FeatureController
17+
{
18+
/// <summary>Consensus manager class.</summary>
19+
private readonly IConsensusManager consensusManager;
20+
21+
/// <summary>Thread safe access to the best chain of block headers from genesis.</summary>
22+
private readonly ChainIndexer chainIndexer;
23+
24+
/// <summary>Provides access to the block store database.</summary>
25+
private readonly IBlockStore blockStore;
26+
27+
/// <inheritdoc />
28+
public BlockStoreRPCController(
29+
IFullNode fullNode,
30+
IConsensusManager consensusManager,
31+
ChainIndexer chainIndexer,
32+
Network network,
33+
IBlockStore blockStore) : base(fullNode: fullNode, consensusManager: consensusManager, chainIndexer: chainIndexer, network: network)
34+
{
35+
this.consensusManager = consensusManager;
36+
this.chainIndexer = chainIndexer;
37+
this.blockStore = blockStore;
38+
}
39+
40+
/// <summary>
41+
/// By default this function only works when there is an unspent output in the utxo for this transaction.
42+
/// To make it work, you need to maintain a transaction index, using the -txindex command line option.
43+
/// </summary>
44+
/// <param name="txids">The txids to filter</param>
45+
/// <param name="blockhash">If specified, looks for txid in the block with this hash</param>
46+
/// <returns></returns>
47+
[ActionName("gettxoutproof")]
48+
[ActionDescription("Checks if transactions are within block. Returns proof of transaction inclusion (raw MerkleBlock).")]
49+
public MerkleBlock GetTxOutProof(string[] txids, string blockhash = "")
50+
{
51+
List<uint256> transactionIds = new List<uint256>();
52+
ChainedHeaderBlock block = null;
53+
foreach (var txString in txids)
54+
{
55+
transactionIds.Add(uint256.Parse(txString));
56+
}
57+
58+
if (!string.IsNullOrEmpty(blockhash))
59+
{
60+
// Loop through txids and veryify that the transaction is in the block.
61+
foreach (var transactionId in transactionIds)
62+
{
63+
var hashBlock = uint256.Parse(blockhash);
64+
ChainedHeader chainedHeader = this.GetTransactionBlock(transactionId);
65+
if (chainedHeader.HashBlock != hashBlock)
66+
{
67+
throw new RPCServerException(RPCErrorCode.RPC_INVALID_ADDRESS_OR_KEY, "Not all transactions found in specified or retrieved block");
68+
}
69+
if (block == null && chainedHeader.BlockDataAvailability == BlockDataAvailabilityState.BlockAvailable) // Only get the block once.
70+
{
71+
block = this.consensusManager.GetBlockData(chainedHeader.HashBlock);
72+
}
73+
}
74+
}
75+
else
76+
{
77+
// Loop through txids and try to find which block they're in. Exit loop once a block is found.
78+
foreach (var transactionId in transactionIds)
79+
{
80+
ChainedHeader chainedHeader = this.GetTransactionBlock(transactionId);
81+
if (chainedHeader.BlockDataAvailability == BlockDataAvailabilityState.BlockAvailable)
82+
{
83+
block = this.consensusManager.GetBlockData(chainedHeader.HashBlock);
84+
break;
85+
}
86+
}
87+
}
88+
if (block == null)
89+
{
90+
throw new RPCServerException(RPCErrorCode.RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
91+
}
92+
var result = new MerkleBlock(block.Block, transactionIds.ToArray());
93+
return result;
94+
}
95+
96+
internal ChainedHeader GetTransactionBlock(uint256 trxid)
97+
{
98+
ChainedHeader block = null;
99+
uint256 blockid = this.blockStore?.GetBlockIdByTransactionId(trxid);
100+
if (blockid != null)
101+
{
102+
block = this.chainIndexer?.GetHeader(blockid);
103+
}
104+
return block;
105+
}
106+
}
107+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace Blockcore.Features.BlockStore.Api.Models
2+
{
3+
public static class BlockStoreRouteEndPoint
4+
{
5+
public const string GetAddressesBalances = "getaddressesbalances";
6+
public const string GetVerboseAddressesBalances = "getverboseaddressesbalances";
7+
public const string GetAddressIndexerTip = "addressindexertip";
8+
public const string GetBlock = "block";
9+
public const string GetBlockCount = "GetBlockCount";
10+
}
11+
}

src/Features/Blockcore.Features.BlockStore/Blockcore.Features.BlockStore.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
<ItemGroup>
2121
<ProjectReference Include="..\..\External\NBitcoin\NBitcoin.csproj" />
2222
<ProjectReference Include="..\..\Blockcore\Blockcore.csproj" />
23+
<ProjectReference Include="..\Blockcore.Features.RPC\Blockcore.Features.RPC.csproj" />
2324
</ItemGroup>
2425

2526
<ItemGroup>

src/Features/Blockcore.Features.RPC/RPCClient.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ blockchain getchaintips
8585
blockchain getdifficulty
8686
blockchain getmempoolinfo
8787
blockchain getrawmempool Yes
88-
blockchain gettxout Yes
89-
blockchain gettxoutproof
88+
blockchain gettxout Yes
89+
blockchain gettxoutproof Yes
9090
blockchain verifytxoutproof
9191
blockchain gettxoutsetinfo
9292
blockchain verifychain

src/Tests/Blockcore.Features.BlockStore.Tests/BlockStoreControllerTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
using Blockcore.Base;
44
using Blockcore.Controllers.Models;
55
using Blockcore.Features.BlockStore.AddressIndexing;
6-
using Blockcore.Features.BlockStore.Controllers;
6+
using Blockcore.Features.BlockStore.Api.Contollers;
77
using Blockcore.Features.BlockStore.Models;
88
using Blockcore.Interfaces;
99
using Blockcore.Tests.Common;

0 commit comments

Comments
 (0)