diff --git a/src/Stratis.Bitcoin.Features.Api/NodeController.cs b/src/Stratis.Bitcoin.Features.Api/NodeController.cs index 934a2b4c5b..79544a06ad 100644 --- a/src/Stratis.Bitcoin.Features.Api/NodeController.cs +++ b/src/Stratis.Bitcoin.Features.Api/NodeController.cs @@ -156,6 +156,7 @@ public IActionResult Status() ProcessId = Process.GetCurrentProcess().Id, Network = this.fullNode.Network.Name, ConsensusHeight = this.chainState.ConsensusTip?.Height, + HeaderHeight = this.consensusManager.HeaderTip, DataDirectoryPath = this.nodeSettings.DataDir, Testnet = this.network.IsTest(), RelayFee = this.nodeSettings.MinRelayTxFeeRate?.FeePerK?.ToUnit(MoneyUnit.BTC) ?? 0, diff --git a/src/Stratis.Bitcoin.Features.PoA/Models/FederationMemberModel.cs b/src/Stratis.Bitcoin.Features.PoA/Models/FederationMemberModel.cs index 547bfc4fce..a7eaca21b7 100644 --- a/src/Stratis.Bitcoin.Features.PoA/Models/FederationMemberModel.cs +++ b/src/Stratis.Bitcoin.Features.PoA/Models/FederationMemberModel.cs @@ -46,5 +46,8 @@ public sealed class FederationMemberDetailedModel : FederationMemberModel [JsonProperty("rewardEstimatePerBlock")] public double RewardEstimatePerBlock { get; set; } + + [JsonProperty("miningStats")] + public MiningStatisticsModel MiningStatistics { get; set; } } } \ No newline at end of file diff --git a/src/Stratis.Bitcoin.Features.PoA/PoAMiner.cs b/src/Stratis.Bitcoin.Features.PoA/PoAMiner.cs index d0d0e99934..7d1c583063 100644 --- a/src/Stratis.Bitcoin.Features.PoA/PoAMiner.cs +++ b/src/Stratis.Bitcoin.Features.PoA/PoAMiner.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Microsoft.Extensions.Logging; using NBitcoin; +using Newtonsoft.Json; using Stratis.Bitcoin.AsyncWork; using Stratis.Bitcoin.Configuration; using Stratis.Bitcoin.Configuration.Logging; @@ -37,6 +38,12 @@ public interface IPoAMiner : IDisposable { /// Starts mining loop. void InitializeMining(); + + /// + /// Returns mining statistics in the last amount of blocks equal to the federation size. + /// + /// Returns true if the miner produced a block in the last round and block producer hits. + MiningStatisticsModel MiningStatistics { get; } } /// @@ -73,6 +80,8 @@ public class PoAMiner : IPoAMiner private readonly NodeSettings nodeSettings; + private MiningStatisticsModel miningStatistics; + private readonly IWalletManager walletManager; protected readonly VotingManager votingManager; @@ -418,7 +427,6 @@ private void AddComponentStats(StringBuilder log) log.AppendLine(); return; } - ChainedHeader tip = this.consensusManager.Tip; ChainedHeader currentHeader = tip; @@ -442,6 +450,8 @@ private void AddComponentStats(StringBuilder log) if (timeHeader < currentHeader.Header.Time) timeHeader += this.network.ConsensusOptions.TargetSpacingSeconds; + var statistics = new MiningStatisticsModel(); + // Iterate mining slots. for (int i = 0; i < maxDepth; i++) { @@ -449,7 +459,12 @@ private void AddComponentStats(StringBuilder log) PubKey pubKey = modifiedFederation[headerSlot].PubKey; - string pubKeyRepresentation = (pubKey == this.federationManager.CurrentFederationKey?.PubKey) ? "█████" : pubKey.ToString().Substring(0, pubKeyTakeCharacters); + string pubKeyRepresentation = pubKey.ToString().Substring(0, pubKeyTakeCharacters); + if (pubKey == this.federationManager.CurrentFederationKey?.PubKey) + { + pubKeyRepresentation = "█████"; + statistics.ProducedBlockInLastRound = true; + } // Mined in this slot? if (timeHeader == currentHeader.Header.Time) @@ -475,6 +490,9 @@ private void AddComponentStats(StringBuilder log) log.AppendLine(); } + statistics.FederationSize = maxDepth; + statistics.MinerHits = hitCount; + log.Append("..."); log.AppendLine(); log.AppendLine($"Miner hits".PadRight(LoggingConfiguration.ColumnLength) + $": {hitCount} of {maxDepth}({(((float)hitCount / (float)maxDepth)).ToString("P2")})"); @@ -482,6 +500,12 @@ private void AddComponentStats(StringBuilder log) log.AppendLine(); } + /// + public MiningStatisticsModel MiningStatistics + { + get { return this.miningStatistics; } + } + /// public virtual void Dispose() { @@ -491,4 +515,16 @@ public virtual void Dispose() this.cancellation.Dispose(); } } + + public sealed class MiningStatisticsModel + { + [JsonProperty(PropertyName = "federationSize")] + public int FederationSize { get; set; } + + [JsonProperty(PropertyName = "minerHits")] + public int MinerHits { get; set; } + + [JsonProperty(PropertyName = "producedBlockInLastRound")] + public bool ProducedBlockInLastRound { get; set; } + } } diff --git a/src/Stratis.Bitcoin.Features.PoA/Voting/FederationController.cs b/src/Stratis.Bitcoin.Features.PoA/Voting/FederationController.cs index bc861e5634..619c7f93ff 100644 --- a/src/Stratis.Bitcoin.Features.PoA/Voting/FederationController.cs +++ b/src/Stratis.Bitcoin.Features.PoA/Voting/FederationController.cs @@ -20,6 +20,7 @@ public sealed class FederationController : Controller private readonly IIdleFederationMembersKicker idleFederationMembersKicker; private readonly ILogger logger; private readonly Network network; + private readonly IPoAMiner poaMiner; private readonly ReconstructFederationService reconstructFederationService; private readonly VotingManager votingManager; @@ -29,12 +30,14 @@ public sealed class FederationController : Controller VotingManager votingManager, Network network, IIdleFederationMembersKicker idleFederationMembersKicker, + IPoAMiner poAMiner, ReconstructFederationService reconstructFederationService) { this.chainIndexer = chainIndexer; this.federationManager = federationManager; this.idleFederationMembersKicker = idleFederationMembersKicker; this.network = network; + this.poaMiner = poAMiner; this.reconstructFederationService = reconstructFederationService; this.votingManager = votingManager; @@ -126,6 +129,8 @@ public IActionResult GetCurrentMemberInfo() federationMemberModel.RewardEstimatePerBlock = 9d / this.federationManager.GetFederationMembers().Count; + federationMemberModel.MiningStatistics = this.poaMiner.MiningStatistics; + return Json(federationMemberModel); } catch (Exception e) diff --git a/src/Stratis.Bitcoin/Controllers/Models/StatusModel.cs b/src/Stratis.Bitcoin/Controllers/Models/StatusModel.cs index effaf15628..170b066f67 100644 --- a/src/Stratis.Bitcoin/Controllers/Models/StatusModel.cs +++ b/src/Stratis.Bitcoin/Controllers/Models/StatusModel.cs @@ -38,9 +38,12 @@ public StatusModel() /// System identifier of the node's process. public int ProcessId { get; set; } - /// The height of the consensus. + /// The height of consensus. public int? ConsensusHeight { get; set; } + /// The height of the header store. + public int? HeaderHeight { get; set; } + /// Height of the most recent block in persistent storage. /// public int BlockStoreHeight { get; set; }