Github-Pull: #10357
Rebased-From: 0311836f69
tags/v0.15.1
@@ -362,6 +362,9 @@ std::string HelpMessage(HelpMessageMode mode) | |||
strUsage += HelpMessageOpt("-maxorphantx=<n>", strprintf(_("Keep at most <n> unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS)); | |||
strUsage += HelpMessageOpt("-maxmempool=<n>", strprintf(_("Keep the transaction memory pool below <n> megabytes (default: %u)"), DEFAULT_MAX_MEMPOOL_SIZE)); | |||
strUsage += HelpMessageOpt("-mempoolexpiry=<n>", strprintf(_("Do not keep transactions in the mempool longer than <n> hours (default: %u)"), DEFAULT_MEMPOOL_EXPIRY)); | |||
if (showDebug) { | |||
strUsage += HelpMessageOpt("-minimumchainwork=<hex>", strprintf("Minimum work assumed to exist on a valid chain in hex (default: %s, testnet: %s)", defaultChainParams->GetConsensus().nMinimumChainWork.GetHex(), testnetChainParams->GetConsensus().nMinimumChainWork.GetHex())); | |||
} | |||
strUsage += HelpMessageOpt("-persistmempool", strprintf(_("Whether to save the mempool on shutdown and load on restart (default: %u)"), DEFAULT_PERSIST_MEMPOOL)); | |||
strUsage += HelpMessageOpt("-blockreconstructionextratxn=<n>", strprintf(_("Extra transactions to keep in memory for compact block reconstructions (default: %u)"), DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN)); | |||
strUsage += HelpMessageOpt("-par=<n>", strprintf(_("Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)"), | |||
@@ -979,6 +982,20 @@ bool AppInitParameterInteraction() | |||
else | |||
LogPrintf("Validating signatures for all blocks.\n"); | |||
if (gArgs.IsArgSet("-minimumchainwork")) { | |||
const std::string minChainWorkStr = gArgs.GetArg("-minimumchainwork", ""); | |||
if (!IsHexNumber(minChainWorkStr)) { | |||
return InitError(strprintf("Invalid non-hex (%s) minimum chain work value specified", minChainWorkStr)); | |||
} | |||
nMinimumChainWork = UintToArith256(uint256S(minChainWorkStr)); | |||
} else { | |||
nMinimumChainWork = UintToArith256(chainparams.GetConsensus().nMinimumChainWork); | |||
} | |||
LogPrintf("Setting nMinimumChainWork=%s\n", nMinimumChainWork.GetHex()); | |||
if (nMinimumChainWork < UintToArith256(chainparams.GetConsensus().nMinimumChainWork)) { | |||
LogPrintf("Warning: nMinimumChainWork set below default value of %s\n", chainparams.GetConsensus().nMinimumChainWork.GetHex()); | |||
} | |||
// mempool limits | |||
int64_t nMempoolSizeMax = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; | |||
int64_t nMempoolSizeMin = gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000 * 40; |
@@ -466,7 +466,7 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<con | |||
// Make sure pindexBestKnownBlock is up to date, we'll need it. | |||
ProcessBlockAvailability(nodeid); | |||
if (state->pindexBestKnownBlock == nullptr || state->pindexBestKnownBlock->nChainWork < chainActive.Tip()->nChainWork || state->pindexBestKnownBlock->nChainWork < UintToArith256(consensusParams.nMinimumChainWork)) { | |||
if (state->pindexBestKnownBlock == nullptr || state->pindexBestKnownBlock->nChainWork < chainActive.Tip()->nChainWork || state->pindexBestKnownBlock->nChainWork < nMinimumChainWork) { | |||
// This peer has nothing interesting. | |||
return; | |||
} |
@@ -253,6 +253,31 @@ BOOST_AUTO_TEST_CASE(util_IsHex) | |||
BOOST_CHECK(!IsHex("0x0000")); | |||
} | |||
BOOST_AUTO_TEST_CASE(util_IsHexNumber) | |||
{ | |||
BOOST_CHECK(IsHexNumber("0x0")); | |||
BOOST_CHECK(IsHexNumber("0")); | |||
BOOST_CHECK(IsHexNumber("0x10")); | |||
BOOST_CHECK(IsHexNumber("10")); | |||
BOOST_CHECK(IsHexNumber("0xff")); | |||
BOOST_CHECK(IsHexNumber("ff")); | |||
BOOST_CHECK(IsHexNumber("0xFfa")); | |||
BOOST_CHECK(IsHexNumber("Ffa")); | |||
BOOST_CHECK(IsHexNumber("0x00112233445566778899aabbccddeeffAABBCCDDEEFF")); | |||
BOOST_CHECK(IsHexNumber("00112233445566778899aabbccddeeffAABBCCDDEEFF")); | |||
BOOST_CHECK(!IsHexNumber("")); // empty string not allowed | |||
BOOST_CHECK(!IsHexNumber("0x")); // empty string after prefix not allowed | |||
BOOST_CHECK(!IsHexNumber("0x0 ")); // no spaces at end, | |||
BOOST_CHECK(!IsHexNumber(" 0x0")); // or beginning, | |||
BOOST_CHECK(!IsHexNumber("0x 0")); // or middle, | |||
BOOST_CHECK(!IsHexNumber(" ")); // etc. | |||
BOOST_CHECK(!IsHexNumber("0x0ga")); // invalid character | |||
BOOST_CHECK(!IsHexNumber("x0")); // broken prefix | |||
BOOST_CHECK(!IsHexNumber("0x0x00")); // two prefixes not allowed | |||
} | |||
BOOST_AUTO_TEST_CASE(util_seed_insecure_rand) | |||
{ | |||
SeedInsecureRand(true); |
@@ -65,6 +65,19 @@ bool IsHex(const std::string& str) | |||
return (str.size() > 0) && (str.size()%2 == 0); | |||
} | |||
bool IsHexNumber(const std::string& str) | |||
{ | |||
size_t starting_location = 0; | |||
if (str.size() > 2 && *str.begin() == '0' && *(str.begin()+1) == 'x') { | |||
starting_location = 2; | |||
} | |||
for (auto c : str.substr(starting_location)) { | |||
if (HexDigit(c) < 0) return false; | |||
} | |||
// Return false for empty string or "0x". | |||
return (str.size() > starting_location); | |||
} | |||
std::vector<unsigned char> ParseHex(const char* psz) | |||
{ | |||
// convert hex dump to vector |
@@ -38,7 +38,13 @@ std::string SanitizeString(const std::string& str, int rule = SAFE_CHARS_DEFAULT | |||
std::vector<unsigned char> ParseHex(const char* psz); | |||
std::vector<unsigned char> ParseHex(const std::string& str); | |||
signed char HexDigit(char c); | |||
/* Returns true if each character in str is a hex character, and has an even | |||
* number of hex digits.*/ | |||
bool IsHex(const std::string& str); | |||
/** | |||
* Return true if the string is a hex number, optionally prefixed with "0x" | |||
*/ | |||
bool IsHexNumber(const std::string& str); | |||
std::vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid = nullptr); | |||
std::string DecodeBase64(const std::string& str); | |||
std::string EncodeBase64(const unsigned char* pch, size_t len); |
@@ -80,6 +80,7 @@ int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE; | |||
bool fEnableReplacement = DEFAULT_ENABLE_REPLACEMENT; | |||
uint256 hashAssumeValid; | |||
arith_uint256 nMinimumChainWork; | |||
CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE); | |||
CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE; | |||
@@ -1032,8 +1033,6 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams) | |||
bool IsInitialBlockDownload() | |||
{ | |||
const CChainParams& chainParams = Params(); | |||
// Once this function has returned false, it must remain false. | |||
static std::atomic<bool> latchToFalse{false}; | |||
// Optimization: pre-test latch before taking the lock. | |||
@@ -1047,7 +1046,7 @@ bool IsInitialBlockDownload() | |||
return true; | |||
if (chainActive.Tip() == nullptr) | |||
return true; | |||
if (chainActive.Tip()->nChainWork < UintToArith256(chainParams.GetConsensus().nMinimumChainWork)) | |||
if (chainActive.Tip()->nChainWork < nMinimumChainWork) | |||
return true; | |||
if (chainActive.Tip()->GetBlockTime() < (GetTime() - nMaxTipAge)) | |||
return true; | |||
@@ -1664,7 +1663,7 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd | |||
if (it != mapBlockIndex.end()) { | |||
if (it->second->GetAncestor(pindex->nHeight) == pindex && | |||
pindexBestHeader->GetAncestor(pindex->nHeight) == pindex && | |||
pindexBestHeader->nChainWork >= UintToArith256(chainparams.GetConsensus().nMinimumChainWork)) { | |||
pindexBestHeader->nChainWork >= nMinimumChainWork) { | |||
// This block is a member of the assumed verified chain and an ancestor of the best header. | |||
// The equivalent time check discourages hash power from extorting the network via DOS attack | |||
// into accepting an invalid block through telling users they must manually set assumevalid. |
@@ -186,6 +186,9 @@ extern bool fEnableReplacement; | |||
/** Block hash whose ancestors we will assume to have valid scripts without checking them. */ | |||
extern uint256 hashAssumeValid; | |||
/** Minimum work we will assume exists on some valid chain. */ | |||
extern arith_uint256 nMinimumChainWork; | |||
/** Best header we've seen so far (used for getheaders queries' starting points). */ | |||
extern CBlockIndex *pindexBestHeader; | |||