decred.org/dcrwallet/v3@v3.1.0/wallet/difficulty.go (about) 1 // Copyright (c) 2013-2016 The btcsuite developers 2 // Copyright (c) 2015-2023 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 wallet 7 8 // This code was copied from dcrd/blockchain/difficulty.go and modified for 9 // dcrwallet's header storage. 10 11 import ( 12 "context" 13 "math/big" 14 "time" 15 16 "decred.org/dcrwallet/v3/deployments" 17 "decred.org/dcrwallet/v3/errors" 18 "decred.org/dcrwallet/v3/wallet/walletdb" 19 blockchain "github.com/decred/dcrd/blockchain/standalone/v2" 20 "github.com/decred/dcrd/chaincfg/chainhash" 21 "github.com/decred/dcrd/chaincfg/v3" 22 "github.com/decred/dcrd/dcrutil/v4" 23 "github.com/decred/dcrd/wire" 24 ) 25 26 func (w *Wallet) isTestNet3() bool { 27 return w.chainParams.Net == wire.TestNet3 28 } 29 30 const testNet3MaxDiffActivationHeight = 962928 31 32 var ( 33 // bigZero is 0 represented as a big.Int. It is defined here to avoid 34 // the overhead of creating it multiple times. 35 bigZero = big.NewInt(0) 36 ) 37 38 // findPrevTestNetDifficulty returns the difficulty of the previous block which 39 // did not have the special testnet minimum difficulty rule applied. 40 func (w *Wallet) findPrevTestNetDifficulty(dbtx walletdb.ReadTx, h *wire.BlockHeader, chain []*BlockNode) (uint32, error) { 41 // Search backwards through the chain for the last block without 42 // the special rule applied. 43 blocksPerRetarget := w.chainParams.WorkDiffWindowSize * w.chainParams.WorkDiffWindows 44 for int64(h.Height)%blocksPerRetarget != 0 && h.Bits == w.chainParams.PowLimitBits { 45 if h.PrevBlock == (chainhash.Hash{}) { 46 h = nil 47 break 48 } 49 50 if len(chain) > 0 && int32(h.Height)-int32(chain[0].Header.Height) > 0 { 51 h = chain[h.Height-chain[0].Header.Height-1].Header 52 } else { 53 var err error 54 h, err = w.txStore.GetBlockHeader(dbtx, &h.PrevBlock) 55 if err != nil { 56 return 0, err 57 } 58 } 59 } 60 61 // Return the found difficulty or the minimum difficulty if no 62 // appropriate block was found. 63 lastBits := w.chainParams.PowLimitBits 64 if h != nil { 65 lastBits = h.Bits 66 } 67 return lastBits, nil 68 } 69 70 // calcNextBlake256Diff calculates the required difficulty for the block AFTER 71 // the passed header based on the difficulty retarget rules for the blake256 72 // hash algorithm used at Decred launch. 73 func (w *Wallet) calcNextBlake256Diff(dbtx walletdb.ReadTx, header *wire.BlockHeader, 74 chain []*BlockNode, newBlockTime time.Time) (uint32, error) { 75 76 // Get the old difficulty; if we aren't at a block height where it changes, 77 // just return this. 78 oldDiff := header.Bits 79 oldDiffBig := blockchain.CompactToBig(header.Bits) 80 81 // We're not at a retarget point, return the oldDiff. 82 params := w.chainParams 83 nextHeight := int64(header.Height) + 1 84 if nextHeight%params.WorkDiffWindowSize != 0 { 85 // For networks that support it, allow special reduction of the 86 // required difficulty once too much time has elapsed without 87 // mining a block. 88 // 89 // Note that this behavior is deprecated and thus is only supported on 90 // testnet v3 prior to the max diff activation height. It will be 91 // removed in future version of testnet. 92 if params.ReduceMinDifficulty && (!w.isTestNet3() || nextHeight < 93 testNet3MaxDiffActivationHeight) { 94 95 // Return minimum difficulty when more than the desired 96 // amount of time has elapsed without mining a block. 97 reductionTime := int64(params.MinDiffReductionTime / 98 time.Second) 99 allowMinTime := header.Timestamp.Unix() + reductionTime 100 if newBlockTime.Unix() > allowMinTime { 101 return params.PowLimitBits, nil 102 } 103 104 // The block was mined within the desired timeframe, so 105 // return the difficulty for the last block which did 106 // not have the special minimum difficulty rule applied. 107 return w.findPrevTestNetDifficulty(dbtx, header, chain) 108 } 109 110 return oldDiff, nil 111 } 112 113 // Declare some useful variables. 114 RAFBig := big.NewInt(w.chainParams.RetargetAdjustmentFactor) 115 nextDiffBigMin := blockchain.CompactToBig(header.Bits) 116 nextDiffBigMin.Div(nextDiffBigMin, RAFBig) 117 nextDiffBigMax := blockchain.CompactToBig(header.Bits) 118 nextDiffBigMax.Mul(nextDiffBigMax, RAFBig) 119 120 alpha := params.WorkDiffAlpha 121 122 // Number of nodes to traverse while calculating difficulty. 123 nodesToTraverse := (params.WorkDiffWindowSize * params.WorkDiffWindows) 124 125 // Initialize bigInt slice for the percentage changes for each window period 126 // above or below the target. 127 windowChanges := make([]*big.Int, params.WorkDiffWindows) 128 129 // Regress through all of the previous blocks and store the percent changes 130 // per window period; use bigInts to emulate 64.32 bit fixed point. 131 var olderTime, windowPeriod int64 132 var weights uint64 133 oldHeader := header 134 recentTime := header.Timestamp.Unix() 135 136 for i := int64(0); ; i++ { 137 // Store and reset after reaching the end of every window period. 138 if i%params.WorkDiffWindowSize == 0 && i != 0 { 139 olderTime = oldHeader.Timestamp.Unix() 140 timeDifference := recentTime - olderTime 141 142 // Just assume we're at the target (no change) if we've 143 // gone all the way back to the genesis block. 144 if oldHeader.Height == 0 { 145 timeDifference = int64(params.TargetTimespan / 146 time.Second) 147 } 148 149 timeDifBig := big.NewInt(timeDifference) 150 timeDifBig.Lsh(timeDifBig, 32) // Add padding 151 targetTemp := big.NewInt(int64(params.TargetTimespan / 152 time.Second)) 153 154 windowAdjusted := targetTemp.Div(timeDifBig, targetTemp) 155 156 // Weight it exponentially. Be aware that this could at some point 157 // overflow if alpha or the number of blocks used is really large. 158 windowAdjusted = windowAdjusted.Lsh(windowAdjusted, 159 uint((params.WorkDiffWindows-windowPeriod)*alpha)) 160 161 // Sum up all the different weights incrementally. 162 weights += 1 << uint64((params.WorkDiffWindows-windowPeriod)* 163 alpha) 164 165 // Store it in the slice. 166 windowChanges[windowPeriod] = windowAdjusted 167 168 windowPeriod++ 169 170 recentTime = olderTime 171 } 172 173 if i == nodesToTraverse { 174 break // Exit for loop when we hit the end. 175 } 176 177 // Get the previous node while staying at the genesis block as needed. 178 // Query the header from the provided chain instead of database if 179 // present. The parent of chain[0] is guaranteed to be in stored in the 180 // database. 181 if oldHeader.Height != 0 { 182 if len(chain) > 0 && int32(oldHeader.Height)-int32(chain[0].Header.Height) > 0 { 183 oldHeader = chain[oldHeader.Height-chain[0].Header.Height-1].Header 184 } else { 185 var err error 186 oldHeader, err = w.txStore.GetBlockHeader(dbtx, &oldHeader.PrevBlock) 187 if err != nil { 188 return 0, err 189 } 190 } 191 } 192 } 193 194 // Sum up the weighted window periods. 195 weightedSum := big.NewInt(0) 196 for i := int64(0); i < params.WorkDiffWindows; i++ { 197 weightedSum.Add(weightedSum, windowChanges[i]) 198 } 199 200 // Divide by the sum of all weights. 201 weightsBig := big.NewInt(int64(weights)) 202 weightedSumDiv := weightedSum.Div(weightedSum, weightsBig) 203 204 // Multiply by the old diff. 205 nextDiffBig := weightedSumDiv.Mul(weightedSumDiv, oldDiffBig) 206 207 // Right shift to restore the original padding (restore non-fixed point). 208 nextDiffBig = nextDiffBig.Rsh(nextDiffBig, 32) 209 210 // Check to see if we're over the limits for the maximum allowable retarget; 211 // if we are, return the maximum or minimum except in the case that oldDiff 212 // is zero. 213 if oldDiffBig.Cmp(bigZero) == 0 { // This should never really happen, 214 nextDiffBig.Set(nextDiffBig) // but in case it does... 215 } else if nextDiffBig.Cmp(bigZero) == 0 { 216 nextDiffBig.Set(params.PowLimit) 217 } else if nextDiffBig.Cmp(nextDiffBigMax) == 1 { 218 nextDiffBig.Set(nextDiffBigMax) 219 } else if nextDiffBig.Cmp(nextDiffBigMin) == -1 { 220 nextDiffBig.Set(nextDiffBigMin) 221 } 222 223 // Prevent the difficulty from going lower than the minimum allowed 224 // difficulty. 225 // 226 // Larger numbers result in a lower difficulty, so imposing a minimum 227 // difficulty equates to limiting the maximum target value. 228 if nextDiffBig.Cmp(params.PowLimit) > 0 { 229 nextDiffBig.Set(params.PowLimit) 230 } 231 232 // Prevent the difficulty from going higher than a maximum allowed 233 // difficulty on the test network. This is to prevent runaway difficulty on 234 // testnet by ASICs and GPUs since it's not reasonable to require 235 // high-powered hardware to keep the test network running smoothly. 236 // 237 // Smaller numbers result in a higher difficulty, so imposing a maximum 238 // difficulty equates to limiting the minimum target value. 239 // 240 // This rule is only active on the version 3 test network once the max diff 241 // activation height has been reached. 242 if w.minTestNetTarget != nil && nextDiffBig.Cmp(w.minTestNetTarget) < 0 && 243 (!w.isTestNet3() || nextHeight >= testNet3MaxDiffActivationHeight) { 244 245 nextDiffBig = w.minTestNetTarget 246 } 247 248 // Convert the difficulty to the compact representation and return it. 249 nextDiffBits := blockchain.BigToCompact(nextDiffBig) 250 return nextDiffBits, nil 251 } 252 253 func (w *Wallet) loadCachedBlake3WorkDiffCandidateAnchor() *wire.BlockHeader { 254 w.cachedBlake3WorkDiffCandidateAnchorMu.Lock() 255 defer w.cachedBlake3WorkDiffCandidateAnchorMu.Unlock() 256 257 return w.cachedBlake3WorkDiffCandidateAnchor 258 } 259 260 func (w *Wallet) storeCachedBlake3WorkDiffCandidateAnchor(candidate *wire.BlockHeader) { 261 w.cachedBlake3WorkDiffCandidateAnchorMu.Lock() 262 defer w.cachedBlake3WorkDiffCandidateAnchorMu.Unlock() 263 264 w.cachedBlake3WorkDiffCandidateAnchor = candidate 265 } 266 267 // isBlake3PowAgendaForcedActive returns whether or not the agenda to change the 268 // proof of work hash function to blake3, as defined in DCP0011, is forced 269 // active by the chain parameters. 270 func (w *Wallet) isBlake3PowAgendaForcedActive() bool { 271 const deploymentID = chaincfg.VoteIDBlake3Pow 272 deployment, ok := w.deploymentsByID[deploymentID] 273 if !ok { 274 return false 275 } 276 277 return deployment.ForcedChoiceID == "yes" 278 } 279 280 // calcNextBlake3DiffFromAnchor calculates the required difficulty for the block 281 // AFTER the passed previous block node relative to the given anchor block based 282 // on the difficulty retarget rules defined in DCP0011. 283 // 284 // This function is safe for concurrent access. 285 func (w *Wallet) calcNextBlake3DiffFromAnchor(prevNode, blake3Anchor *wire.BlockHeader) uint32 { 286 // Calculate the time and height deltas as the difference between the 287 // provided block and the blake3 anchor block. 288 // 289 // Notice that if the difficulty prior to the activation point were being 290 // maintained, this would need to be the timestamp and height of the parent 291 // of the blake3 anchor block (except when the anchor is the genesis block) 292 // in order for the absolute calculations to exactly match the behavior of 293 // relative calculations. 294 // 295 // However, since the initial difficulty is reset with the agenda, no 296 // additional offsets are needed. 297 timeDelta := prevNode.Timestamp.Unix() - blake3Anchor.Timestamp.Unix() 298 heightDelta := int64(prevNode.Height) - int64(blake3Anchor.Height) 299 300 // Calculate the next target difficulty using the ASERT algorithm. 301 // 302 // Note that the difficulty of the anchor block is NOT used for the initial 303 // difficulty because the difficulty must be reset due to the change to 304 // blake3 for proof of work. The initial difficulty comes from the chain 305 // parameters instead. 306 params := w.chainParams 307 nextDiff := blockchain.CalcASERTDiff(params.WorkDiffV2Blake3StartBits, 308 params.PowLimit, int64(params.TargetTimePerBlock.Seconds()), timeDelta, 309 heightDelta, params.WorkDiffV2HalfLifeSecs) 310 311 // Prevent the difficulty from going higher than a maximum allowed 312 // difficulty on the test network. This is to prevent runaway difficulty on 313 // testnet by ASICs and GPUs since it's not reasonable to require 314 // high-powered hardware to keep the test network running smoothly. 315 // 316 // Smaller numbers result in a higher difficulty, so imposing a maximum 317 // difficulty equates to limiting the minimum target value. 318 if w.minTestNetTarget != nil && nextDiff < w.minTestNetDiffBits { 319 nextDiff = w.minTestNetDiffBits 320 } 321 322 return nextDiff 323 } 324 325 // calcWantHeight calculates the height of the final block of the previous 326 // interval given a stake validation height, stake validation interval, and 327 // block height. 328 func calcWantHeight(stakeValidationHeight, interval, height int64) int64 { 329 // The adjusted height accounts for the fact the starting validation 330 // height does not necessarily start on an interval and thus the 331 // intervals might not be zero-based. 332 intervalOffset := stakeValidationHeight % interval 333 adjustedHeight := height - intervalOffset - 1 334 return (adjustedHeight - ((adjustedHeight + 1) % interval)) + 335 intervalOffset 336 } 337 338 // checkDifficultyPositional ensures the difficulty specified in the block 339 // header matches the calculated difficulty based on the difficulty retarget 340 // rules. These checks do not, and must not, rely on having the full block data 341 // of all ancestors available. 342 // 343 // This function is safe for concurrent access. 344 func (w *Wallet) checkDifficultyPositional(dbtx walletdb.ReadTx, header *wire.BlockHeader, 345 prevNode *wire.BlockHeader, chain []*BlockNode) error { 346 // ------------------------------------------------------------------------- 347 // The ability to determine whether or not the blake3 proof of work agenda 348 // is active is not possible in the general case here because that relies on 349 // additional context that is not available in the positional checks. 350 // However, it is important to check for valid bits in the positional checks 351 // to protect against various forms of malicious behavior. 352 // 353 // Thus, with the exception of the special cases where it is possible to 354 // definitively determine the agenda is active, allow valid difficulty bits 355 // under both difficulty algorithms while rejecting blocks that satisify 356 // neither here in the positional checks and allow the contextual checks 357 // that happen later to ensure the difficulty bits are valid specifically 358 // for the correct difficulty algorithm as determined by the state of the 359 // blake3 proof of work agenda. 360 // ------------------------------------------------------------------------- 361 362 // Ensure the difficulty specified in the block header matches the 363 // calculated difficulty using the algorithm defined in DCP0011 when the 364 // blake3 proof of work agenda is always active. 365 // 366 // Apply special handling for networks where the agenda is always active to 367 // always require the initial starting difficulty for the first block and to 368 // treat the first block as the anchor once it has been mined. 369 // 370 // This is to done to help provide better difficulty target behavior for the 371 // initial blocks on such networks since the genesis block will necessarily 372 // have a hard-coded timestamp that will very likely be outdated by the time 373 // mining starts. As a result, merely using the genesis block as the anchor 374 // for all blocks would likely result in a lot of the initial blocks having 375 // a significantly lower difficulty than desired because they would all be 376 // behind the ideal schedule relative to that outdated timestamp. 377 if w.isBlake3PowAgendaForcedActive() { 378 var blake3Diff uint32 379 380 // Use the initial starting difficulty for the first block. 381 if prevNode.Height == 0 { 382 blake3Diff = w.chainParams.WorkDiffV2Blake3StartBits 383 } else { 384 // Treat the first block as the anchor for all descendants of it. 385 anchor, err := w.ancestorHeaderAtHeight(dbtx, prevNode, chain, 1) 386 if err != nil { 387 return err 388 } 389 blake3Diff = w.calcNextBlake3DiffFromAnchor(prevNode, anchor) 390 } 391 392 if header.Bits != blake3Diff { 393 err := errors.Errorf("%w: block difficulty of %d is not the expected "+ 394 "value of %d (difficulty algorithm: ASERT)", 395 blockchain.ErrUnexpectedDifficulty, header.Bits, blake3Diff) 396 return errors.E(errors.Consensus, err) 397 } 398 399 return nil 400 } 401 402 // Only the original difficulty algorithm needs to be checked when it is 403 // impossible for the blake3 proof of work agenda to be active or the block 404 // is not solved for blake3. 405 // 406 // Note that since the case where the blake3 proof of work agenda is always 407 // active is already handled above, the only remaining way for the agenda to 408 // be active is for it to have been voted in which requires voting to be 409 // possible (stake validation height), at least one interval of voting, and 410 // one interval of being locked in. 411 isSolvedBlake3 := func(header *wire.BlockHeader) bool { 412 powHash := header.PowHashV2() 413 err := blockchain.CheckProofOfWorkHash(&powHash, header.Bits) 414 return err == nil 415 } 416 rcai := int64(w.chainParams.RuleChangeActivationInterval) 417 svh := w.chainParams.StakeValidationHeight 418 firstPossibleActivationHeight := svh + rcai*2 419 minBlake3BlockVersion := uint32(10) 420 if w.chainParams.Net != wire.MainNet { 421 minBlake3BlockVersion++ 422 } 423 isBlake3PossiblyActive := uint32(header.Version) >= minBlake3BlockVersion && 424 int64(header.Height) >= firstPossibleActivationHeight 425 if !isBlake3PossiblyActive || !isSolvedBlake3(header) { 426 // Ensure the difficulty specified in the block header matches the 427 // calculated difficulty based on the previous block and difficulty 428 // retarget rules for the blake256 hash algorithm used at Decred launch. 429 blake256Diff, err := w.calcNextBlake256Diff(dbtx, prevNode, chain, header.Timestamp) 430 if err != nil { 431 return err 432 } 433 if header.Bits != blake256Diff { 434 err := errors.Errorf("%w: block difficulty of %d is not the expected "+ 435 "value of %d (difficulty algorithm: EMA)", 436 blockchain.ErrUnexpectedDifficulty, header.Bits, blake256Diff) 437 return errors.E(errors.Consensus, err) 438 } 439 440 return nil 441 } 442 443 // At this point, the blake3 proof of work agenda might possibly be active 444 // and the block is solved using blake3, so the agenda is very likely 445 // active. 446 // 447 // Calculating the required difficulty once the agenda activates for the 448 // algorithm defined in DCP0011 requires the block prior to the activation 449 // of the agenda as an anchor. However, as previously discussed, the 450 // additional context needed to definitively determine when the agenda 451 // activated is not available here in the positional checks. 452 // 453 // In light of that, the following logic uses the fact that the agenda could 454 // have only possibly activated at a rule change activation interval to 455 // iterate backwards one interval at a time through all possible candidate 456 // anchors until one of them results in a required difficulty that matches. 457 // 458 // In the case there is a match, the header is assumed to be valid enough to 459 // make it through the positional checks. 460 // 461 // As an additional optimization to avoid a bunch of extra work during the 462 // initial header sync, a candidate anchor that results in a matching 463 // required difficulty is cached and tried first on subsequent descendant 464 // headers since it is very likely to be the correct one. 465 cachedCandidate := w.loadCachedBlake3WorkDiffCandidateAnchor() 466 if cachedCandidate != nil { 467 isAncestor, err := w.isAncestorOf(dbtx, cachedCandidate, prevNode, chain) 468 if err != nil { 469 return err 470 } 471 if isAncestor { 472 blake3Diff := w.calcNextBlake3DiffFromAnchor(prevNode, cachedCandidate) 473 if header.Bits == blake3Diff { 474 return nil 475 } 476 } 477 } 478 479 // Iterate backwards through all possible anchor candidates which 480 // consist of the final blocks of previous rule change activation 481 // intervals so long as the block also has a version that is at least 482 // the minimum version that is enforced before voting on the agenda 483 // could have even started and the agenda could still possibly be 484 // active. 485 finalNodeHeight := calcWantHeight(svh, rcai, int64(header.Height)) 486 candidate, err := w.ancestorHeaderAtHeight(dbtx, prevNode, chain, int32(finalNodeHeight)) 487 if err != nil { 488 return err 489 } 490 for candidate != nil && 491 uint32(candidate.Version) >= minBlake3BlockVersion && 492 int64(candidate.Height) >= firstPossibleActivationHeight-1 { 493 494 blake3Diff := w.calcNextBlake3DiffFromAnchor(prevNode, candidate) 495 if header.Bits == blake3Diff { 496 w.storeCachedBlake3WorkDiffCandidateAnchor(candidate) 497 return nil 498 } 499 candidate, err = w.relativeAncestor(dbtx, candidate, rcai, chain) 500 if err != nil { 501 return err 502 } 503 } 504 505 // At this point, none of the possible difficulties for blake3 matched, so 506 // the agenda is very likely not actually active and therefore the only 507 // remaining valid option is the original difficulty algorithm. 508 // 509 // Ensure the difficulty specified in the block header matches the 510 // calculated difficulty based on the previous block and difficulty retarget 511 // rules for the blake256 hash algorithm used at Decred launch. 512 blake256Diff, err := w.calcNextBlake256Diff(dbtx, prevNode, chain, header.Timestamp) 513 if err != nil { 514 return err 515 } 516 if header.Bits != blake256Diff { 517 err := errors.Errorf("%w: block difficulty of %d is not the expected value "+ 518 "of %d (difficulty algorithm: EMA)", 519 blockchain.ErrUnexpectedDifficulty, header.Bits, blake256Diff) 520 return errors.E(errors.Consensus, err) 521 } 522 523 return nil 524 } 525 526 // estimateSupply returns an estimate of the coin supply for the provided block 527 // height. This is primarily used in the stake difficulty algorithm and relies 528 // on an estimate to simplify the necessary calculations. The actual total 529 // coin supply as of a given block height depends on many factors such as the 530 // number of votes included in every prior block (not including all votes 531 // reduces the subsidy) and whether or not any of the prior blocks have been 532 // invalidated by stakeholders thereby removing the PoW subsidy for them. 533 func estimateSupply(params *chaincfg.Params, height int64) int64 { 534 if height <= 0 { 535 return 0 536 } 537 538 // Estimate the supply by calculating the full block subsidy for each 539 // reduction interval and multiplying it the number of blocks in the 540 // interval then adding the subsidy produced by number of blocks in the 541 // current interval. 542 supply := params.BlockOneSubsidy() 543 reductions := height / params.SubsidyReductionInterval 544 subsidy := params.BaseSubsidy 545 for i := int64(0); i < reductions; i++ { 546 supply += params.SubsidyReductionInterval * subsidy 547 548 subsidy *= params.MulSubsidy 549 subsidy /= params.DivSubsidy 550 } 551 supply += (1 + height%params.SubsidyReductionInterval) * subsidy 552 553 // Blocks 0 and 1 have special subsidy amounts that have already been 554 // added above, so remove what their subsidies would have normally been 555 // which were also added above. 556 supply -= params.BaseSubsidy * 2 557 558 return supply 559 } 560 561 // sumPurchasedTickets returns the sum of the number of tickets purchased in the 562 // most recent specified number of blocks from the point of view of the passed 563 // header. 564 func (w *Wallet) sumPurchasedTickets(dbtx walletdb.ReadTx, startHeader *wire.BlockHeader, chain []*BlockNode, numToSum int64) (int64, error) { 565 var numPurchased int64 566 for h, numTraversed := startHeader, int64(0); h != nil && numTraversed < numToSum; numTraversed++ { 567 numPurchased += int64(h.FreshStake) 568 if h.PrevBlock == (chainhash.Hash{}) { 569 break 570 } 571 if len(chain) > 0 && int32(h.Height)-int32(chain[0].Header.Height) > 0 { 572 h = chain[h.Height-chain[0].Header.Height-1].Header 573 continue 574 } 575 var err error 576 h, err = w.txStore.GetBlockHeader(dbtx, &h.PrevBlock) 577 if err != nil { 578 return 0, err 579 } 580 } 581 582 return numPurchased, nil 583 } 584 585 // calcNextStakeDiffV2 calculates the next stake difficulty for the given set 586 // of parameters using the algorithm defined in DCP0001. 587 // 588 // This function contains the heart of the algorithm and thus is separated for 589 // use in both the actual stake difficulty calculation as well as estimation. 590 // 591 // The caller must perform all of the necessary chain traversal in order to 592 // get the current difficulty, previous retarget interval's pool size plus 593 // its immature tickets, as well as the current pool size plus immature tickets. 594 func calcNextStakeDiffV2(params *chaincfg.Params, nextHeight, curDiff, prevPoolSizeAll, curPoolSizeAll int64) int64 { 595 // Shorter version of various parameter for convenience. 596 votesPerBlock := int64(params.TicketsPerBlock) 597 ticketPoolSize := int64(params.TicketPoolSize) 598 ticketMaturity := int64(params.TicketMaturity) 599 600 // Calculate the difficulty by multiplying the old stake difficulty 601 // with two ratios that represent a force to counteract the relative 602 // change in the pool size (Fc) and a restorative force to push the pool 603 // size towards the target value (Fr). 604 // 605 // Per DCP0001, the generalized equation is: 606 // 607 // nextDiff = min(max(curDiff * Fc * Fr, Slb), Sub) 608 // 609 // The detailed form expands to: 610 // 611 // curPoolSizeAll curPoolSizeAll 612 // nextDiff = curDiff * --------------- * ----------------- 613 // prevPoolSizeAll targetPoolSizeAll 614 // 615 // Slb = w.chainParams.MinimumStakeDiff 616 // 617 // estimatedTotalSupply 618 // Sub = ------------------------------- 619 // targetPoolSize / votesPerBlock 620 // 621 // In order to avoid the need to perform floating point math which could 622 // be problematic across languages due to uncertainty in floating point 623 // math libs, this is further simplified to integer math as follows: 624 // 625 // curDiff * curPoolSizeAll^2 626 // nextDiff = ----------------------------------- 627 // prevPoolSizeAll * targetPoolSizeAll 628 // 629 // Further, the Sub parameter must calculate the denomitor first using 630 // integer math. 631 targetPoolSizeAll := votesPerBlock * (ticketPoolSize + ticketMaturity) 632 curPoolSizeAllBig := big.NewInt(curPoolSizeAll) 633 nextDiffBig := big.NewInt(curDiff) 634 nextDiffBig.Mul(nextDiffBig, curPoolSizeAllBig) 635 nextDiffBig.Mul(nextDiffBig, curPoolSizeAllBig) 636 nextDiffBig.Div(nextDiffBig, big.NewInt(prevPoolSizeAll)) 637 nextDiffBig.Div(nextDiffBig, big.NewInt(targetPoolSizeAll)) 638 639 // Limit the new stake difficulty between the minimum allowed stake 640 // difficulty and a maximum value that is relative to the total supply. 641 // 642 // NOTE: This is intentionally using integer math to prevent any 643 // potential issues due to uncertainty in floating point math libs. The 644 // ticketPoolSize parameter already contains the result of 645 // (targetPoolSize / votesPerBlock). 646 nextDiff := nextDiffBig.Int64() 647 estimatedSupply := estimateSupply(params, nextHeight) 648 maximumStakeDiff := estimatedSupply / ticketPoolSize 649 if nextDiff > maximumStakeDiff { 650 nextDiff = maximumStakeDiff 651 } 652 if nextDiff < params.MinimumStakeDiff { 653 nextDiff = params.MinimumStakeDiff 654 } 655 return nextDiff 656 } 657 658 func (w *Wallet) ancestorHeaderAtHeight(dbtx walletdb.ReadTx, h *wire.BlockHeader, chain []*BlockNode, height int32) (*wire.BlockHeader, error) { 659 switch { 660 case height == int32(h.Height): 661 return h, nil 662 case height > int32(h.Height), height < 0: 663 return nil, nil // dcrd's blockNode.Ancestor returns nil for child heights 664 } 665 666 if len(chain) > 0 && height-int32(chain[0].Header.Height) >= 0 { 667 return chain[height-int32(chain[0].Header.Height)].Header, nil 668 } 669 670 // Because the parent of chain[0] must be in the main chain, the header can 671 // be queried by its main chain height. 672 ns := dbtx.ReadBucket(wtxmgrNamespaceKey) 673 hash, err := w.txStore.GetMainChainBlockHashForHeight(ns, height) 674 if err != nil { 675 return nil, err 676 } 677 return w.txStore.GetBlockHeader(dbtx, &hash) 678 } 679 680 // isAncestorOf returns whether or not node is an ancestor of the provided 681 // target node. 682 // 683 // Replaces dcrd's internal/blockchain func (node *blockNode).IsAncestorOf(target *blockNode). 684 func (w *Wallet) isAncestorOf(dbtx walletdb.ReadTx, node, target *wire.BlockHeader, 685 chain []*BlockNode) (bool, error) { 686 687 ancestorHeader, err := w.ancestorHeaderAtHeight(dbtx, target, chain, int32(node.Height)) 688 if err != nil { 689 return false, err 690 } 691 return ancestorHeader.BlockHash() == node.BlockHash(), nil 692 } 693 694 // relativeAncestor returns the ancestor block node a relative 'distance' blocks 695 // before this node. This is equivalent to calling Ancestor with the node's 696 // height minus provided distance. 697 // 698 // Replaces dcrd's internal/blockchain func (node *blockNode) RelativeAncestor(distance int64). 699 func (w *Wallet) relativeAncestor(dbtx walletdb.ReadTx, node *wire.BlockHeader, 700 distance int64, chain []*BlockNode) (*wire.BlockHeader, error) { 701 702 return w.ancestorHeaderAtHeight(dbtx, node, chain, int32(node.Height)-int32(distance)) 703 } 704 705 // nextRequiredDCP0001PoSDifficulty calculates the required stake difficulty for 706 // the block after the passed previous block node based on the algorithm defined 707 // in DCP0001. 708 func (w *Wallet) nextRequiredDCP0001PoSDifficulty(dbtx walletdb.ReadTx, curHeader *wire.BlockHeader, chain []*BlockNode) (dcrutil.Amount, error) { 709 // Stake difficulty before any tickets could possibly be purchased is 710 // the minimum value. 711 nextHeight := int64(0) 712 if curHeader != nil { 713 nextHeight = int64(curHeader.Height) + 1 714 } 715 stakeDiffStartHeight := int64(w.chainParams.CoinbaseMaturity) + 1 716 if nextHeight < stakeDiffStartHeight { 717 return dcrutil.Amount(w.chainParams.MinimumStakeDiff), nil 718 } 719 720 // Return the previous block's difficulty requirements if the next block 721 // is not at a difficulty retarget interval. 722 intervalSize := w.chainParams.StakeDiffWindowSize 723 curDiff := curHeader.SBits 724 if nextHeight%intervalSize != 0 { 725 return dcrutil.Amount(curDiff), nil 726 } 727 728 // Get the pool size and number of tickets that were immature at the 729 // previous retarget interval. 730 // 731 // NOTE: Since the stake difficulty must be calculated based on existing 732 // blocks, it is always calculated for the block after a given block, so 733 // the information for the previous retarget interval must be retrieved 734 // relative to the block just before it to coincide with how it was 735 // originally calculated. 736 var prevPoolSize int64 737 prevRetargetHeight := nextHeight - intervalSize - 1 738 prevRetargetHeader, err := w.ancestorHeaderAtHeight(dbtx, curHeader, chain, int32(prevRetargetHeight)) 739 if err != nil { 740 return 0, err 741 } 742 if prevRetargetHeader != nil { 743 prevPoolSize = int64(prevRetargetHeader.PoolSize) 744 } 745 ticketMaturity := int64(w.chainParams.TicketMaturity) 746 prevImmatureTickets, err := w.sumPurchasedTickets(dbtx, prevRetargetHeader, chain, ticketMaturity) 747 if err != nil { 748 return 0, err 749 } 750 751 // Return the existing ticket price for the first few intervals to avoid 752 // division by zero and encourage initial pool population. 753 prevPoolSizeAll := prevPoolSize + prevImmatureTickets 754 if prevPoolSizeAll == 0 { 755 return dcrutil.Amount(curDiff), nil 756 } 757 758 // Count the number of currently immature tickets. 759 immatureTickets, err := w.sumPurchasedTickets(dbtx, curHeader, chain, ticketMaturity) 760 if err != nil { 761 return 0, err 762 } 763 764 // Calculate and return the final next required difficulty. 765 curPoolSizeAll := int64(curHeader.PoolSize) + immatureTickets 766 sdiff := calcNextStakeDiffV2(w.chainParams, nextHeight, curDiff, prevPoolSizeAll, curPoolSizeAll) 767 return dcrutil.Amount(sdiff), nil 768 } 769 770 // NextStakeDifficulty returns the ticket price for the next block after the 771 // current main chain tip block. This function only succeeds when DCP0001 is 772 // known to be active. As a fallback, the StakeDifficulty method of 773 // wallet.NetworkBackend may be used to query the next ticket price from a 774 // trusted full node. 775 func (w *Wallet) NextStakeDifficulty(ctx context.Context) (dcrutil.Amount, error) { 776 const op errors.Op = "wallet.NextStakeDifficulty" 777 var sdiff dcrutil.Amount 778 err := walletdb.View(ctx, w.db, func(dbtx walletdb.ReadTx) error { 779 tipHash, tipHeight := w.txStore.MainChainTip(dbtx) 780 if !deployments.DCP0001.Active(tipHeight, w.chainParams.Net) { 781 return errors.E(errors.Deployment, "DCP0001 is not known to be active") 782 } 783 tipHeader, err := w.txStore.GetBlockHeader(dbtx, &tipHash) 784 if err != nil { 785 return err 786 } 787 sdiff, err = w.nextRequiredDCP0001PoSDifficulty(dbtx, tipHeader, nil) 788 return err 789 }) 790 if err != nil { 791 return 0, errors.E(op, err) 792 } 793 return sdiff, nil 794 } 795 796 // NextStakeDifficultyAfterHeader returns the ticket price for the child of h. 797 // All headers of ancestor blocks of h must be recorded by the wallet. This 798 // function only succeeds when DCP0001 is known to be active. 799 func (w *Wallet) NextStakeDifficultyAfterHeader(ctx context.Context, h *wire.BlockHeader) (dcrutil.Amount, error) { 800 const op errors.Op = "wallet.NextStakeDifficultyAfterHeader" 801 if !deployments.DCP0001.Active(int32(h.Height), w.chainParams.Net) { 802 return 0, errors.E(op, errors.Deployment, "DCP0001 is not known to be active") 803 } 804 var sdiff dcrutil.Amount 805 err := walletdb.View(ctx, w.db, func(dbtx walletdb.ReadTx) error { 806 var err error 807 sdiff, err = w.nextRequiredDCP0001PoSDifficulty(dbtx, h, nil) 808 return err 809 }) 810 if err != nil { 811 return 0, errors.E(op, err) 812 } 813 return sdiff, nil 814 } 815 816 // ValidateHeaderChainDifficulties validates the PoW and PoS difficulties of all 817 // blocks in chain[idx:]. The parent of chain[0] must be recorded as wallet 818 // main chain block. If a consensus violation is caught, a subslice of chain 819 // beginning with the invalid block is returned. 820 func (w *Wallet) ValidateHeaderChainDifficulties(ctx context.Context, chain []*BlockNode, idx int) ([]*BlockNode, error) { 821 var invalid []*BlockNode 822 err := walletdb.View(ctx, w.db, func(dbtx walletdb.ReadTx) error { 823 var err error 824 invalid, err = w.validateHeaderChainDifficulties(dbtx, chain, idx) 825 return err 826 }) 827 return invalid, err 828 } 829 830 func (w *Wallet) validateHeaderChainDifficulties(dbtx walletdb.ReadTx, chain []*BlockNode, idx int) ([]*BlockNode, error) { 831 const op errors.Op = "wallet.validateHeaderChainDifficulties" 832 833 inMainChain, _ := w.txStore.BlockInMainChain(dbtx, &chain[0].Header.PrevBlock) 834 if !inMainChain { 835 return nil, errors.E(op, errors.Bug, "parent of chain[0] is not in main chain") 836 } 837 838 var parent *wire.BlockHeader 839 840 for ; idx < len(chain); idx++ { 841 n := chain[idx] 842 h := n.Header 843 hash := n.Hash 844 if parent == nil && h.Height != 0 { 845 if idx == 0 { 846 var err error 847 parent, err = w.txStore.GetBlockHeader(dbtx, &h.PrevBlock) 848 if err != nil { 849 return nil, err 850 } 851 } else { 852 parent = chain[idx-1].Header 853 } 854 } 855 856 // Validate advertised and performed work 857 err := w.checkDifficultyPositional(dbtx, h, parent, chain) 858 if err != nil { 859 return nil, errors.E(op, err) 860 } 861 // Check V1 Proof of Work 862 err = blockchain.CheckProofOfWork(hash, h.Bits, w.chainParams.PowLimit) 863 if err != nil { 864 // Check V2 Proof of Work 865 blake3PowHash := n.Header.PowHashV2() 866 err = blockchain.CheckProofOfWork(&blake3PowHash, h.Bits, 867 w.chainParams.PowLimit) 868 } 869 if err != nil { 870 return chain[idx:], errors.E(op, errors.Consensus, err) 871 } 872 873 // Validate ticket price 874 if deployments.DCP0001.Active(int32(h.Height), w.chainParams.Net) { 875 sdiff, err := w.nextRequiredDCP0001PoSDifficulty(dbtx, parent, chain) 876 if err != nil { 877 return nil, errors.E(op, err) 878 } 879 if dcrutil.Amount(h.SBits) != sdiff { 880 err := errors.Errorf("%v has invalid PoS difficulty, got %v, want %v", 881 hash, dcrutil.Amount(h.SBits), sdiff) 882 return chain[idx:], errors.E(op, errors.Consensus, err) 883 } 884 } 885 886 parent = h 887 } 888 889 return nil, nil 890 }