From 92bfde0edf5537576121c20ad8e5466fd9fa1e98 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 28 Jul 2017 10:50:07 +0000 Subject: [PATCH] Improve network height estimation --- src/gtest/test_metrics.cpp | 38 +++++++++++++++++++------------------- src/metrics.cpp | 14 ++++++++++---- src/metrics.h | 2 +- 3 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/gtest/test_metrics.cpp b/src/gtest/test_metrics.cpp index 8f313b5d2..143fe46d6 100644 --- a/src/gtest/test_metrics.cpp +++ b/src/gtest/test_metrics.cpp @@ -96,40 +96,40 @@ TEST(Metrics, GetLocalSolPS) { TEST(Metrics, EstimateNetHeightInner) { // Ensure that the (rounded) current height is returned if the tip is current SetMockTime(15000); - EXPECT_EQ(100, EstimateNetHeightInner(100, 14100, 50, 7500, 150)); + EXPECT_EQ(100, EstimateNetHeightInner(100, 14100, 50, 7500, 0, 150)); SetMockTime(15150); - EXPECT_EQ(100, EstimateNetHeightInner(101, 14250, 50, 7500, 150)); + EXPECT_EQ(100, EstimateNetHeightInner(101, 14250, 50, 7500, 0, 150)); // Ensure that correct estimates are returned if the tip is in the past SetMockTime(15300); // Tip is 2 blocks behind - EXPECT_EQ(100, EstimateNetHeightInner(100, 14100, 50, 7500, 150)); + EXPECT_EQ(100, EstimateNetHeightInner(100, 14100, 50, 7500, 0, 150)); SetMockTime(15900); // Tip is 6 blocks behind - EXPECT_EQ(110, EstimateNetHeightInner(100, 14100, 50, 7500, 150)); + EXPECT_EQ(110, EstimateNetHeightInner(100, 14100, 50, 7500, 0, 150)); // Check estimates during resync SetMockTime(15000); - EXPECT_EQ(100, EstimateNetHeightInner( 0, 0, 50, 7500, 150)); - EXPECT_EQ(100, EstimateNetHeightInner( 7, 600, 50, 7500, 150)); - EXPECT_EQ(100, EstimateNetHeightInner( 8, 600, 50, 7500, 150)); - EXPECT_EQ(100, EstimateNetHeightInner(10, 750, 50, 7500, 150)); - EXPECT_EQ(100, EstimateNetHeightInner(11, 900, 50, 7500, 150)); - EXPECT_EQ(100, EstimateNetHeightInner(20, 2100, 50, 7500, 150)); - EXPECT_EQ(100, EstimateNetHeightInner(49, 6450, 50, 7500, 150)); - EXPECT_EQ(100, EstimateNetHeightInner(50, 6600, 50, 7500, 150)); - EXPECT_EQ(100, EstimateNetHeightInner(51, 6750, 50, 7500, 150)); - EXPECT_EQ(100, EstimateNetHeightInner(55, 7350, 50, 7500, 150)); - EXPECT_EQ(100, EstimateNetHeightInner(56, 7500, 50, 7500, 150)); - EXPECT_EQ(100, EstimateNetHeightInner(57, 7650, 50, 7500, 150)); - EXPECT_EQ(100, EstimateNetHeightInner(75, 10350, 50, 7500, 150)); + EXPECT_EQ(100, EstimateNetHeightInner( 0, 0, 50, 7500, 0, 150)); + EXPECT_EQ(100, EstimateNetHeightInner( 7, 600, 50, 7500, 0, 150)); + EXPECT_EQ(100, EstimateNetHeightInner( 8, 600, 50, 7500, 0, 150)); + EXPECT_EQ(100, EstimateNetHeightInner(10, 750, 50, 7500, 0, 150)); + EXPECT_EQ(100, EstimateNetHeightInner(11, 900, 50, 7500, 0, 150)); + EXPECT_EQ(100, EstimateNetHeightInner(20, 2100, 50, 7500, 0, 150)); + EXPECT_EQ(100, EstimateNetHeightInner(49, 6450, 50, 7500, 0, 150)); + EXPECT_EQ(100, EstimateNetHeightInner(50, 6600, 50, 7500, 0, 150)); + EXPECT_EQ(100, EstimateNetHeightInner(51, 6750, 50, 7500, 0, 150)); + EXPECT_EQ(100, EstimateNetHeightInner(55, 7350, 50, 7500, 0, 150)); + EXPECT_EQ(100, EstimateNetHeightInner(56, 7500, 50, 7500, 0, 150)); + EXPECT_EQ(100, EstimateNetHeightInner(57, 7650, 50, 7500, 0, 150)); + EXPECT_EQ(100, EstimateNetHeightInner(75, 10350, 50, 7500, 0, 150)); // More complex calculations: SetMockTime(20000); // - Checkpoint spacing: 200 // -> Average spacing: 175 // -> estimated height: 127 -> 130 - EXPECT_EQ(130, EstimateNetHeightInner(100, 14100, 50, 5250, 150)); + EXPECT_EQ(130, EstimateNetHeightInner(100, 14100, 50, 5250, 0, 150)); // - Checkpoint spacing: 50 // -> Average spacing: 100 // -> estimated height: 153 -> 150 - EXPECT_EQ(150, EstimateNetHeightInner(100, 14100, 50, 12000, 150)); + EXPECT_EQ(150, EstimateNetHeightInner(100, 14100, 50, 12000, 0, 150)); } diff --git a/src/metrics.cpp b/src/metrics.cpp index b10e94630..1bac2c9c0 100644 --- a/src/metrics.cpp +++ b/src/metrics.cpp @@ -106,12 +106,17 @@ double GetLocalSolPS() int EstimateNetHeightInner(int height, int64_t tipmediantime, int heightLastCheckpoint, int64_t timeLastCheckpoint, - int64_t targetSpacing) + int64_t genesisTime, int64_t targetSpacing) { // We average the target spacing with the observed spacing to the last - // checkpoint, and use that to estimate the current network height. - int medianHeight = height - CBlockIndex::nMedianTimeSpan / 2; - double checkpointSpacing = (double (tipmediantime - timeLastCheckpoint)) / (medianHeight - heightLastCheckpoint); + // checkpoint (either from below or above depending on the current height), + // and use that to estimate the current network height. + int medianHeight = height > CBlockIndex::nMedianTimeSpan ? + height - (1 + ((CBlockIndex::nMedianTimeSpan - 1) / 2)) : + height / 2; + double checkpointSpacing = medianHeight > heightLastCheckpoint ? + (double (tipmediantime - timeLastCheckpoint)) / (medianHeight - heightLastCheckpoint) : + (double (timeLastCheckpoint - genesisTime)) / heightLastCheckpoint; double averageSpacing = (targetSpacing + checkpointSpacing) / 2; int netheight = medianHeight + ((GetTime() - tipmediantime) / averageSpacing); // Round to nearest ten to reduce noise @@ -125,6 +130,7 @@ int EstimateNetHeight(int height, int64_t tipmediantime, CChainParams chainParam height, tipmediantime, Checkpoints::GetTotalBlocksEstimate(checkpointData), checkpointData.nTimeLastCheckpoint, + chainParams.GenesisBlock().nTime, chainParams.GetConsensus().nPowTargetSpacing); } diff --git a/src/metrics.h b/src/metrics.h index 7f7efdea6..2d60d30ca 100644 --- a/src/metrics.h +++ b/src/metrics.h @@ -65,7 +65,7 @@ void MarkStartTime(); double GetLocalSolPS(); int EstimateNetHeightInner(int height, int64_t tipmediantime, int heightLastCheckpoint, int64_t timeLastCheckpoint, - int64_t targetSpacing); + int64_t genesisTime, int64_t targetSpacing); void TriggerRefresh();