-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathstake_version_intervals.go
113 lines (98 loc) · 3.66 KB
/
stake_version_intervals.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
// Copyright (c) 2017-2023 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package main
import (
"context"
"log"
"github.com/decred/dcrd/chaincfg/v3"
"github.com/decred/dcrd/rpc/jsonrpc/types/v4"
"github.com/decred/dcrd/rpcclient/v8"
)
// StakeVersionIntervals wraps a set of types.VersionIntervals
type StakeVersionIntervals struct {
Intervals []types.VersionInterval
MinVoteVersion uint32
MaxVoteVersion uint32
}
// GetStakeVersionUpgradeSVI will search through every stake version interval
// to find the first SVI which meets the upgrade threshold for the provided version.
func (s *StakeVersionIntervals) GetStakeVersionUpgradeSVI(version uint32) (upgradeOccurred bool, upgradeSVI types.VersionInterval) {
// This site is not able to cope with the PoS upgrade threshold being met
// before the PoW threshold.
// That happened on both testnet and mainnet during the version 8 upgrade,
// and on mainnet during version 9.
// Hardcoding those upgrade SVIs rather than detecting them
// programmatically.
if version == 8 {
switch activeNetParams.Name {
case chaincfg.MainNetParams().Name:
return true, s.Intervals[261]
case chaincfg.TestNet3Params().Name:
return true, s.Intervals[152]
default:
panic("unsupported network")
}
}
if version == 9 && activeNetParams.Name == chaincfg.MainNetParams().Name {
return true, s.Intervals[312]
}
for i, svi := range s.Intervals {
// If this is an incomplete SVI, then the upgrade has not happened.
if svi.EndHeight-svi.StartHeight < activeNetParams.StakeVersionInterval {
continue
}
// Count the votes in this SVI to see if the upgrade threshold has been met
var totalVotes int32
var versionVotes int32
for _, voteVersion := range svi.VoteVersions {
totalVotes += int32(voteVersion.Count)
if voteVersion.Version == version {
versionVotes += int32(voteVersion.Count)
}
}
upgradeThreshold := totalVotes * activeNetParams.StakeMajorityMultiplier / activeNetParams.StakeMajorityDivisor
if versionVotes > upgradeThreshold {
log.Printf("v%d upgrade threshold was met during SVI %d (blocks %d-%d). Total votes: %d, v%d votes: %d, threshold: %d",
version, i+1, svi.StartHeight, svi.EndHeight, totalVotes, version, versionVotes, upgradeThreshold)
return true, svi
}
}
return false, types.VersionInterval{}
}
// AllStakeVersionIntervals uses the dcrd client to create an ordered
// set of objects representing every Stake Version Interval up to the
// provided block height
func AllStakeVersionIntervals(ctx context.Context, dcrdClient *rpcclient.Client, height int64) (StakeVersionIntervals, error) {
// Use current height to calculate the number of the current SVI
totalSVIs := 1 + int32((height-activeNetParams.StakeValidationHeight)/activeNetParams.StakeVersionInterval)
// Get SVIs details from dcrd
stakeVersionInfoResult, err := dcrdClient.GetStakeVersionInfo(ctx, totalSVIs)
if err != nil {
return StakeVersionIntervals{}, err
}
svis := StakeVersionIntervals{
Intervals: stakeVersionInfoResult.Intervals,
}
// Reverse the slice of SVIs
// This makes traversing the set easier later on,
// because the first element is the first SVI, etc.
for i := len(svis.Intervals)/2 - 1; i >= 0; i-- {
opp := len(svis.Intervals) - 1 - i
svis.Intervals[i], svis.Intervals[opp] = svis.Intervals[opp], svis.Intervals[i]
}
// Get max vote version
var max uint32
for version := range activeNetParams.Deployments {
if version > max {
max = version
}
}
min := activeNetParams.GenesisBlock.Header.StakeVersion
if min < 4 {
min = 4
}
svis.MinVoteVersion = min
svis.MaxVoteVersion = max
return svis, nil
}