github.com/decred/dcrd/blockchain@v1.2.1/thresholdstate.go (about) 1 // Copyright (c) 2016 The btcsuite developers 2 // Copyright (c) 2017-2019 The Decred developers 3 // Use of this source code is governed by an ISC 4 // license that can be found in the LICENSE file. 5 6 package blockchain 7 8 import ( 9 "fmt" 10 11 "github.com/decred/dcrd/chaincfg" 12 "github.com/decred/dcrd/chaincfg/chainhash" 13 ) 14 15 // ThresholdState define the various threshold states used when voting on 16 // consensus changes. 17 type ThresholdState byte 18 19 // These constants are used to identify specific threshold states. 20 // 21 // NOTE: This section specifically does not use iota for the individual states 22 // since these values are serialized and must be stable for long-term storage. 23 const ( 24 // ThresholdDefined is the first state for each deployment and is the 25 // state for the genesis block has by definition for all deployments. 26 ThresholdDefined ThresholdState = 0 27 28 // ThresholdStarted is the state for a deployment once its start time 29 // has been reached. 30 ThresholdStarted ThresholdState = 1 31 32 // ThresholdLockedIn is the state for a deployment during the retarget 33 // period which is after the ThresholdStarted state period and the 34 // number of blocks that have voted for the deployment equal or exceed 35 // the required number of votes for the deployment. 36 ThresholdLockedIn ThresholdState = 2 37 38 // ThresholdActive is the state for a deployment for all blocks after a 39 // retarget period in which the deployment was in the ThresholdLockedIn 40 // state. 41 ThresholdActive ThresholdState = 3 42 43 // ThresholdFailed is the state for a deployment once its expiration 44 // time has been reached and it did not reach the ThresholdLockedIn 45 // state. 46 ThresholdFailed ThresholdState = 4 47 48 // ThresholdInvalid is a deployment that does not exist. 49 ThresholdInvalid ThresholdState = 5 50 ) 51 52 // thresholdStateStrings is a map of ThresholdState values back to their 53 // constant names for pretty printing. 54 var thresholdStateStrings = map[ThresholdState]string{ 55 ThresholdDefined: "ThresholdDefined", 56 ThresholdStarted: "ThresholdStarted", 57 ThresholdLockedIn: "ThresholdLockedIn", 58 ThresholdActive: "ThresholdActive", 59 ThresholdFailed: "ThresholdFailed", 60 } 61 62 // String returns the ThresholdState as a human-readable name. 63 func (t ThresholdState) String() string { 64 if s := thresholdStateStrings[t]; s != "" { 65 return s 66 } 67 return fmt.Sprintf("Unknown ThresholdState (%d)", int(t)) 68 } 69 70 const ( 71 // invalidChoice indicates an invalid choice in the 72 // ThresholdStateTuple. 73 invalidChoice = uint32(0xffffffff) 74 ) 75 76 // ThresholdStateTuple contains the current state and the activated choice, 77 // when valid. 78 type ThresholdStateTuple struct { 79 // state contains the current ThresholdState. 80 State ThresholdState 81 82 // Choice is set to invalidChoice unless state is: ThresholdLockedIn, 83 // ThresholdFailed & ThresholdActive. choice should always be 84 // crosschecked with invalidChoice. 85 Choice uint32 86 } 87 88 // thresholdStateTupleStrings is a map of ThresholdState values back to their 89 // constant names for pretty printing. 90 var thresholdStateTupleStrings = map[ThresholdState]string{ 91 ThresholdDefined: "defined", 92 ThresholdStarted: "started", 93 ThresholdLockedIn: "lockedin", 94 ThresholdActive: "active", 95 ThresholdFailed: "failed", 96 } 97 98 // String returns the ThresholdStateTuple as a human-readable tuple. 99 func (t ThresholdStateTuple) String() string { 100 if s := thresholdStateTupleStrings[t.State]; s != "" { 101 return fmt.Sprintf("%v", s) 102 } 103 return "invalid" 104 } 105 106 // newThresholdState returns an initialized ThresholdStateTuple. 107 func newThresholdState(state ThresholdState, choice uint32) ThresholdStateTuple { 108 return ThresholdStateTuple{State: state, Choice: choice} 109 } 110 111 // thresholdConditionTally is returned by thresholdConditionChecker.Condition 112 // to indicate how many votes an option received. The isAbstain and isNo flags 113 // are accordingly set. Note isAbstain and isNo can NOT be both true at the 114 // same time. 115 type thresholdConditionTally struct { 116 // Vote count 117 count uint32 118 119 // isAbstain is the abstain (or zero vote). 120 isAbstain bool 121 122 // isNo is the hard no vote. 123 isNo bool 124 } 125 126 // thresholdConditionChecker provides a generic interface that is invoked to 127 // determine when a consensus rule change threshold should be changed. 128 type thresholdConditionChecker interface { 129 // BeginTime returns the unix timestamp for the median block time after 130 // which voting on a rule change starts (at the next window). 131 BeginTime() uint64 132 133 // EndTime returns the unix timestamp for the median block time after 134 // which an attempted rule change fails if it has not already been 135 // locked in or activated. 136 EndTime() uint64 137 138 // RuleChangeActivationQuorum is the minimum number of votes required 139 // in a voting period for before we check 140 // RuleChangeActivationThreshold. 141 RuleChangeActivationQuorum() uint32 142 143 // RuleChangeActivationThreshold is the number of votes required in 144 // order to lock in a rule change. 145 RuleChangeActivationThreshold(uint32) uint32 146 147 // RuleChangeActivationInterval is the number of blocks in each threshold 148 // state retarget window. 149 RuleChangeActivationInterval() uint32 150 151 // StakeValidationHeight is the minimum height required before votes start 152 // counting. 153 StakeValidationHeight() int64 154 155 // Condition returns an array of thresholdConditionTally that contains 156 // all votes. By convention isAbstain and isNo can not be true at the 157 // same time. The array is always returned in the same order so that 158 // the consumer can repeatedly call this function without having to 159 // care about said order. Only 1 isNo vote is allowed. By convention 160 // the zero value of the vote as determined by the mask is an isAbstain 161 // vote. 162 Condition(*blockNode, uint32) ([]thresholdConditionTally, error) 163 } 164 165 // thresholdStateCache provides a type to cache the threshold states of each 166 // threshold window for a set of IDs. It also keeps track of which entries have 167 // been modified and therefore need to be written to the database. 168 type thresholdStateCache struct { 169 dbUpdates map[chainhash.Hash]ThresholdStateTuple 170 entries map[chainhash.Hash]ThresholdStateTuple 171 } 172 173 // Lookup returns the threshold state associated with the given hash along with 174 // a boolean that indicates whether or not it is valid. 175 func (c *thresholdStateCache) Lookup(hash chainhash.Hash) (ThresholdStateTuple, bool) { 176 state, ok := c.entries[hash] 177 return state, ok 178 } 179 180 // Update updates the cache to contain the provided hash to threshold state 181 // mapping while properly tracking needed updates flush changes to the database. 182 func (c *thresholdStateCache) Update(hash chainhash.Hash, state ThresholdStateTuple) { 183 if existing, ok := c.entries[hash]; ok && existing == state { 184 return 185 } 186 187 c.dbUpdates[hash] = state 188 c.entries[hash] = state 189 } 190 191 // MarkFlushed marks all of the current udpates as flushed to the database. 192 // This is useful so the caller can ensure the needed database updates are not 193 // lost until they have successfully been written to the database. 194 func (c *thresholdStateCache) MarkFlushed() { 195 for hash := range c.dbUpdates { 196 delete(c.dbUpdates, hash) 197 } 198 } 199 200 // newThresholdCaches returns a new array of caches to be used when calculating 201 // threshold states. 202 func newThresholdCaches(params *chaincfg.Params) map[uint32][]thresholdStateCache { 203 caches := make(map[uint32][]thresholdStateCache) 204 for version := range params.Deployments { 205 caches[version] = make([]thresholdStateCache, 206 len(params.Deployments[version])) 207 for k := range caches[version] { 208 caches[version][k].entries = make(map[chainhash.Hash]ThresholdStateTuple) 209 caches[version][k].dbUpdates = make(map[chainhash.Hash]ThresholdStateTuple) 210 } 211 } 212 return caches 213 } 214 215 // nextThresholdState returns the current rule change threshold state for the 216 // block AFTER the given node and deployment ID. The cache is used to ensure 217 // the threshold states for previous windows are only calculated once. 218 // 219 // This function MUST be called with the chain state lock held (for writes). 220 func (b *BlockChain) nextThresholdState(version uint32, prevNode *blockNode, checker thresholdConditionChecker, cache *thresholdStateCache) (ThresholdStateTuple, error) { 221 // The threshold state for the window that contains the genesis block is 222 // defined by definition. 223 confirmationWindow := int64(checker.RuleChangeActivationInterval()) 224 svh := checker.StakeValidationHeight() 225 if prevNode == nil || prevNode.height+1 < svh+confirmationWindow { 226 return newThresholdState(ThresholdDefined, invalidChoice), nil 227 } 228 229 // Get the ancestor that is the last block of the previous confirmation 230 // window in order to get its threshold state. This can be done because 231 // the state is the same for all blocks within a given window. 232 wantHeight := calcWantHeight(svh, 233 int64(checker.RuleChangeActivationInterval()), 234 prevNode.height+1) 235 prevNode = prevNode.Ancestor(wantHeight) 236 237 // Iterate backwards through each of the previous confirmation windows 238 // to find the most recently cached threshold state. 239 var neededStates []*blockNode 240 for prevNode != nil { 241 // Nothing more to do if the state of the block is already 242 // cached. 243 if _, ok := cache.Lookup(prevNode.hash); ok { 244 break 245 } 246 247 // The start and expiration times are based on the median block 248 // time, so calculate it now. 249 medianTime := prevNode.CalcPastMedianTime() 250 251 // The state is simply defined if the start time hasn't been 252 // been reached yet. 253 if uint64(medianTime.Unix()) < checker.BeginTime() { 254 cache.Update(prevNode.hash, ThresholdStateTuple{ 255 State: ThresholdDefined, 256 Choice: invalidChoice, 257 }) 258 break 259 } 260 261 // Add this node to the list of nodes that need the state 262 // calculated and cached. 263 neededStates = append(neededStates, prevNode) 264 265 // Get the ancestor that is the last block of the previous 266 // confirmation window. 267 prevNode = prevNode.RelativeAncestor(confirmationWindow) 268 } 269 270 // Start with the threshold state for the most recent confirmation 271 // window that has a cached state. 272 stateTuple := newThresholdState(ThresholdDefined, invalidChoice) 273 if prevNode != nil { 274 var ok bool 275 stateTuple, ok = cache.Lookup(prevNode.hash) 276 if !ok { 277 return newThresholdState(ThresholdFailed, 278 invalidChoice), AssertError(fmt.Sprintf( 279 "thresholdState: cache lookup failed "+ 280 "for %v", prevNode.hash)) 281 } 282 } 283 284 // Since each threshold state depends on the state of the previous 285 // window, iterate starting from the oldest unknown window. 286 for neededNum := len(neededStates) - 1; neededNum >= 0; neededNum-- { 287 prevNode := neededStates[neededNum] 288 289 switch stateTuple.State { 290 case ThresholdDefined: 291 // Ensure we are at the minimal require height. 292 if prevNode.height < svh { 293 stateTuple.State = ThresholdDefined 294 break 295 } 296 297 // The deployment of the rule change fails if it expires 298 // before it is accepted and locked in. 299 medianTime := prevNode.CalcPastMedianTime() 300 medianTimeUnix := uint64(medianTime.Unix()) 301 if medianTimeUnix >= checker.EndTime() { 302 stateTuple.State = ThresholdFailed 303 break 304 } 305 306 // Make sure we are on the correct stake version. 307 if b.calcStakeVersion(prevNode) < version { 308 stateTuple.State = ThresholdDefined 309 break 310 } 311 312 // The state must remain in the defined state so long as 313 // a majority of the PoW miners have not upgraded. 314 if !b.isMajorityVersion(int32(version), prevNode, 315 b.chainParams.BlockRejectNumRequired) { 316 317 stateTuple.State = ThresholdDefined 318 break 319 } 320 321 // The state for the rule moves to the started state 322 // once its start time has been reached (and it hasn't 323 // already expired per the above). 324 if medianTimeUnix >= checker.BeginTime() { 325 stateTuple.State = ThresholdStarted 326 } 327 328 case ThresholdStarted: 329 // The deployment of the rule change fails if it expires 330 // before it is accepted and locked in. 331 medianTime := prevNode.CalcPastMedianTime() 332 if uint64(medianTime.Unix()) >= checker.EndTime() { 333 stateTuple.State = ThresholdFailed 334 break 335 } 336 337 // At this point, the rule change is still being voted 338 // on, so iterate backwards through the confirmation 339 // window to count all of the votes in it. 340 var ( 341 counts []thresholdConditionTally 342 totalVotes uint32 343 abstainVotes uint32 344 ) 345 countNode := prevNode 346 for i := int64(0); i < confirmationWindow; i++ { 347 c, err := checker.Condition(countNode, version) 348 if err != nil { 349 return newThresholdState( 350 ThresholdFailed, invalidChoice), err 351 } 352 353 // Create array first time around. 354 if len(counts) == 0 { 355 counts = make([]thresholdConditionTally, len(c)) 356 } 357 358 // Tally votes. 359 for k := range c { 360 counts[k].count += c[k].count 361 counts[k].isAbstain = c[k].isAbstain 362 counts[k].isNo = c[k].isNo 363 if c[k].isAbstain { 364 abstainVotes += c[k].count 365 } else { 366 totalVotes += c[k].count 367 } 368 } 369 370 countNode = countNode.parent 371 } 372 373 // Determine if we have reached quorum. 374 totalNonAbstainVotes := uint32(0) 375 for _, v := range counts { 376 if v.isAbstain && !v.isNo { 377 continue 378 } 379 totalNonAbstainVotes += v.count 380 } 381 if totalNonAbstainVotes < checker.RuleChangeActivationQuorum() { 382 break 383 } 384 385 // The state is locked in if the number of blocks in the 386 // period that voted for the rule change meets the 387 // activation threshold. 388 for k, v := range counts { 389 // We require at least 10% quorum on all votes. 390 if v.count < checker.RuleChangeActivationThreshold(totalVotes) { 391 continue 392 } 393 // Something went over the threshold 394 switch { 395 case !v.isAbstain && !v.isNo: 396 // One of the choices has 397 // reached majority. 398 stateTuple.State = ThresholdLockedIn 399 stateTuple.Choice = uint32(k) 400 case !v.isAbstain && v.isNo: 401 // No choice. Only 1 No per 402 // vote is allowed. A No vote 403 // is required though. 404 stateTuple.State = ThresholdFailed 405 stateTuple.Choice = uint32(k) 406 case v.isAbstain && !v.isNo: 407 // This is the abstain case. 408 // The statemachine is not 409 // supposed to change. 410 continue 411 case v.isAbstain && v.isNo: 412 // Invalid choice. 413 stateTuple.State = ThresholdFailed 414 stateTuple.Choice = uint32(k) 415 } 416 break 417 } 418 419 case ThresholdLockedIn: 420 // The new rule becomes active when its previous state 421 // was locked in. 422 stateTuple.State = ThresholdActive 423 424 // Nothing to do if the previous state is active or failed since 425 // they are both terminal states. 426 case ThresholdActive: 427 case ThresholdFailed: 428 } 429 430 // Update the cache to avoid recalculating the state in the 431 // future. 432 cache.Update(prevNode.hash, stateTuple) 433 } 434 435 return stateTuple, nil 436 } 437 438 // deploymentState returns the current rule change threshold for a given stake 439 // version and deploymentID. The threshold is evaluated from the point of view 440 // of the block node passed in as the first argument to this method. 441 // 442 // It is important to note that, as the variable name indicates, this function 443 // expects the block node prior to the block for which the deployment state is 444 // desired. In other words, the returned deployment state is for the block 445 // AFTER the passed node. 446 // 447 // This function MUST be called with the chain state lock held (for writes). 448 func (b *BlockChain) deploymentState(prevNode *blockNode, version uint32, deploymentID string) (ThresholdStateTuple, error) { 449 for k := range b.chainParams.Deployments[version] { 450 if b.chainParams.Deployments[version][k].Vote.Id == deploymentID { 451 checker := deploymentChecker{ 452 deployment: &b.chainParams.Deployments[version][k], 453 chain: b, 454 } 455 cache := &b.deploymentCaches[version][k] 456 return b.nextThresholdState(version, prevNode, checker, cache) 457 } 458 } 459 460 invalidState := ThresholdStateTuple{ 461 State: ThresholdInvalid, 462 Choice: invalidChoice, 463 } 464 return invalidState, DeploymentError(deploymentID) 465 } 466 467 // stateLastChanged returns the node at which the provided consensus deployment 468 // agenda last changed state. The function will return nil if the state has 469 // never changed. 470 // 471 // This function MUST be called with the chain state lock held (for writes). 472 func (b *BlockChain) stateLastChanged(version uint32, node *blockNode, checker thresholdConditionChecker, cache *thresholdStateCache) (*blockNode, error) { 473 // No state changes are possible if the chain is not yet past stake 474 // validation height and had a full interval to change. 475 confirmationInterval := int64(checker.RuleChangeActivationInterval()) 476 svh := checker.StakeValidationHeight() 477 if node == nil || node.height < svh+confirmationInterval { 478 return nil, nil 479 } 480 481 // Determine the current state. Notice that nextThresholdState always 482 // calculates the state for the block after the provided one, so use the 483 // parent to get the state for the requested block. 484 curState, err := b.nextThresholdState(version, node.parent, checker, cache) 485 if err != nil { 486 return nil, err 487 } 488 489 // Determine the first block of the current confirmation interval in order 490 // to determine block at which the state possibly changed. Since the state 491 // can only change at an interval boundary, loop backwards one interval at 492 // a time to determine when (and if) the state changed. 493 finalNodeHeight := calcWantHeight(svh, confirmationInterval, node.height) 494 node = node.Ancestor(finalNodeHeight + 1) 495 priorStateChangeNode := node 496 for node != nil && node.parent != nil { 497 // As previously mentioned, nextThresholdState always calculates the 498 // state for the block after the provided one, so use the parent to get 499 // the state of the block itself. 500 state, err := b.nextThresholdState(version, node.parent, checker, cache) 501 if err != nil { 502 return nil, err 503 } 504 505 if state.State != curState.State { 506 return priorStateChangeNode, nil 507 } 508 509 // Get the ancestor that is the first block of the previous confirmation 510 // interval. 511 priorStateChangeNode = node 512 node = node.RelativeAncestor(confirmationInterval) 513 } 514 515 return nil, nil 516 } 517 518 // StateLastChangedHeight returns the height at which the provided consensus 519 // deployment agenda last changed state. Note that, unlike the ThresholdState 520 // function, this function returns the information as of the passed block hash. 521 // 522 // This function is safe for concurrent access. 523 func (b *BlockChain) StateLastChangedHeight(hash *chainhash.Hash, version uint32, deploymentID string) (int64, error) { 524 // NOTE: The requirement for the node being fully validated here is strictly 525 // stronger than what is actually required. In reality, all that is needed 526 // is for the block data for the node and all of its ancestors to be 527 // available, but there is not currently any tracking to be able to 528 // efficiently determine that state. 529 node := b.index.LookupNode(hash) 530 if node == nil || !b.index.NodeStatus(node).KnownValid() { 531 return 0, HashError(hash.String()) 532 } 533 534 // Fetch the treshold state cache for the provided deployment id as well as 535 // the condition checker. 536 var cache *thresholdStateCache 537 var checker thresholdConditionChecker 538 for k := range b.chainParams.Deployments[version] { 539 if b.chainParams.Deployments[version][k].Vote.Id == deploymentID { 540 checker = deploymentChecker{ 541 deployment: &b.chainParams.Deployments[version][k], 542 chain: b, 543 } 544 cache = &b.deploymentCaches[version][k] 545 break 546 } 547 } 548 549 if cache == nil { 550 return 0, fmt.Errorf("threshold state cache for agenda with "+ 551 "deployment id (%s) not found", deploymentID) 552 } 553 554 // Find the node at which the current state changed. 555 b.chainLock.Lock() 556 stateNode, err := b.stateLastChanged(version, node, checker, cache) 557 b.chainLock.Unlock() 558 if err != nil { 559 return 0, err 560 } 561 562 var height int64 563 if stateNode != nil { 564 height = stateNode.height 565 } 566 return height, nil 567 } 568 569 // NextThresholdState returns the current rule change threshold state of the 570 // given deployment ID for the block AFTER the provided block hash. 571 // 572 // This function is safe for concurrent access. 573 func (b *BlockChain) NextThresholdState(hash *chainhash.Hash, version uint32, deploymentID string) (ThresholdStateTuple, error) { 574 // NOTE: The requirement for the node being fully validated here is strictly 575 // stronger than what is actually required. In reality, all that is needed 576 // is for the block data for the node and all of its ancestors to be 577 // available, but there is not currently any tracking to be able to 578 // efficiently determine that state. 579 node := b.index.LookupNode(hash) 580 if node == nil || !b.index.NodeStatus(node).KnownValid() { 581 invalidState := ThresholdStateTuple{ 582 State: ThresholdInvalid, 583 Choice: invalidChoice, 584 } 585 return invalidState, HashError(hash.String()) 586 } 587 588 b.chainLock.Lock() 589 state, err := b.deploymentState(node, version, deploymentID) 590 b.chainLock.Unlock() 591 return state, err 592 } 593 594 // isLNFeaturesAgendaActive returns whether or not the LN features agenda vote, 595 // as defined in DCP0002 and DCP0003 has passed and is now active from the point 596 // of view of the passed block node. 597 // 598 // It is important to note that, as the variable name indicates, this function 599 // expects the block node prior to the block for which the deployment state is 600 // desired. In other words, the returned deployment state is for the block 601 // AFTER the passed node. 602 // 603 // This function MUST be called with the chain state lock held (for writes). 604 func (b *BlockChain) isLNFeaturesAgendaActive(prevNode *blockNode) (bool, error) { 605 // Determine the correct deployment version for the LN features consensus 606 // vote as defined in DCP0002 and DCP0003 or treat it as active when voting 607 // is not enabled for the current network. 608 const deploymentID = chaincfg.VoteIDLNFeatures 609 deploymentVer, ok := b.deploymentVers[deploymentID] 610 if !ok { 611 return true, nil 612 } 613 614 state, err := b.deploymentState(prevNode, deploymentVer, deploymentID) 615 if err != nil { 616 return false, err 617 } 618 619 // NOTE: The choice field of the return threshold state is not examined 620 // here because there is only one possible choice that can be active for 621 // the agenda, which is yes, so there is no need to check it. 622 return state.State == ThresholdActive, nil 623 624 } 625 626 // IsLNFeaturesAgendaActive returns whether or not the LN features agenda vote, 627 // as defined in DCP0002 and DCP0003 has passed and is now active for the block 628 // AFTER the current best chain block. 629 // 630 // This function is safe for concurrent access. 631 func (b *BlockChain) IsLNFeaturesAgendaActive() (bool, error) { 632 b.chainLock.Lock() 633 isActive, err := b.isLNFeaturesAgendaActive(b.bestChain.Tip()) 634 b.chainLock.Unlock() 635 return isActive, err 636 } 637 638 // isFixSeqLocksAgendaActive returns whether or not the fix sequence locks 639 // agenda vote, as defined in DCP0004 has passed and is now active from the 640 // point of view of the passed block node. 641 // 642 // It is important to note that, as the variable name indicates, this function 643 // expects the block node prior to the block for which the deployment state is 644 // desired. In other words, the returned deployment state is for the block 645 // AFTER the passed node. 646 // 647 // This function MUST be called with the chain state lock held (for writes). 648 func (b *BlockChain) isFixSeqLocksAgendaActive(prevNode *blockNode) (bool, error) { 649 // Determine the correct deployment version for the fix sequence locks 650 // consensus vote as defined in DCP0004 or treat it as active when voting 651 // is not enabled for the current network. 652 const deploymentID = chaincfg.VoteIDFixLNSeqLocks 653 deploymentVer, ok := b.deploymentVers[deploymentID] 654 if !ok { 655 return true, nil 656 } 657 658 state, err := b.deploymentState(prevNode, deploymentVer, deploymentID) 659 if err != nil { 660 return false, err 661 } 662 663 // NOTE: The choice field of the return threshold state is not examined 664 // here because there is only one possible choice that can be active for 665 // the agenda, which is yes, so there is no need to check it. 666 return state.State == ThresholdActive, nil 667 } 668 669 // IsFixSeqLocksAgendaActive returns whether or not whether or not the fix 670 // sequence locks agenda vote, as defined in DCP0004 has passed and is now 671 // active for the block AFTER the current best chain block. 672 // 673 // This function is safe for concurrent access. 674 func (b *BlockChain) IsFixSeqLocksAgendaActive() (bool, error) { 675 b.chainLock.Lock() 676 isActive, err := b.isFixSeqLocksAgendaActive(b.bestChain.Tip()) 677 b.chainLock.Unlock() 678 return isActive, err 679 } 680 681 // VoteCounts is a compacted struct that is used to message vote counts. 682 type VoteCounts struct { 683 Total uint32 684 TotalAbstain uint32 685 VoteChoices []uint32 686 } 687 688 // getVoteCounts returns the vote counts for the specified version for the 689 // current rule change activation interval. 690 // 691 // This function MUST be called with the chain state lock held (for writes). 692 func (b *BlockChain) getVoteCounts(node *blockNode, version uint32, d *chaincfg.ConsensusDeployment) (VoteCounts, error) { 693 // Don't try to count votes before the stake validation height since there 694 // could not possibly have been any. 695 svh := b.chainParams.StakeValidationHeight 696 if node.height < svh { 697 return VoteCounts{ 698 VoteChoices: make([]uint32, len(d.Vote.Choices)), 699 }, nil 700 } 701 702 // Calculate the final height of the prior interval. 703 rcai := int64(b.chainParams.RuleChangeActivationInterval) 704 height := calcWantHeight(svh, rcai, node.height) 705 706 result := VoteCounts{ 707 VoteChoices: make([]uint32, len(d.Vote.Choices)), 708 } 709 countNode := node 710 for countNode.height > height { 711 for _, vote := range countNode.votes { 712 // Wrong versions do not count. 713 if vote.Version != version { 714 continue 715 } 716 717 // Increase total votes. 718 result.Total++ 719 720 index := d.Vote.VoteIndex(vote.Bits) 721 if index == -1 { 722 // Invalid votes are treated as abstain. 723 result.TotalAbstain++ 724 continue 725 } else if d.Vote.Choices[index].IsAbstain { 726 result.TotalAbstain++ 727 } 728 result.VoteChoices[index]++ 729 } 730 731 countNode = countNode.parent 732 } 733 734 return result, nil 735 } 736 737 // GetVoteCounts returns the vote counts for the specified version and 738 // deployment identifier for the current rule change activation interval. 739 // 740 // This function is safe for concurrent access. 741 func (b *BlockChain) GetVoteCounts(version uint32, deploymentID string) (VoteCounts, error) { 742 for k := range b.chainParams.Deployments[version] { 743 deployment := &b.chainParams.Deployments[version][k] 744 if deployment.Vote.Id == deploymentID { 745 b.chainLock.Lock() 746 counts, err := b.getVoteCounts(b.bestChain.Tip(), version, deployment) 747 b.chainLock.Unlock() 748 return counts, err 749 } 750 } 751 return VoteCounts{}, DeploymentError(deploymentID) 752 } 753 754 // CountVoteVersion returns the total number of version votes for the current 755 // rule change activation interval. 756 // 757 // This function is safe for concurrent access. 758 func (b *BlockChain) CountVoteVersion(version uint32) (uint32, error) { 759 b.chainLock.Lock() 760 defer b.chainLock.Unlock() 761 countNode := b.bestChain.Tip() 762 763 // Don't try to count votes before the stake validation height since there 764 // could not possibly have been any. 765 svh := b.chainParams.StakeValidationHeight 766 if countNode.height < svh { 767 return 0, nil 768 } 769 770 // Calculate the final height of the prior interval. 771 rcai := int64(b.chainParams.RuleChangeActivationInterval) 772 height := calcWantHeight(svh, rcai, countNode.height) 773 774 total := uint32(0) 775 for countNode.height > height { 776 for _, vote := range countNode.votes { 777 // Wrong versions do not count. 778 if vote.Version != version { 779 continue 780 } 781 782 // Increase total votes. 783 total++ 784 } 785 786 countNode = countNode.parent 787 } 788 789 return total, nil 790 }