Skip to content

Commit f64e9ef

Browse files
authored
Merge pull request #278 from SiaFoundation/metrics
Fix DifficultyMetrics off-by-1
2 parents 0538280 + 65adb61 commit f64e9ef

File tree

2 files changed

+72
-4
lines changed

2 files changed

+72
-4
lines changed

api/api_test.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,3 +696,71 @@ func TestAPI(t *testing.T) {
696696
t.Run(subtest.name, subtest.test)
697697
}
698698
}
699+
700+
func TestDifficultyMetricsOffByOneRegression(t *testing.T) {
701+
network, genesisBlock := ctestutil.Network()
702+
pk := types.GeneratePrivateKey()
703+
addr := types.StandardUnlockHash(pk.PublicKey())
704+
genesisBlock.Transactions[0].SiacoinOutputs[0].Address = addr
705+
706+
scanCfg := config.Scanner{
707+
NumThreads: 100,
708+
ScanTimeout: 30 * time.Second,
709+
ScanFrequency: 100 * time.Millisecond,
710+
ScanInterval: 3 * time.Hour,
711+
MinLastAnnouncement: 90 * 24 * time.Hour,
712+
}
713+
e, cm, err := newExplorer(t, network, genesisBlock, scanCfg)
714+
if err != nil {
715+
t.Fatal(err)
716+
}
717+
718+
listenAddr := "127.0.0.1:9998"
719+
_, err = newServer(t, cm, e, listenAddr)
720+
if err != nil {
721+
t.Fatal(err)
722+
}
723+
724+
// Mine 450 blocks to ensure we have enough data for our test range (150-450)
725+
for range 450 {
726+
cs := cm.TipState()
727+
b := types.Block{
728+
ParentID: cs.Index.ID,
729+
Timestamp: genesisBlock.Timestamp.Add(time.Duration(cs.Index.Height+1) * network.BlockInterval),
730+
MinerPayouts: []types.SiacoinOutput{{Value: cs.BlockReward()}},
731+
}
732+
if !coreutils.FindBlockNonce(cs, &b, time.Second) {
733+
panic("failed to mine test block quickly enough")
734+
}
735+
if err := cm.AddBlocks([]types.Block{b}); err != nil {
736+
t.Fatal(err)
737+
}
738+
}
739+
for {
740+
tip, _ := e.Tip()
741+
if tip.Height == 450 {
742+
break
743+
}
744+
time.Sleep(100 * time.Millisecond)
745+
}
746+
747+
client := api.NewClient("http://"+listenAddr+"/api", testPassword)
748+
749+
resp, err := client.DifficultyMetrics(150, 450)
750+
if err != nil {
751+
t.Fatal(err)
752+
}
753+
754+
testutil.Equal(t, "blocks per step", 2, resp.BlocksPerStep)
755+
testutil.Equal(t, "difficulties length", 150, len(resp.Difficulties))
756+
testutil.Equal(t, "block times length", 150, len(resp.BlockTimes))
757+
testutil.Equal(t, "drifts length", 150, len(resp.Drifts))
758+
759+
// Verify response starts at height 150
760+
index, _ := cm.BestIndex(150)
761+
cs, _ := cm.State(index.ID)
762+
testutil.Equal(t, "first difficulty is for height 150", cs.Difficulty, resp.Difficulties[0])
763+
764+
// Verify first block time is calculated from height 148 to 150
765+
testutil.Equal(t, "first block time", cs.PrevTimestamps[0].Sub(cs.PrevTimestamps[2])/2, resp.BlockTimes[0])
766+
}

persist/sqlite/metrics.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -286,10 +286,10 @@ func (s *Store) DifficultyMetrics(start, end, step uint64, n *consensus.Network)
286286
return nil
287287
}
288288

289-
// We need blocktime deltas, so offset the range by 1 (if possible)
289+
// We need blocktime deltas, so offset the range by one step (if possible)
290290
queryStart := start
291-
if start > 0 {
292-
queryStart = start - 1
291+
if start >= step {
292+
queryStart = start - step
293293
}
294294
query := `SELECT nm.difficulty, b.timestamp
295295
FROM network_metrics nm
@@ -334,7 +334,7 @@ func (s *Store) DifficultyMetrics(start, end, step uint64, n *consensus.Network)
334334
}
335335

336336
// trim if necessary
337-
if start > 0 {
337+
if start >= step {
338338
result.Difficulties = result.Difficulties[1:]
339339
result.BlockTimes = result.BlockTimes[1:]
340340
result.Drifts = result.Drifts[1:]

0 commit comments

Comments
 (0)