[pow] Update pow to equihash, include fork related changes
This commit is contained in:
parent
cb9e6bbf58
commit
ff894a8f09
|
@ -130,6 +130,7 @@ BITCOIN_CORE_H = \
|
||||||
core_io.h \
|
core_io.h \
|
||||||
core_memusage.h \
|
core_memusage.h \
|
||||||
cuckoocache.h \
|
cuckoocache.h \
|
||||||
|
fork.h \
|
||||||
fs.h \
|
fs.h \
|
||||||
httprpc.h \
|
httprpc.h \
|
||||||
httpserver.h \
|
httpserver.h \
|
||||||
|
@ -241,6 +242,7 @@ libbitcoin_server_a_SOURCES = \
|
||||||
chain.cpp \
|
chain.cpp \
|
||||||
checkpoints.cpp \
|
checkpoints.cpp \
|
||||||
consensus/tx_verify.cpp \
|
consensus/tx_verify.cpp \
|
||||||
|
fork.cpp \
|
||||||
httprpc.cpp \
|
httprpc.cpp \
|
||||||
httpserver.cpp \
|
httpserver.cpp \
|
||||||
index/txindex.cpp \
|
index/txindex.cpp \
|
||||||
|
|
|
@ -9,6 +9,10 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/** The minimum allowed block version (network rule) */
|
||||||
|
static const int32_t MIN_BLOCK_VERSION = 4;
|
||||||
|
/** The minimum allowed transaction version (network rule) */
|
||||||
|
static const int32_t MIN_TX_VERSION = 1;
|
||||||
/** The maximum allowed size for a serialized block, in bytes (only for buffer size limits) */
|
/** The maximum allowed size for a serialized block, in bytes (only for buffer size limits) */
|
||||||
static const unsigned int MAX_BLOCK_SERIALIZED_SIZE = 4000000;
|
static const unsigned int MAX_BLOCK_SERIALIZED_SIZE = 4000000;
|
||||||
/** The maximum allowed weight for a block, see BIP 141 (network rule) */
|
/** The maximum allowed weight for a block, see BIP 141 (network rule) */
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||||
|
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
||||||
|
// Copyright (c) 2018 The Bitcoin Private developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#ifndef BTCP_FORK_H
|
||||||
|
#define BTCP_FORK_H
|
||||||
|
|
||||||
|
static const uint256 forkExtraHashSentinel = uint256S("f0f0f0f0fafafafaffffffffffffffffffffffffffffffffafafafaf0f0f0f0f");
|
||||||
|
|
||||||
|
inline bool isForkBlock(int nHeight, int forkStartHeight, int forkHeightRange)
|
||||||
|
{
|
||||||
|
return (nHeight > forkStartHeight && nHeight <= forkStartHeight + forkHeightRange);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool looksLikeForkBlockHeader(const CBlockHeader& header)
|
||||||
|
{
|
||||||
|
return header.hashReserved == forkExtraHashSentinel;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool isForkEnabled(int nHeight, int forkStartHeight)
|
||||||
|
{
|
||||||
|
return nHeight > forkStartHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -37,7 +37,7 @@
|
||||||
uint64_t nLastBlockTx = 0;
|
uint64_t nLastBlockTx = 0;
|
||||||
uint64_t nLastBlockWeight = 0;
|
uint64_t nLastBlockWeight = 0;
|
||||||
|
|
||||||
int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
|
int64_t UpdateTime(CBlockHeader* pblock, const CChainParams& chainparams, const CBlockIndex* pindexPrev)
|
||||||
{
|
{
|
||||||
int64_t nOldTime = pblock->nTime;
|
int64_t nOldTime = pblock->nTime;
|
||||||
int64_t nNewTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
|
int64_t nNewTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
|
||||||
|
@ -46,8 +46,8 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam
|
||||||
pblock->nTime = nNewTime;
|
pblock->nTime = nNewTime;
|
||||||
|
|
||||||
// Updating time can change work required on testnet:
|
// Updating time can change work required on testnet:
|
||||||
if (consensusParams.fPowAllowMinDifficultyBlocks)
|
if (chainparams.GetConsensus().fPowAllowMinDifficultyBlocks)
|
||||||
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, consensusParams);
|
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams);
|
||||||
|
|
||||||
return nNewTime - nOldTime;
|
return nNewTime - nOldTime;
|
||||||
}
|
}
|
||||||
|
@ -164,8 +164,8 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
|
||||||
|
|
||||||
// Fill in header
|
// Fill in header
|
||||||
pblock->hashPrevBlock = pindexPrev->GetBlockHash();
|
pblock->hashPrevBlock = pindexPrev->GetBlockHash();
|
||||||
UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev);
|
UpdateTime(pblock, chainparams, pindexPrev);
|
||||||
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus());
|
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams);
|
||||||
pblock->nNonce = uint256();
|
pblock->nNonce = uint256();
|
||||||
pblocktemplate->vTxSigOpsCost[0] = WITNESS_SCALE_FACTOR * GetLegacySigOpCount(*pblock->vtx[0]);
|
pblocktemplate->vTxSigOpsCost[0] = WITNESS_SCALE_FACTOR * GetLegacySigOpCount(*pblock->vtx[0]);
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#ifndef BITCOIN_MINER_H
|
#ifndef BITCOIN_MINER_H
|
||||||
#define BITCOIN_MINER_H
|
#define BITCOIN_MINER_H
|
||||||
|
|
||||||
|
#include <chainparams.h>
|
||||||
#include <primitives/block.h>
|
#include <primitives/block.h>
|
||||||
#include <txmempool.h>
|
#include <txmempool.h>
|
||||||
#include <validation.h>
|
#include <validation.h>
|
||||||
|
@ -195,6 +196,6 @@ private:
|
||||||
|
|
||||||
/** Modify the extranonce in a block */
|
/** Modify the extranonce in a block */
|
||||||
void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce);
|
void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce);
|
||||||
int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev);
|
int64_t UpdateTime(CBlockHeader* pblock, const CChainParams& consensusParams, const CBlockIndex* pindexPrev);
|
||||||
|
|
||||||
#endif // BITCOIN_MINER_H
|
#endif // BITCOIN_MINER_H
|
||||||
|
|
151
src/pow.cpp
151
src/pow.cpp
|
@ -7,63 +7,107 @@
|
||||||
|
|
||||||
#include <arith_uint256.h>
|
#include <arith_uint256.h>
|
||||||
#include <chain.h>
|
#include <chain.h>
|
||||||
|
#include <chainparams.h>
|
||||||
|
#include <crypto/equihash.h>
|
||||||
|
#include <fork.h>
|
||||||
#include <primitives/block.h>
|
#include <primitives/block.h>
|
||||||
|
#include <streams.h>
|
||||||
#include <uint256.h>
|
#include <uint256.h>
|
||||||
|
#include <util.h>
|
||||||
|
#include <validation.h>
|
||||||
|
|
||||||
unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params)
|
#include <sodium.h>
|
||||||
|
|
||||||
|
#ifdef ENABLE_RUST
|
||||||
|
#include <librustzcash.h>
|
||||||
|
#endif // ENABLE_RUST
|
||||||
|
|
||||||
|
unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const CChainParams& chainparams)
|
||||||
{
|
{
|
||||||
assert(pindexLast != nullptr);
|
assert(pindexLast != nullptr);
|
||||||
unsigned int nProofOfWorkLimit = UintToArith256(params.powLimit).GetCompact();
|
|
||||||
|
|
||||||
// Only change once per difficulty adjustment interval
|
const Consensus::Params& params = chainparams.GetConsensus();
|
||||||
if ((pindexLast->nHeight+1) % params.DifficultyAdjustmentInterval() != 0)
|
int nHeight = pindexLast->nHeight + 1;
|
||||||
{
|
|
||||||
if (params.fPowAllowMinDifficultyBlocks)
|
arith_uint256 proofOfWorkLimit;
|
||||||
|
if(!isForkEnabled(nHeight, chainparams.ForkStartHeight()))
|
||||||
|
proofOfWorkLimit = UintToArith256(params.prePowLimit);
|
||||||
|
else
|
||||||
|
proofOfWorkLimit = UintToArith256(params.powLimit);
|
||||||
|
|
||||||
|
unsigned int nProofOfWorkLimit = proofOfWorkLimit.GetCompact();
|
||||||
|
unsigned int nProofOfWorkBomb = UintToArith256(uint256S("000000000000000000000000000000000000000000000000000000000000ffff")).GetCompact();
|
||||||
|
|
||||||
|
bool is_fork = isForkBlock(nHeight, chainparams.ForkStartHeight(), chainparams.ForkHeightRange());
|
||||||
|
bool was_fork = isForkBlock(nHeight - params.nPowAveragingWindow, chainparams.ForkStartHeight(), chainparams.ForkHeightRange());
|
||||||
|
|
||||||
|
// Genesis block
|
||||||
|
if (pindexLast == NULL)
|
||||||
|
return nProofOfWorkLimit;
|
||||||
|
|
||||||
|
// right at fork
|
||||||
|
else if(is_fork && !was_fork)
|
||||||
|
return nProofOfWorkLimit;
|
||||||
|
|
||||||
|
// right post fork
|
||||||
|
else if(!is_fork && was_fork)
|
||||||
|
return nProofOfWorkLimit;
|
||||||
|
|
||||||
|
// difficulty bomb
|
||||||
|
else if(pindexLast->nHeight > params.nPowDifficultyBombHeight)
|
||||||
|
return nProofOfWorkBomb;
|
||||||
|
|
||||||
|
// testnet only
|
||||||
|
else if (params.fPowAllowMinDifficultyBlocks)
|
||||||
{
|
{
|
||||||
// Special difficulty rule for testnet:
|
// Special difficulty rule for testnet:
|
||||||
// If the new block's timestamp is more than 2* 10 minutes
|
// If the new block's timestamp is more than 2* 10 minutes
|
||||||
// then allow mining of a min-difficulty block.
|
// then allow mining of a min-difficulty block.
|
||||||
if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + params.nPowTargetSpacing*2)
|
if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + params.nPowTargetSpacing*2)
|
||||||
return nProofOfWorkLimit;
|
return nProofOfWorkLimit;
|
||||||
else
|
|
||||||
{
|
|
||||||
// Return the last non-special-min-difficulty-rules-block
|
|
||||||
const CBlockIndex* pindex = pindexLast;
|
|
||||||
while (pindex->pprev && pindex->nHeight % params.DifficultyAdjustmentInterval() != 0 && pindex->nBits == nProofOfWorkLimit)
|
|
||||||
pindex = pindex->pprev;
|
|
||||||
return pindex->nBits;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return pindexLast->nBits;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Go back by what we want to be 14 days worth of blocks
|
|
||||||
int nHeightFirst = pindexLast->nHeight - (params.DifficultyAdjustmentInterval()-1);
|
|
||||||
assert(nHeightFirst >= 0);
|
|
||||||
const CBlockIndex* pindexFirst = pindexLast->GetAncestor(nHeightFirst);
|
|
||||||
assert(pindexFirst);
|
|
||||||
|
|
||||||
return CalculateNextWorkRequired(pindexLast, pindexFirst->GetBlockTime(), params);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params& params)
|
|
||||||
{
|
|
||||||
if (params.fPowNoRetargeting)
|
if (params.fPowNoRetargeting)
|
||||||
return pindexLast->nBits;
|
return pindexLast->nBits;
|
||||||
|
|
||||||
|
// Find the first block in the averaging interval
|
||||||
|
const CBlockIndex* pindexFirst = pindexLast;
|
||||||
|
arith_uint256 bnTot {0};
|
||||||
|
for (int i = 0; pindexFirst && i < params.nPowAveragingWindow; i++) {
|
||||||
|
arith_uint256 bnTmp;
|
||||||
|
bnTmp.SetCompact(pindexFirst->nBits);
|
||||||
|
bnTot += bnTmp;
|
||||||
|
pindexFirst = pindexFirst->pprev;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check we have enough blocks
|
||||||
|
if (pindexFirst == NULL)
|
||||||
|
return nProofOfWorkLimit;
|
||||||
|
|
||||||
|
arith_uint256 bnAvg {bnTot / params.nPowAveragingWindow};
|
||||||
|
|
||||||
|
bool isFork = isForkBlock(pindexLast->nHeight + 1, chainparams.ForkStartHeight(), chainparams.ForkHeightRange());
|
||||||
|
return CalculateNextWorkRequired(bnAvg, pindexLast->GetMedianTimePast(), pindexFirst->GetMedianTimePast(), params, proofOfWorkLimit, isFork);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg,
|
||||||
|
int64_t nLastBlockTime, int64_t nFirstBlockTime,
|
||||||
|
const Consensus::Params& params, const arith_uint256 bnPowLimit, bool isFork)
|
||||||
|
{
|
||||||
// Limit adjustment step
|
// Limit adjustment step
|
||||||
int64_t nActualTimespan = pindexLast->GetBlockTime() - nFirstBlockTime;
|
// Use medians to prevent time-warp attacks
|
||||||
if (nActualTimespan < params.nPowTargetTimespan/4)
|
int64_t nActualTimespan = nLastBlockTime - nFirstBlockTime;
|
||||||
nActualTimespan = params.nPowTargetTimespan/4;
|
nActualTimespan = params.AveragingWindowTimespan(isFork) + (nActualTimespan - params.AveragingWindowTimespan(isFork))/4;
|
||||||
if (nActualTimespan > params.nPowTargetTimespan*4)
|
|
||||||
nActualTimespan = params.nPowTargetTimespan*4;
|
if (nActualTimespan < params.MinActualTimespan(isFork))
|
||||||
|
nActualTimespan = params.MinActualTimespan(isFork);
|
||||||
|
if (nActualTimespan > params.MaxActualTimespan(isFork))
|
||||||
|
nActualTimespan = params.MaxActualTimespan(isFork);
|
||||||
|
|
||||||
// Retarget
|
// Retarget
|
||||||
const arith_uint256 bnPowLimit = UintToArith256(params.powLimit);
|
arith_uint256 bnNew {bnAvg};
|
||||||
arith_uint256 bnNew;
|
bnNew /= params.AveragingWindowTimespan(isFork);
|
||||||
bnNew.SetCompact(pindexLast->nBits);
|
|
||||||
bnNew *= nActualTimespan;
|
bnNew *= nActualTimespan;
|
||||||
bnNew /= params.nPowTargetTimespan;
|
|
||||||
|
|
||||||
if (bnNew > bnPowLimit)
|
if (bnNew > bnPowLimit)
|
||||||
bnNew = bnPowLimit;
|
bnNew = bnPowLimit;
|
||||||
|
@ -89,3 +133,38 @@ bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CheckEquihashSolution(const CBlockHeader *pblock, const CChainParams& params)
|
||||||
|
{
|
||||||
|
unsigned int n = params.EquihashN();
|
||||||
|
unsigned int k = params.EquihashK();
|
||||||
|
|
||||||
|
// Hash state
|
||||||
|
crypto_generichash_blake2b_state state;
|
||||||
|
EhInitialiseState(n, k, state);
|
||||||
|
|
||||||
|
// I = the block header minus nonce and solution.
|
||||||
|
CEquihashInput I{*pblock};
|
||||||
|
// I||V
|
||||||
|
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||||
|
ss << I;
|
||||||
|
ss << pblock->nNonce;
|
||||||
|
|
||||||
|
// H(I||V||...
|
||||||
|
crypto_generichash_blake2b_update(&state, (unsigned char*)&ss[0], ss.size());
|
||||||
|
|
||||||
|
#ifdef ENABLE_RUST
|
||||||
|
// Ensure that our Rust interactions are working in production builds. This is
|
||||||
|
// temporary and should be removed.
|
||||||
|
{
|
||||||
|
assert(librustzcash_xor(0x0f0f0f0f0f0f0f0f, 0x1111111111111111) == 0x1e1e1e1e1e1e1e1e);
|
||||||
|
}
|
||||||
|
#endif // ENABLE_RUST
|
||||||
|
|
||||||
|
bool isValid;
|
||||||
|
EhIsValidSolution(n, k, state, pblock->nSolution, isValid);
|
||||||
|
if (!isValid)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
11
src/pow.h
11
src/pow.h
|
@ -6,18 +6,23 @@
|
||||||
#ifndef BITCOIN_POW_H
|
#ifndef BITCOIN_POW_H
|
||||||
#define BITCOIN_POW_H
|
#define BITCOIN_POW_H
|
||||||
|
|
||||||
#include <consensus/params.h>
|
#include <chainparams.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
class CBlockHeader;
|
class CBlockHeader;
|
||||||
class CBlockIndex;
|
class CBlockIndex;
|
||||||
class uint256;
|
class uint256;
|
||||||
|
class arith_uint256;
|
||||||
|
|
||||||
unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params&);
|
|
||||||
unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params&);
|
unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const CChainParams&);
|
||||||
|
unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg,
|
||||||
|
int64_t nLastBlockTime, int64_t nFirstBlockTime,
|
||||||
|
const Consensus::Params& params, const arith_uint256 bnPowLimit, bool isFork);
|
||||||
|
|
||||||
/** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */
|
/** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */
|
||||||
bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&);
|
bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&);
|
||||||
|
bool CheckEquihashSolution(const CBlockHeader *pblock, const CChainParams& params);
|
||||||
|
|
||||||
#endif // BITCOIN_POW_H
|
#endif // BITCOIN_POW_H
|
||||||
|
|
|
@ -569,7 +569,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
|
||||||
const Consensus::Params& consensusParams = Params().GetConsensus();
|
const Consensus::Params& consensusParams = Params().GetConsensus();
|
||||||
|
|
||||||
// Update nTime
|
// Update nTime
|
||||||
UpdateTime(pblock, consensusParams, pindexPrev);
|
UpdateTime(pblock, Params(), pindexPrev);
|
||||||
pblock->nNonce = uint256();
|
pblock->nNonce = uint256();
|
||||||
|
|
||||||
// NOTE: If at some point we support pre-segwit miners post-segwit-activation, this needs to take segwit support into consideration
|
// NOTE: If at some point we support pre-segwit miners post-segwit-activation, this needs to take segwit support into consideration
|
||||||
|
|
|
@ -3248,7 +3248,7 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationSta
|
||||||
|
|
||||||
// Check proof of work
|
// Check proof of work
|
||||||
const Consensus::Params& consensusParams = params.GetConsensus();
|
const Consensus::Params& consensusParams = params.GetConsensus();
|
||||||
if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams))
|
if (block.nBits != GetNextWorkRequired(pindexPrev, &block, params))
|
||||||
return state.DoS(100, false, REJECT_INVALID, "bad-diffbits", false, "incorrect proof of work");
|
return state.DoS(100, false, REJECT_INVALID, "bad-diffbits", false, "incorrect proof of work");
|
||||||
|
|
||||||
// Check against checkpoints
|
// Check against checkpoints
|
||||||
|
|
Loading…
Reference in New Issue