Skip to content

Commit

Permalink
Add endpoint to return the network weight for POS chains (#377)
Browse files Browse the repository at this point in the history
* Add endpoint to return the network weight for pos chains

* Add pos network weight to getblockchaininfo rpc method
  • Loading branch information
dangershony authored Jan 21, 2022
1 parent bdd6e67 commit d4e38ee
Show file tree
Hide file tree
Showing 10 changed files with 89 additions and 12 deletions.
9 changes: 9 additions & 0 deletions src/Blockcore/Interfaces/INetworkWeight.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using NBitcoin;

namespace Blockcore.Interfaces
{
public interface INetworkWeight
{
double GetPosNetworkWeight();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public IActionResult GetStakingInfo()
try
{
if (!this.fullNode.Network.Consensus.IsProofOfStake)
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.MethodNotAllowed, "Method not allowed", "Method not available for Proof of Stake");
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.MethodNotAllowed, "Method not allowed", "Method only available for Proof of Stake");

GetStakingInfoModel model = this.posMinting != null ? this.posMinting.GetGetStakingInfoModel() : new GetStakingInfoModel();

Expand All @@ -79,6 +79,31 @@ public IActionResult GetStakingInfo()
}
}

/// <summary>
/// Get staking info from the miner.
/// </summary>
/// <returns>All staking info details as per the GetStakingInfoModel.</returns>
[Route("getnetworkstakinginfo")]
[HttpGet]
public IActionResult GetNetworkStakingInfo()
{
try
{
if (!this.fullNode.Network.Consensus.IsProofOfStake)
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.MethodNotAllowed, "Method not allowed", "Method only available for Proof of Stake");

double networkWeight = this.posMinting.GetNetworkWeight();
double posDifficulty = this.posMinting.GetDifficulty(null);

return this.Json(new GetNetworkStakingInfoModel { Difficulty = posDifficulty, NetStakeWeight = (long)networkWeight });
}
catch (Exception e)
{
this.logger.LogError("Exception occurred: {0}", e.ToString());
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, e.Message, e.ToString());
}
}

/// <summary>
/// Start staking.
/// </summary>
Expand All @@ -93,7 +118,7 @@ public IActionResult StartStaking([FromBody] StartStakingRequest request)
try
{
if (!this.fullNode.Network.Consensus.IsProofOfStake)
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.MethodNotAllowed, "Method not allowed", "Method not available for Proof of Stake");
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.MethodNotAllowed, "Method not allowed", "Method only available for Proof of Stake");

if (!this.ModelState.IsValid)
{
Expand Down Expand Up @@ -139,7 +164,7 @@ public IActionResult StopStaking([FromBody] bool corsProtection = true)
try
{
if (!this.fullNode.Network.Consensus.IsProofOfStake)
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.MethodNotAllowed, "Method not allowed", "Method not available for Proof of Stake");
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.MethodNotAllowed, "Method not allowed", "Method only available for Proof of Stake");

this.fullNode.NodeFeature<MiningFeature>(true).StopStaking();
return this.Ok();
Expand All @@ -162,7 +187,7 @@ public IActionResult StakingExpiry([FromBody] StakingExpiryRequest request)
try
{
if (!this.fullNode.Network.Consensus.IsProofOfStake)
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.MethodNotAllowed, "Method not allowed", "Method not available for Proof of Stake");
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.MethodNotAllowed, "Method not allowed", "Method only available for Proof of Stake");

if (!this.minerSettings.EnforceStakingFlag)
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.Forbidden, "Operation not allowed", "This operation is only allowed if EnforceStakingFlag is true");
Expand Down Expand Up @@ -196,7 +221,7 @@ public IActionResult GetStakingNotExpired([FromBody] StakingNotExpiredRequest re
try
{
if (!this.fullNode.Network.Consensus.IsProofOfStake)
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.MethodNotAllowed, "Method not allowed", "Method not available for Proof of Stake");
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.MethodNotAllowed, "Method not allowed", "Method only available for Proof of Stake");

if (!this.minerSettings.EnforceStakingFlag)
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.Forbidden, "Operation not allowed", "This operation is only allowed if EnforceStakingFlag is true");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using Newtonsoft.Json;

namespace Blockcore.Features.Miner.Api.Models
{
/// <summary>
/// Data structure returned by RPC command "getstakinginfo".
/// </summary>
public class GetNetworkStakingInfoModel
{
/// <summary>Target difficulty that the next block must meet.</summary>
[JsonProperty(PropertyName = "difficulty")]
public double Difficulty { get; set; }

/// <summary>Estimation of the total staking weight of all nodes on the network.</summary>
[JsonProperty(PropertyName = "netStakeWeight")]
public long NetStakeWeight { get; set; }

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@
<ProjectReference Include="..\Blockcore.Features.Wallet\Blockcore.Features.Wallet.csproj" />
<ProjectReference Include="..\..\Blockcore\Blockcore.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="Api\" />
</ItemGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<NoWarn>1701;1702;1705;IDE0008;</NoWarn>
<DocumentationFile>
Expand Down
4 changes: 3 additions & 1 deletion src/Features/Blockcore.Features.Miner/MiningFeature.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
using Blockcore.Features.RPC;
using Blockcore.Features.Wallet;
using Blockcore.Features.Wallet.UI;
using Blockcore.Interfaces;
using Blockcore.Interfaces.UI;
using Blockcore.Mining;
using Blockcore.Networks;
Expand Down Expand Up @@ -256,7 +257,8 @@ public static IFullNodeBuilder AddPowPosMining(this IFullNodeBuilder fullNodeBui
.FeatureServices(services =>
{
services.AddSingleton<IPowMining, PowMining>();
services.AddSingleton<IPosMinting, PosMinting>();
services.AddSingleton<IPosMinting, PosMinting>()
.AddSingleton<INetworkWeight, PosMinting>(provider => (PosMinting)provider.GetService<IPosMinting>());
services.AddSingleton<IBlockProvider, BlockProvider>();
services.AddSingleton<BlockDefinition, PowBlockDefinition>();
services.AddSingleton<BlockDefinition, PosBlockDefinition>();
Expand Down
7 changes: 6 additions & 1 deletion src/Features/Blockcore.Features.Miner/Staking/PosMinting.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ namespace Blockcore.Features.Miner.Staking
/// and the new value depends on the kernel, it is hard to predict its value in the future.
/// </para>
/// </remarks>
public class PosMinting : IPosMinting
public class PosMinting : IPosMinting, INetworkWeight
{
/// <summary>
/// Indicates the current state: idle, staking requested, staking in progress and stop staking requested.
Expand Down Expand Up @@ -1189,6 +1189,11 @@ public double GetNetworkWeight()
return res;
}

public double GetPosNetworkWeight()
{
return GetNetworkWeight();
}

/// <inheritdoc/>
public GetStakingInfoModel GetGetStakingInfoModel()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ public class FullNodeController : FeatureController
/// <summary>An interface implementation used to retrieve the network difficulty target.</summary>
private readonly INetworkDifficulty networkDifficulty;

/// <summary>An interface implementation used to retrieve the total network weight.</summary>
private readonly INetworkWeight networkWeight;

/// <summary>An interface implementation for the blockstore.</summary>
private readonly IBlockStore blockStore;

Expand All @@ -73,7 +76,8 @@ public FullNodeController(
IConsensusManager consensusManager = null,
IBlockStore blockStore = null,
IInitialBlockDownloadState ibdState = null,
IStakeChain stakeChain = null)
IStakeChain stakeChain = null,
INetworkWeight networkWeight = null)
: base(
fullNode: fullNode,
network: network,
Expand All @@ -91,6 +95,7 @@ public FullNodeController(
this.blockStore = blockStore;
this.ibdState = ibdState;
this.stakeChain = stakeChain;
this.networkWeight = networkWeight;
}

/// <summary>
Expand Down Expand Up @@ -462,6 +467,7 @@ public BlockchainInfoModel GetBlockchainInfo()
Headers = (uint)(this.ChainIndexer?.Height ?? 0),
BestBlockHash = this.ChainState?.ConsensusTip?.HashBlock,
Difficulty = this.GetNetworkDifficulty()?.Difficulty ?? 0.0,
NetworkWeight = (long)this.GetPosNetworkWeight(),
MedianTime = this.ChainState?.ConsensusTip?.GetMedianTimePast().ToUnixTimeSeconds() ?? 0,
VerificationProgress = 0.0,
IsInitialBlockDownload = this.ibdState?.IsInitialBlockDownload() ?? true,
Expand Down Expand Up @@ -550,5 +556,10 @@ private Target GetNetworkDifficulty()
{
return this.networkDifficulty?.GetNetworkDifficulty();
}

private double GetPosNetworkWeight()
{
return this.networkWeight?.GetPosNetworkWeight() ?? 0;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace Blockcore.Features.RPC.Models
// * "headers": xxxxxx, (numeric) the current number of headers we have validated
// "bestblockhash": "...", (string) the hash of the currently best block
// "difficulty": xxxxxx, (numeric) the current difficulty
// "networkWeight: xxxxx, (numeric) the total network weight
// * "mediantime": xxxxxx, (numeric) median time for the current best block
// * "verificationprogress": xxxx, (numeric) estimate of verification progress[0..1]
// * "initialblockdownload": xxxx, (bool) (debug information) estimate of whether this node is in Initial Block Download mode.
Expand Down Expand Up @@ -64,6 +65,9 @@ public class BlockchainInfoModel

[JsonProperty(PropertyName = "difficulty")]
public double Difficulty { get; set; }

[JsonProperty(PropertyName = "networkWeight")]
public long NetworkWeight { get; set; }

[JsonProperty(PropertyName = "mediantime")]
public long MedianTime { get; set; }
Expand Down
4 changes: 4 additions & 0 deletions src/Node/Blockcore.Node/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@
"commandName": "Project",
"commandLineArgs": "--chain=X42 -server -rpcallowip=127.0.0.1 -rpcbind=127.0.0.1 -rpcpassword=rpcpassword -rpcuser=rpcuser -datadir=nodedata -testnet"
},
"XDS (MAIN)": {
"commandName": "Project",
"commandLineArgs": "--chain=XDS -server -rpcallowip=127.0.0.1 -rpcbind=127.0.0.1 -rpcpassword=rpcpassword -rpcuser=rpcuser"
},
"XDS (MAIN/LOCAL)": {
"commandName": "Project",
"commandLineArgs": "--chain=XDS -server -rpcallowip=127.0.0.1 -rpcbind=127.0.0.1 -rpcpassword=rpcpassword -rpcuser=rpcuser -datadir=nodedata"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ public void StartStaking_OnProofOfWorkNetwork_Returns_MethodNotAllowed()

ErrorModel error = errorResponse.Errors[0];
Assert.Equal(405, error.Status);
Assert.Equal("Method not available for Proof of Stake", error.Description);
Assert.Equal("Method only available for Proof of Stake", error.Description);
}
}
}
Expand Down

0 comments on commit d4e38ee

Please sign in to comment.