Changeset View
Standalone View
src/pow.cpp
// Copyright (c) 2009-2010 Satoshi Nakamoto | // Copyright (c) 2009-2010 Satoshi Nakamoto | ||||
// Copyright (c) 2009-2016 The Bitcoin Core developers | // Copyright (c) 2009-2016 The Bitcoin Core developers | ||||
// Copyright (c) 2017 The Bitcoin developers | |||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include "pow.h" | #include "pow.h" | ||||
#include "arith_uint256.h" | #include "arith_uint256.h" | ||||
#include "chain.h" | #include "chain.h" | ||||
#include "primitives/block.h" | #include "primitives/block.h" | ||||
▲ Show 20 Lines • Show All 133 Lines • ▼ Show 20 Lines | bool CheckProofOfWork(uint256 hash, uint32_t nBits, | ||||
// Check proof of work matches claimed amount | // Check proof of work matches claimed amount | ||||
if (UintToArith256(hash) > bnTarget) { | if (UintToArith256(hash) > bnTarget) { | ||||
return false; | return false; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
/** | |||||
* Compute the a target based on the work done between 2 blocks and the time | |||||
* required to produce that work. | |||||
*/ | |||||
static arith_uint256 ComputeTarget(const CBlockIndex *pindexFirst, | |||||
const CBlockIndex *pindexLast, | |||||
const Consensus::Params ¶ms) { | |||||
assert(pindexLast->nHeight > pindexFirst->nHeight); | |||||
schancel: I assume there is no chance that these are from different chains due to other mechanisms? | |||||
/** | |||||
* From the total work done and the time it took to produce that much work, | |||||
* we can deduce how much work we expect to be produced in the targeted time | |||||
* between blocks. | |||||
*/ | |||||
arith_uint256 work = pindexLast->nChainWork - pindexFirst->nChainWork; | |||||
work *= params.nPowTargetSpacing; | |||||
// In order to avoid difficulty cliffs, we bound the amplitude of the | |||||
// adjustement we are going to do. | |||||
assert(pindexLast->nTime > pindexFirst->nTime); | |||||
kyuupichanUnsubmitted Not Done Inline ActionsThere are (patholigcal) cases where this assert could fail if MTP is not used. Since the condition is protected against anyway by the bounds you added immediately below, I suggest we remove this assert. kyuupichan: There are (patholigcal) cases where this assert could fail if MTP is not used. Since the… | |||||
schancelUnsubmitted Not Done Inline ActionsBlocks for this case should be rejected by the network. However, if they did get through, what would be the outcome of this assert triggering? schancel: Blocks for this case should be rejected by the network. However, if they did get through, what… | |||||
deadalnixAuthorUnsubmitted Not Done Inline ActionsNode crash. deadalnix: Node crash. | |||||
int64_t nActualTimespan = pindexLast->nTime - pindexFirst->nTime; | |||||
if (nActualTimespan > 288 * params.nPowTargetSpacing) { | |||||
nActualTimespan = 288 * params.nPowTargetSpacing; | |||||
schancelUnsubmitted Not Done Inline Actions144 * params.nPowerTargetSpacing would be the ideal value to find -- this caps it at twice that? If so, should we use 2 * (pindexLast->nHeight - pindexFirst->nHeight) * params.nPowerTargetSpacing ? schancel: `144 * params.nPowerTargetSpacing` would be the ideal value to find -- this caps it at twice… | |||||
} else if (nActualTimespan < 72 * params.nPowTargetSpacing) { | |||||
nActualTimespan = 72 * params.nPowTargetSpacing; | |||||
schancelUnsubmitted Not Done Inline ActionsSimilar question schancel: Similar question | |||||
} | |||||
work /= nActualTimespan; | |||||
/** | |||||
* We need to compute T = (2^256 / W) - 1 but 2^256 doesn't fit in 256 bits. | |||||
* By expressing 1 as W / W, we get (2^256 - W) / W, and we can compute | |||||
* 2^256 - W as the complement of W. | |||||
*/ | |||||
return (-work) / work; | |||||
schancelUnsubmitted Not Done Inline ActionsSince this is uint, I assume -work on this class returns the two's complement? The implementation on base_uint class looks like it to me, but it's been a long time since dealing with this. schancel: Since this is uint, I assume `-work` on this class returns the two's complement? The… | |||||
deadalnixAuthorUnsubmitted Not Done Inline ActionsYes, -x return the 2's complement. deadalnix: Yes, -x return the 2's complement. | |||||
} | |||||
/** | |||||
* To reduce the impact of timestamp manipulation, we select the block we are | |||||
* basing our computation on via a median of 3. | |||||
*/ | |||||
static const CBlockIndex *GetSuitableBlock(const CBlockIndex *pindex) { | |||||
assert(pindex->nHeight >= 3); | |||||
/** | |||||
* In order to avoid a block is a very skewed timestamp to have too much | |||||
* influence, we select the median of the 3 top most blocks as a starting | |||||
* point. | |||||
*/ | |||||
const CBlockIndex *blocks[3]; | |||||
blocks[2] = pindex; | |||||
blocks[1] = pindex->pprev; | |||||
blocks[0] = blocks[1]->pprev; | |||||
// Sorting network. | |||||
if (blocks[0]->nTime > blocks[2]->nTime) { | |||||
std::swap(blocks[0], blocks[2]); | |||||
} | |||||
if (blocks[0]->nTime > blocks[1]->nTime) { | |||||
std::swap(blocks[0], blocks[1]); | |||||
} | |||||
if (blocks[1]->nTime > blocks[2]->nTime) { | |||||
std::swap(blocks[1], blocks[2]); | |||||
} | |||||
// We should have our candidate in the middle now. | |||||
return blocks[1]; | |||||
} | |||||
/** | |||||
* Compute the next required proof of work using a weighted average of the | |||||
* estimated hashrate per block. | |||||
* | |||||
* Using a weighted average ensure that the timestamp parameter cancels out in | |||||
* most of the calculation - except for the timestamp of the first and last | |||||
* block. Because timestamps are the least trustworthy information we have as | |||||
* input, this ensures the algorithm is more resistant to malicious inputs. | |||||
*/ | |||||
uint32_t GetNextCashWorkRequired(const CBlockIndex *pindexPrev, | |||||
const CBlockHeader *pblock, | |||||
const Consensus::Params ¶ms) { | |||||
// This cannot handle the genesis block and early blocks in general. | |||||
assert(pindexPrev); | |||||
// Special difficulty rule for testnet: | |||||
// If the new block's timestamp is more than 2* 10 minutes then allow | |||||
// mining of a min-difficulty block. | |||||
if (params.fPowAllowMinDifficultyBlocks && | |||||
(pblock->GetBlockTime() > | |||||
pindexPrev->GetBlockTime() + 2 * params.nPowTargetSpacing)) { | |||||
return UintToArith256(params.powLimit).GetCompact(); | |||||
} | |||||
// Compute the difficulty based on the full adjustement interval. | |||||
const uint32_t nHeight = pindexPrev->nHeight; | |||||
assert(nHeight >= params.DifficultyAdjustmentInterval()); | |||||
// Get the last suitable block of the difficulty interval. | |||||
const CBlockIndex *pindexLast = GetSuitableBlock(pindexPrev); | |||||
schancelUnsubmitted Not Done Inline ActionsThis should always be the n-2 block assuming ordered timestamps? schancel: This should always be the `n-2` block assuming ordered timestamps? | |||||
deadalnixAuthorUnsubmitted Not Done Inline ActionsThis is n-1 most of the time. deadalnix: This is n-1 most of the time. | |||||
assert(pindexLast); | |||||
// Get the first suitable block of the difficulty interval. | |||||
uint32_t nHeightFirst = nHeight - 144; | |||||
const CBlockIndex *pindexFirst = | |||||
GetSuitableBlock(pindexPrev->GetAncestor(nHeightFirst)); | |||||
assert(pindexFirst); | |||||
// Compute the target based on time and work done during the interval. | |||||
const arith_uint256 nextTarget = | |||||
ComputeTarget(pindexFirst, pindexLast, params); | |||||
const arith_uint256 powLimit = UintToArith256(params.powLimit); | |||||
if (nextTarget > powLimit) { | |||||
return powLimit.GetCompact(); | |||||
} | |||||
return nextTarget.GetCompact(); | |||||
} |
I assume there is no chance that these are from different chains due to other mechanisms?