mirror of
https://github.com/jwinterm/myriadcoin.git
synced 2026-10-17 05:41:34 +02:00
579 lines
20 KiB
C++
579 lines
20 KiB
C++
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
|
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#include "pow.h"
|
|
|
|
#include "arith_uint256.h"
|
|
#include "chain.h"
|
|
#include "chainparams.h"
|
|
#include "primitives/block.h"
|
|
#include "uint256.h"
|
|
#include "util.h"
|
|
#include "bignum.h"
|
|
|
|
unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params, int algo)
|
|
{
|
|
const arith_uint256 nProofOfWorkLimit = UintToArith256(params.powLimit);
|
|
|
|
// Genesis block
|
|
if (pindexLast == NULL)
|
|
{
|
|
if(fDebug)
|
|
{
|
|
LogPrintf("pindexLast is null. returning nProofOfWorkLimit\n");
|
|
}
|
|
return nProofOfWorkLimit.GetCompact();
|
|
}
|
|
|
|
// find previous block with same algo
|
|
const CBlockIndex* pindexPrev = GetLastBlockIndexForAlgo(pindexLast, algo);
|
|
|
|
// Genesis block
|
|
if (pindexPrev == NULL)
|
|
{
|
|
if(fDebug)
|
|
{
|
|
LogPrintf("pindexPrev is null. returning nProofOfWorkLimit\n");
|
|
}
|
|
return nProofOfWorkLimit.GetCompact();
|
|
}
|
|
|
|
const CBlockIndex* pindexFirst = NULL;
|
|
|
|
if( (pindexLast->nHeight >= params.nBlockTimeWarpPreventStart1) && (pindexLast->nHeight < params.nBlockTimeWarpPreventStart2) )
|
|
{
|
|
// find first block in averaging interval
|
|
// Go back by what we want to be nAveragingInterval blocks
|
|
pindexFirst = pindexPrev;
|
|
for (int i = 0; pindexFirst && i < params.nAveragingInterval - 1; i++)
|
|
{
|
|
pindexFirst = pindexFirst->pprev;
|
|
pindexFirst = GetLastBlockIndexForAlgo(pindexFirst, algo);
|
|
}
|
|
if (pindexFirst == NULL)
|
|
return nProofOfWorkLimit.GetCompact(); // not nAveragingInterval blocks of this algo available
|
|
|
|
// check block before first block for time warp
|
|
const CBlockIndex* pindexFirstPrev = pindexFirst->pprev;
|
|
if (pindexFirstPrev == NULL)
|
|
return nProofOfWorkLimit.GetCompact();
|
|
pindexFirstPrev = GetLastBlockIndexForAlgo(pindexFirstPrev, algo);
|
|
if (pindexFirstPrev == NULL)
|
|
return nProofOfWorkLimit.GetCompact();
|
|
// take previous block if block times are out of order
|
|
if (pindexFirstPrev->GetBlockTime() > pindexFirst->GetBlockTime())
|
|
{
|
|
LogPrintf(" First blocks out of order times, swapping: %d %d\n", pindexFirstPrev->GetBlockTime(), pindexFirst->GetBlockTime());
|
|
pindexFirst = pindexFirstPrev;
|
|
}
|
|
|
|
}
|
|
else if ( (pindexLast->nHeight >= params.nBlockTimeWarpPreventStart2) && (pindexLast->nHeight < params.nBlockTimeWarpPreventStart3) )
|
|
{
|
|
// find first block in averaging interval
|
|
// Go back by what we want to be nAveragingInterval blocks
|
|
pindexFirst = pindexPrev;
|
|
for (int i = 0; pindexFirst && i < params.nAveragingInterval - 1; i++)
|
|
{
|
|
pindexFirst = pindexFirst->pprev;
|
|
pindexFirst = GetLastBlockIndexForAlgo(pindexFirst, algo);
|
|
}
|
|
if (pindexFirst == NULL)
|
|
return nProofOfWorkLimit.GetCompact(); // not nAveragingInterval blocks of this algo available
|
|
|
|
const CBlockIndex* pindexFirstPrev;
|
|
for ( ;; )
|
|
{
|
|
// check blocks before first block for time warp
|
|
pindexFirstPrev = pindexFirst->pprev;
|
|
if (pindexFirstPrev == NULL)
|
|
return nProofOfWorkLimit.GetCompact();
|
|
pindexFirstPrev = GetLastBlockIndexForAlgo(pindexFirstPrev, algo);
|
|
if (pindexFirstPrev == NULL)
|
|
return nProofOfWorkLimit.GetCompact();
|
|
// take previous block if block times are out of order
|
|
if (pindexFirstPrev->GetBlockTime() > pindexFirst->GetBlockTime())
|
|
{
|
|
LogPrintf(" First blocks out of order times, swapping: %d %d\n", pindexFirstPrev->GetBlockTime(), pindexFirst->GetBlockTime());
|
|
pindexFirst = pindexFirstPrev;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// find first block in averaging interval
|
|
// Go back by what we want to be nAveragingInterval blocks
|
|
pindexFirst = pindexPrev;
|
|
for (int i = 0; pindexFirst && i < params.nAveragingInterval - 1; i++)
|
|
{
|
|
pindexFirst = pindexFirst->pprev;
|
|
pindexFirst = GetLastBlockIndexForAlgo(pindexFirst, algo);
|
|
if (pindexFirst == NULL)
|
|
{
|
|
if(fDebug)
|
|
{
|
|
LogPrintf("pindexFirst is null. returning nProofOfWorkLimit\n");
|
|
}
|
|
return nProofOfWorkLimit.GetCompact();
|
|
}
|
|
}
|
|
}
|
|
|
|
int64_t nActualTimespan;
|
|
|
|
if (pindexLast->nHeight >= params.nBlockTimeWarpPreventStart3)
|
|
{
|
|
nActualTimespan = pindexPrev->GetMedianTimePast() - pindexFirst->GetMedianTimePast();
|
|
if(fDebug)
|
|
{
|
|
LogPrintf(" nActualTimespan = %d before bounds %d %d\n", nActualTimespan, pindexPrev->GetMedianTimePast(), pindexFirst->GetMedianTimePast());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nActualTimespan = pindexPrev->GetBlockTime() - pindexFirst->GetBlockTime();
|
|
if(fDebug)
|
|
{
|
|
LogPrintf(" nActualTimespan = %d before bounds %d %d\n", nActualTimespan, pindexPrev->GetBlockTime(), pindexFirst->GetBlockTime());
|
|
}
|
|
}
|
|
|
|
// Time warp mitigation: Don't adjust difficulty if time is negative
|
|
if ( (pindexLast->nHeight >= params.nBlockTimeWarpPreventStart1) && (pindexLast->nHeight < params.nBlockTimeWarpPreventStart2) )
|
|
{
|
|
if (nActualTimespan < 0)
|
|
{
|
|
if(fDebug)
|
|
{
|
|
LogPrintf(" nActualTimespan negative %d\n", nActualTimespan);
|
|
LogPrintf(" Keeping: %08x \n", pindexPrev->nBits);
|
|
}
|
|
return pindexPrev->nBits;
|
|
}
|
|
}
|
|
|
|
if (pindexLast->nHeight >= params.Phase2Timespan_Start)
|
|
{
|
|
return CalculateNextWorkRequiredV2(pindexPrev, pindexFirst, params, algo, nActualTimespan);
|
|
}
|
|
else
|
|
{
|
|
return CalculateNextWorkRequiredV1(pindexPrev, pindexFirst, params, algo, nActualTimespan, pindexLast->nHeight);
|
|
}
|
|
}
|
|
|
|
unsigned int CalculateNextWorkRequiredV1(const CBlockIndex* pindexPrev, const CBlockIndex* pindexFirst, const Consensus::Params& params, int algo, int64_t nActualTimespan, int nHeight)
|
|
{
|
|
const arith_uint256 nProofOfWorkLimit = UintToArith256(params.powLimit);
|
|
|
|
int64_t nTargetSpacingPerAlgo = params.nPowTargetSpacingV1 * NUM_ALGOS; // 30 * 5 = 150s per algo
|
|
int64_t nAveragingTargetTimespan = params.nAveragingInterval * nTargetSpacingPerAlgo; // 10 * 150 = 1500s, 25 minutes
|
|
int64_t nMinActualTimespanV1 = nAveragingTargetTimespan * (100 - params.nMaxAdjustUpV1) / 100;
|
|
int64_t nMinActualTimespanV2 = nAveragingTargetTimespan * (100 - params.nMaxAdjustUpV2) / 100;
|
|
int64_t nMaxActualTimespan = nAveragingTargetTimespan * (100 + params.nMaxAdjustDown) / 100;
|
|
|
|
int64_t nMinActualTimespan;
|
|
if (nHeight >= params.nBlockDiffAdjustV2)
|
|
{
|
|
nMinActualTimespan = nMinActualTimespanV2;
|
|
}
|
|
else
|
|
{
|
|
nMinActualTimespan = nMinActualTimespanV1;
|
|
}
|
|
|
|
if (nActualTimespan < nMinActualTimespan)
|
|
nActualTimespan = nMinActualTimespan;
|
|
if (nActualTimespan > nMaxActualTimespan)
|
|
nActualTimespan = nMaxActualTimespan;
|
|
|
|
if(fDebug)
|
|
{
|
|
LogPrintf(" nActualTimespan = %d after bounds %d %d\n", nActualTimespan, nMinActualTimespan, nMaxActualTimespan);
|
|
}
|
|
|
|
// Retarget
|
|
arith_uint256 bnNew;
|
|
arith_uint256 bnOld;
|
|
bnNew.SetCompact(pindexPrev->nBits);
|
|
bnOld = bnNew;
|
|
bnNew *= nActualTimespan;
|
|
bnNew /= nAveragingTargetTimespan;
|
|
if (bnNew > nProofOfWorkLimit)
|
|
bnNew = nProofOfWorkLimit;
|
|
|
|
/// debug print
|
|
if(fDebug)
|
|
{
|
|
LogPrintf("CalculateNextWorkRequiredV1(Algo=%d): RETARGET\n", algo);
|
|
LogPrintf("CalculateNextWorkRequiredV1(Algo=%d): nTargetTimespan = %d nActualTimespan = %d\n", algo, nAveragingTargetTimespan, nActualTimespan);
|
|
LogPrintf("CalculateNextWorkRequiredV1(Algo=%d): Before: %08x %s\n", algo, pindexPrev->nBits, bnOld.ToString());
|
|
LogPrintf("CalculateNextWorkRequiredV1(Algo=%d): After: %08x %s\n", algo, bnNew.GetCompact(), bnNew.ToString());
|
|
}
|
|
|
|
return bnNew.GetCompact();
|
|
}
|
|
|
|
|
|
unsigned int CalculateNextWorkRequiredV2(const CBlockIndex* pindexPrev, const CBlockIndex* pindexFirst, const Consensus::Params& params, int algo, int64_t nActualTimespan)
|
|
{
|
|
const arith_uint256 nProofOfWorkLimit = UintToArith256(params.powLimit);
|
|
|
|
int64_t nTargetSpacingPerAlgo = params.nPowTargetSpacingV2 * NUM_ALGOS; // 60 * 5 = 300s per algo
|
|
int64_t nAveragingTargetTimespan = params.nAveragingInterval * nTargetSpacingPerAlgo; // 10 * 300 = 3000s, 50 minutes
|
|
int64_t nMinActualTimespan = nAveragingTargetTimespan * (100 - params.nMaxAdjustUpV2) / 100;
|
|
int64_t nMaxActualTimespan = nAveragingTargetTimespan * (100 + params.nMaxAdjustDown) / 100;
|
|
|
|
if (nActualTimespan < nMinActualTimespan)
|
|
nActualTimespan = nMinActualTimespan;
|
|
if (nActualTimespan > nMaxActualTimespan)
|
|
nActualTimespan = nMaxActualTimespan;
|
|
|
|
if(fDebug)
|
|
{
|
|
LogPrintf(" nActualTimespan = %d after bounds %d %d\n", nActualTimespan, nMinActualTimespan, nMaxActualTimespan);
|
|
}
|
|
|
|
arith_uint256 bnNew;
|
|
arith_uint256 bnOld;
|
|
bnNew.SetCompact(pindexPrev->nBits);
|
|
bnOld = bnNew;
|
|
bnNew *= nActualTimespan;
|
|
bnNew /= nAveragingTargetTimespan;
|
|
if (bnNew > nProofOfWorkLimit)
|
|
bnNew = nProofOfWorkLimit;
|
|
|
|
/// debug print
|
|
if(fDebug)
|
|
{
|
|
LogPrintf("CalculateNextWorkRequiredV2(Algo=%d): RETARGET\n", algo);
|
|
LogPrintf("CalculateNextWorkRequiredV2(Algo=%d): nTargetTimespan = %d nActualTimespan = %d\n", algo, nAveragingTargetTimespan, nActualTimespan);
|
|
LogPrintf("CalculateNextWorkRequiredV2(Algo=%d): Before: %08x %s\n", algo, pindexPrev->nBits, bnOld.ToString());
|
|
LogPrintf("CalculateNextWorkRequiredV2(Algo=%d): After: %08x %s\n", algo, bnNew.GetCompact(), bnNew.ToString());
|
|
}
|
|
|
|
return bnNew.GetCompact();
|
|
}
|
|
|
|
|
|
bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params& params)
|
|
{
|
|
bool fNegative;
|
|
bool fOverflow;
|
|
arith_uint256 bnTarget;
|
|
|
|
bnTarget.SetCompact(nBits, &fNegative, &fOverflow);
|
|
|
|
// Check range
|
|
if (fNegative || bnTarget == 0 || fOverflow || bnTarget > UintToArith256(params.powLimit))
|
|
return error("CheckProofOfWork(): nBits below minimum work");
|
|
|
|
// Check proof of work matches claimed amount
|
|
if (UintToArith256(hash) > bnTarget)
|
|
return error("CheckProofOfWork(): hash doesn't match nBits");
|
|
|
|
return true;
|
|
}
|
|
|
|
arith_uint256 GetBlockProofBase(const CBlockIndex& block)
|
|
{
|
|
arith_uint256 bnTarget;
|
|
bool fNegative;
|
|
bool fOverflow;
|
|
bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow);
|
|
if (fNegative || fOverflow || bnTarget == 0)
|
|
return 0;
|
|
// We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256
|
|
// as it's too large for a arith_uint256. However, as 2**256 is at least as large
|
|
// as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1,
|
|
// or ~bnTarget / (nTarget+1) + 1.
|
|
return (~bnTarget / (bnTarget + 1)) + 1;
|
|
}
|
|
|
|
int GetAlgoWorkFactor(int algo)
|
|
{
|
|
switch (algo)
|
|
{
|
|
case ALGO_SHA256D:
|
|
return 1;
|
|
// work factor = absolute work ratio * optimisation factor
|
|
case ALGO_SCRYPT:
|
|
return 1024 * 4;
|
|
case ALGO_GROESTL:
|
|
return 64 * 8;
|
|
case ALGO_SKEIN:
|
|
return 4 * 6;
|
|
case ALGO_QUBIT:
|
|
return 128 * 8;
|
|
default:
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
arith_uint256 GetPrevWorkForAlgo(const CBlockIndex& block, int algo)
|
|
{
|
|
const CBlockIndex* pindex = █
|
|
while (pindex != NULL)
|
|
{
|
|
if (pindex->GetAlgo() == algo)
|
|
{
|
|
return GetBlockProofBase(*pindex);
|
|
}
|
|
pindex = pindex->pprev;
|
|
}
|
|
return UintToArith256(Params().GetConsensus().powLimit);
|
|
}
|
|
|
|
arith_uint256 GetPrevWorkForAlgoWithDecay(const CBlockIndex& block, int algo)
|
|
{
|
|
int nDistance = 0;
|
|
arith_uint256 nWork;
|
|
const CBlockIndex* pindex = █
|
|
while (pindex != NULL)
|
|
{
|
|
if (nDistance > 32)
|
|
{
|
|
return UintToArith256(Params().GetConsensus().powLimit);
|
|
}
|
|
if (pindex->GetAlgo() == algo)
|
|
{
|
|
arith_uint256 nWork = GetBlockProofBase(*pindex);
|
|
nWork *= (32 - nDistance);
|
|
nWork /= 32;
|
|
if (nWork < UintToArith256(Params().GetConsensus().powLimit))
|
|
nWork = UintToArith256(Params().GetConsensus().powLimit);
|
|
return nWork;
|
|
}
|
|
pindex = pindex->pprev;
|
|
nDistance++;
|
|
}
|
|
return UintToArith256(Params().GetConsensus().powLimit);
|
|
}
|
|
|
|
arith_uint256 GetPrevWorkForAlgoWithDecay2(const CBlockIndex& block, int algo)
|
|
{
|
|
int nDistance = 0;
|
|
arith_uint256 nWork;
|
|
const CBlockIndex* pindex = █
|
|
while (pindex != NULL)
|
|
{
|
|
if (nDistance > 32)
|
|
{
|
|
return arith_uint256(0);
|
|
}
|
|
if (pindex->GetAlgo() == algo)
|
|
{
|
|
arith_uint256 nWork = GetBlockProofBase(*pindex);
|
|
nWork *= (32 - nDistance);
|
|
nWork /= 32;
|
|
return nWork;
|
|
}
|
|
pindex = pindex->pprev;
|
|
nDistance++;
|
|
}
|
|
return arith_uint256(0);
|
|
}
|
|
|
|
arith_uint256 GetPrevWorkForAlgoWithDecay3(const CBlockIndex& block, int algo)
|
|
{
|
|
int nDistance = 0;
|
|
arith_uint256 nWork;
|
|
const CBlockIndex* pindex = █
|
|
while (pindex != NULL)
|
|
{
|
|
if (nDistance > 100)
|
|
{
|
|
return arith_uint256(0);
|
|
}
|
|
if (pindex->GetAlgo() == algo)
|
|
{
|
|
arith_uint256 nWork = GetBlockProofBase(*pindex);
|
|
nWork *= (100 - nDistance);
|
|
nWork /= 100;
|
|
return nWork;
|
|
}
|
|
pindex = pindex->pprev;
|
|
nDistance++;
|
|
}
|
|
return arith_uint256(0);
|
|
}
|
|
|
|
arith_uint256 GetGeometricMeanPrevWork(const CBlockIndex& block)
|
|
{
|
|
//arith_uint256 bnRes;
|
|
arith_uint256 nBlockWork = GetBlockProofBase(block);
|
|
CBigNum bnBlockWork = CBigNum(ArithToUint256(nBlockWork));
|
|
int nAlgo = block.GetAlgo();
|
|
|
|
for (int algo = 0; algo < NUM_ALGOS_IMPL; algo++)
|
|
{
|
|
if (algo != nAlgo)
|
|
{
|
|
arith_uint256 nBlockWorkAlt = GetPrevWorkForAlgoWithDecay3(block, algo);
|
|
CBigNum bnBlockWorkAlt = CBigNum(ArithToUint256(nBlockWorkAlt));
|
|
if (bnBlockWorkAlt != 0)
|
|
bnBlockWork *= bnBlockWorkAlt;
|
|
}
|
|
}
|
|
// Compute the geometric mean
|
|
CBigNum bnRes = bnBlockWork.nthRoot(NUM_ALGOS);
|
|
|
|
// Scale to roughly match the old work calculation
|
|
bnRes <<= 8;
|
|
|
|
//return bnRes;
|
|
return UintToArith256(bnRes.getuint256());
|
|
}
|
|
|
|
arith_uint256 GetBlockProof(const CBlockIndex& block)
|
|
{
|
|
const CChainParams& chainparams = Params();
|
|
|
|
arith_uint256 bnTarget;
|
|
int nHeight = block.nHeight;
|
|
int nAlgo = block.GetAlgo();
|
|
|
|
if (nHeight >= chainparams.GetConsensus().nGeoAvgWork_Start)
|
|
{
|
|
bnTarget = GetGeometricMeanPrevWork(block);
|
|
}
|
|
else if (nHeight >= chainparams.GetConsensus().nBlockAlgoNormalisedWorkStart)
|
|
{
|
|
arith_uint256 nBlockWork = GetBlockProofBase(block);
|
|
for (int algo = 0; algo < NUM_ALGOS; algo++)
|
|
{
|
|
if (algo != nAlgo)
|
|
{
|
|
if (nHeight >= chainparams.GetConsensus().nBlockAlgoNormalisedWorkDecayStart2)
|
|
{
|
|
nBlockWork += GetPrevWorkForAlgoWithDecay2(block, algo);
|
|
}
|
|
else
|
|
{
|
|
if (nHeight >= chainparams.GetConsensus().nBlockAlgoNormalisedWorkDecayStart1)
|
|
{
|
|
nBlockWork += GetPrevWorkForAlgoWithDecay(block, algo);
|
|
}
|
|
else
|
|
{
|
|
nBlockWork += GetPrevWorkForAlgo(block, algo);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
bnTarget = nBlockWork / NUM_ALGOS;
|
|
}
|
|
else if (nHeight >= chainparams.GetConsensus().nBlockAlgoWorkWeightStart)
|
|
{
|
|
bnTarget = GetBlockProofBase(block) * GetAlgoWorkFactor(nAlgo);
|
|
}
|
|
else
|
|
{
|
|
bnTarget = GetBlockProofBase(block);
|
|
}
|
|
return bnTarget;
|
|
}
|
|
|
|
bool CheckAuxPowProofOfWork(const CBlockHeader& block, const Consensus::Params& params)
|
|
{
|
|
int algo = block.GetAlgo();
|
|
/* Except for legacy blocks with full version 1, ensure that
|
|
the chain ID is correct. Legacy blocks are not allowed since
|
|
the merge-mining start, which is checked in AcceptBlockHeader
|
|
where the height is known. */
|
|
if (!block.nVersion.IsLegacy() && params.fStrictChainId && block.nVersion.GetChainId() != params.nAuxpowChainId)
|
|
return error("%s : block does not have our chain ID"
|
|
" (got %d, expected %d, full nVersion %d)",
|
|
__func__,
|
|
block.nVersion.GetChainId(),
|
|
params.nAuxpowChainId,
|
|
block.nVersion.GetFullVersion());
|
|
|
|
/* If there is no auxpow, just check the block hash. */
|
|
if (!block.auxpow) {
|
|
if (block.nVersion.IsAuxpow())
|
|
return error("%s : no auxpow on block with auxpow version",
|
|
__func__);
|
|
|
|
if (!CheckProofOfWork(block.GetPoWHash(algo), block.nBits, params))
|
|
return error("%s : non-AUX proof of work failed", __func__);
|
|
|
|
return true;
|
|
}
|
|
|
|
/* We have auxpow. Check it. */
|
|
|
|
if (!block.nVersion.IsAuxpow())
|
|
return error("%s : auxpow on block with non-auxpow version", __func__);
|
|
|
|
if (!block.auxpow->check(block.GetHash(), block.nVersion.GetChainId(), params))
|
|
return error("%s : AUX POW is not valid", __func__);
|
|
|
|
if(fDebug)
|
|
{
|
|
bool fNegative;
|
|
bool fOverflow;
|
|
arith_uint256 bnTarget;
|
|
bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow);
|
|
|
|
LogPrintf("DEBUG: proof-of-work submitted \n parent-PoWhash: %s\n target: %s bits: %08x \n",
|
|
block.auxpow->getParentBlockPoWHash(algo).ToString().c_str(),
|
|
bnTarget.ToString().c_str(),
|
|
bnTarget.GetCompact());
|
|
}
|
|
|
|
if (!(algo == ALGO_SHA256D || algo == ALGO_SCRYPT) )
|
|
{
|
|
return error("%s : AUX POW is not allowed on this algo", __func__);
|
|
}
|
|
|
|
if (!CheckProofOfWork(block.auxpow->getParentBlockPoWHash(algo), block.nBits, params))
|
|
{
|
|
return error("%s : AUX proof of work failed", __func__);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from, const CBlockIndex& tip, const Consensus::Params& params)
|
|
{
|
|
arith_uint256 r;
|
|
int sign = 1;
|
|
if (to.nChainWork > from.nChainWork) {
|
|
r = to.nChainWork - from.nChainWork;
|
|
} else {
|
|
r = from.nChainWork - to.nChainWork;
|
|
sign = -1;
|
|
}
|
|
r = r * arith_uint256(params.nPowTargetSpacingV2) / GetBlockProof(tip);
|
|
if (r.bits() > 63) {
|
|
return sign * std::numeric_limits<int64_t>::max();
|
|
}
|
|
return sign * r.GetLow64();
|
|
}
|
|
|
|
const CBlockIndex* GetLastBlockIndex(const CBlockIndex* pindex, int algo)
|
|
{
|
|
while (pindex && pindex->pprev && (pindex->GetAlgo() != algo))
|
|
pindex = pindex->pprev;
|
|
return pindex;
|
|
}
|
|
|
|
const CBlockIndex* GetLastBlockIndexForAlgo(const CBlockIndex* pindex, int algo)
|
|
{
|
|
for (;;)
|
|
{
|
|
if (!pindex)
|
|
return NULL;
|
|
if (pindex->GetAlgo() == algo)
|
|
return pindex;
|
|
pindex = pindex->pprev;
|
|
}
|
|
}
|
|
|
|
|