Merge pull request #4468
e11b2ce
Fix large reorgs (Pieter Wuille)afc32c5
Fix rebuild-chainstate feature and improve its performance (Pieter Wuille)16d5194
Skip reindexed blocks individually (Pieter Wuille)ad96e7c
Make -reindex cope with out-of-order blocks (Wladimir J. van der Laan)e17bd58
Rename setBlockIndexValid to setBlockIndexCandidates (Pieter Wuille)1af838b
Add height to "Requesting block" debug (R E Broadley)1bcee67
Better logging of stalling (R E Broadley)4c93322
Improve getheaders (sending) logging (R E Broadley)f244c99
Remove CheckMinWork, as we always know all parent headers (Pieter Wuille)ad6e601
RPC additions after headers-first (Pieter Wuille)341735e
Headers-first synchronization (Pieter Wuille)
This commit is contained in:
commit
84d13eef88
15 changed files with 479 additions and 501 deletions
|
@ -10,7 +10,7 @@ touch "$DATADIR/regtest/debug.log"
|
|||
tail -q -n 1 -F "$DATADIR/regtest/debug.log" | grep -m 1 -q "Done loading" &
|
||||
WAITER=$!
|
||||
PORT=`expr 10000 + $$ % 55536`
|
||||
"@abs_top_builddir@/src/bitcoind@EXEEXT@" -connect=0.0.0.0 -datadir="$DATADIR" -rpcuser=user -rpcpassword=pass -listen -keypool=3 -debug -debug=net -logtimestamps -port=$PORT -whitelist=127.0.0.1 -regtest -rpcport=`expr $PORT + 1` &
|
||||
"@abs_top_builddir@/src/bitcoind@EXEEXT@" -connect=0.0.0.0 -datadir="$DATADIR" -rpcuser=user -rpcpassword=pass -listen -keypool=3 -debug -debug=net -logtimestamps -checkmempool=0 -port=$PORT -whitelist=127.0.0.1 -regtest -rpcport=`expr $PORT + 1` &
|
||||
BITCOIND=$!
|
||||
|
||||
#Install a watchdog.
|
||||
|
|
32
src/chain.h
32
src/chain.h
|
@ -49,12 +49,29 @@ struct CDiskBlockPos
|
|||
};
|
||||
|
||||
enum BlockStatus {
|
||||
// Unused.
|
||||
BLOCK_VALID_UNKNOWN = 0,
|
||||
BLOCK_VALID_HEADER = 1, // parsed, version ok, hash satisfies claimed PoW, 1 <= vtx count <= max, timestamp not in future
|
||||
BLOCK_VALID_TREE = 2, // parent found, difficulty matches, timestamp >= median previous, checkpoint
|
||||
BLOCK_VALID_TRANSACTIONS = 3, // only first tx is coinbase, 2 <= coinbase input script length <= 100, transactions valid, no duplicate txids, sigops, size, merkle root
|
||||
BLOCK_VALID_CHAIN = 4, // outputs do not overspend inputs, no double spends, coinbase output ok, immature coinbase spends, BIP30
|
||||
BLOCK_VALID_SCRIPTS = 5, // scripts/signatures ok
|
||||
|
||||
// Parsed, version ok, hash satisfies claimed PoW, 1 <= vtx count <= max, timestamp not in future
|
||||
BLOCK_VALID_HEADER = 1,
|
||||
|
||||
// All parent headers found, difficulty matches, timestamp >= median previous, checkpoint. Implies all parents
|
||||
// are also at least TREE.
|
||||
BLOCK_VALID_TREE = 2,
|
||||
|
||||
// Only first tx is coinbase, 2 <= coinbase input script length <= 100, transactions valid, no duplicate txids,
|
||||
// sigops, size, merkle root. Implies all parents are at least TREE but not necessarily TRANSACTIONS. When all
|
||||
// parent blocks also have TRANSACTIONS, CBlockIndex::nChainTx will be set.
|
||||
BLOCK_VALID_TRANSACTIONS = 3,
|
||||
|
||||
// Outputs do not overspend inputs, no double spends, coinbase output ok, immature coinbase spends, BIP30.
|
||||
// Implies all parents are also at least CHAIN.
|
||||
BLOCK_VALID_CHAIN = 4,
|
||||
|
||||
// Scripts & signatures ok. Implies all parents are also at least SCRIPTS.
|
||||
BLOCK_VALID_SCRIPTS = 5,
|
||||
|
||||
// All validity bits.
|
||||
BLOCK_VALID_MASK = BLOCK_VALID_HEADER | BLOCK_VALID_TREE | BLOCK_VALID_TRANSACTIONS |
|
||||
BLOCK_VALID_CHAIN | BLOCK_VALID_SCRIPTS,
|
||||
|
||||
|
@ -103,7 +120,8 @@ public:
|
|||
// Note: in a potential headers-first mode, this number cannot be relied upon
|
||||
unsigned int nTx;
|
||||
|
||||
// (memory only) Number of transactions in the chain up to and including this block
|
||||
// (memory only) Number of transactions in the chain up to and including this block.
|
||||
// This value will be non-zero only if and only if transactions for this block and all its parents are available.
|
||||
unsigned int nChainTx; // change to 64-bit type when necessary; won't happen before 2030
|
||||
|
||||
// Verification status of this block. See enum BlockStatus
|
||||
|
@ -146,7 +164,7 @@ public:
|
|||
SetNull();
|
||||
}
|
||||
|
||||
CBlockIndex(CBlockHeader& block)
|
||||
CBlockIndex(const CBlockHeader& block)
|
||||
{
|
||||
SetNull();
|
||||
|
||||
|
|
|
@ -974,7 +974,7 @@ bool AppInit2(boost::thread_group& threadGroup)
|
|||
|
||||
// If the loaded chain has a wrong genesis, bail out immediately
|
||||
// (we're likely using a testnet datadir, or the other way around).
|
||||
if (!mapBlockIndex.empty() && chainActive.Genesis() == NULL)
|
||||
if (!mapBlockIndex.empty() && mapBlockIndex.count(Params().HashGenesisBlock()) == 0)
|
||||
return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?"));
|
||||
|
||||
// Initialize the block index (no-op if non-empty database was already loaded)
|
||||
|
|
737
src/main.cpp
737
src/main.cpp
File diff suppressed because it is too large
Load diff
26
src/main.h
26
src/main.h
|
@ -72,9 +72,17 @@ static const int MAX_SCRIPTCHECK_THREADS = 16;
|
|||
/** -par default (number of script-checking threads, 0 = auto) */
|
||||
static const int DEFAULT_SCRIPTCHECK_THREADS = 0;
|
||||
/** Number of blocks that can be requested at any given time from a single peer. */
|
||||
static const int MAX_BLOCKS_IN_TRANSIT_PER_PEER = 128;
|
||||
/** Timeout in seconds before considering a block download peer unresponsive. */
|
||||
static const unsigned int BLOCK_DOWNLOAD_TIMEOUT = 60;
|
||||
static const int MAX_BLOCKS_IN_TRANSIT_PER_PEER = 16;
|
||||
/** Timeout in seconds during which a peer must stall block download progress before being disconnected. */
|
||||
static const unsigned int BLOCK_STALLING_TIMEOUT = 2;
|
||||
/** Number of headers sent in one getheaders result. We rely on the assumption that if a peer sends
|
||||
* less than this number, we reached their tip. Changing this value is a protocol upgrade. */
|
||||
static const unsigned int MAX_HEADERS_RESULTS = 2000;
|
||||
/** Size of the "block download window": how far ahead of our current height do we fetch?
|
||||
* Larger windows tolerate larger download speed differences between peer, but increase the potential
|
||||
* degree of disordering of blocks on disk (which make reindexing and in the future perhaps pruning
|
||||
* harder). We'll probably want to make this a per-peer adaptive value at some point. */
|
||||
static const unsigned int BLOCK_DOWNLOAD_WINDOW = 1024;
|
||||
|
||||
/** "reject" message codes **/
|
||||
static const unsigned char REJECT_MALFORMED = 0x01;
|
||||
|
@ -110,6 +118,9 @@ extern bool fIsBareMultisigStd;
|
|||
extern unsigned int nCoinCacheSize;
|
||||
extern CFeeRate minRelayTxFee;
|
||||
|
||||
// Best header we've seen so far (used for getheaders queries' starting points).
|
||||
extern CBlockIndex *pindexBestHeader;
|
||||
|
||||
// Minimum disk space required - used in CheckDiskSpace()
|
||||
static const uint64_t nMinDiskSpace = 52428800;
|
||||
|
||||
|
@ -137,8 +148,6 @@ void RegisterNodeSignals(CNodeSignals& nodeSignals);
|
|||
/** Unregister a network node */
|
||||
void UnregisterNodeSignals(CNodeSignals& nodeSignals);
|
||||
|
||||
void PushGetBlocks(CNode* pnode, CBlockIndex* pindexBegin, uint256 hashEnd);
|
||||
|
||||
/** Process an incoming block */
|
||||
bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp = NULL);
|
||||
/** Check whether enough disk space is available for an incoming block */
|
||||
|
@ -193,6 +202,8 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
|||
struct CNodeStateStats {
|
||||
int nMisbehavior;
|
||||
int nSyncHeight;
|
||||
int nCommonHeight;
|
||||
std::vector<int> vHeightInFlight;
|
||||
};
|
||||
|
||||
struct CDiskTxPos : public CDiskBlockPos
|
||||
|
@ -439,9 +450,6 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
|
|||
// Apply the effects of this block (with given index) on the UTXO set represented by coins
|
||||
bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck = false);
|
||||
|
||||
// Add this block to the block index, and if necessary, switch the active block chain to this
|
||||
bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos& pos);
|
||||
|
||||
// Context-independent validity checks
|
||||
bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW = true);
|
||||
bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
|
||||
|
@ -449,7 +457,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW = t
|
|||
// Store block on disk
|
||||
// if dbp is provided, the file is known to already reside on disk
|
||||
bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex **pindex, CDiskBlockPos* dbp = NULL);
|
||||
bool AcceptBlockHeader(CBlockHeader& block, CValidationState& state, CBlockIndex **ppindex= NULL);
|
||||
bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex **ppindex= NULL);
|
||||
|
||||
|
||||
|
||||
|
|
50
src/net.cpp
50
src/net.cpp
|
@ -73,7 +73,6 @@ map<CNetAddr, LocalServiceInfo> mapLocalHost;
|
|||
static bool vfReachable[NET_MAX] = {};
|
||||
static bool vfLimited[NET_MAX] = {};
|
||||
static CNode* pnodeLocalHost = NULL;
|
||||
static CNode* pnodeSync = NULL;
|
||||
uint64_t nLocalHostNonce = 0;
|
||||
static std::vector<ListenSocket> vhListenSocket;
|
||||
CAddrMan addrman;
|
||||
|
@ -519,10 +518,6 @@ void CNode::CloseSocketDisconnect()
|
|||
TRY_LOCK(cs_vRecvMsg, lockRecv);
|
||||
if (lockRecv)
|
||||
vRecvMsg.clear();
|
||||
|
||||
// if this was the sync node, we'll need a new one
|
||||
if (this == pnodeSync)
|
||||
pnodeSync = NULL;
|
||||
}
|
||||
|
||||
void CNode::PushVersion()
|
||||
|
@ -615,7 +610,6 @@ void CNode::copyStats(CNodeStats &stats)
|
|||
X(nSendBytes);
|
||||
X(nRecvBytes);
|
||||
X(fWhitelisted);
|
||||
stats.fSyncNode = (this == pnodeSync);
|
||||
|
||||
// It is common for nodes with good ping times to suddenly become lagged,
|
||||
// due to a new block arriving or other large transfer.
|
||||
|
@ -1487,61 +1481,20 @@ bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOu
|
|||
}
|
||||
|
||||
|
||||
// for now, use a very simple selection metric: the node from which we received
|
||||
// most recently
|
||||
static int64_t NodeSyncScore(const CNode *pnode) {
|
||||
return pnode->nLastRecv;
|
||||
}
|
||||
|
||||
void static StartSync(const vector<CNode*> &vNodes) {
|
||||
CNode *pnodeNewSync = NULL;
|
||||
int64_t nBestScore = 0;
|
||||
|
||||
int nBestHeight = g_signals.GetHeight().get_value_or(0);
|
||||
|
||||
// Iterate over all nodes
|
||||
BOOST_FOREACH(CNode* pnode, vNodes) {
|
||||
// check preconditions for allowing a sync
|
||||
if (!pnode->fClient && !pnode->fOneShot &&
|
||||
!pnode->fDisconnect && pnode->fSuccessfullyConnected &&
|
||||
(pnode->nStartingHeight > (nBestHeight - 144)) &&
|
||||
(pnode->nVersion < NOBLKS_VERSION_START || pnode->nVersion >= NOBLKS_VERSION_END)) {
|
||||
// if ok, compare node's score with the best so far
|
||||
int64_t nScore = NodeSyncScore(pnode);
|
||||
if (pnodeNewSync == NULL || nScore > nBestScore) {
|
||||
pnodeNewSync = pnode;
|
||||
nBestScore = nScore;
|
||||
}
|
||||
}
|
||||
}
|
||||
// if a new sync candidate was found, start sync!
|
||||
if (pnodeNewSync) {
|
||||
pnodeNewSync->fStartSync = true;
|
||||
pnodeSync = pnodeNewSync;
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadMessageHandler()
|
||||
{
|
||||
SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
|
||||
while (true)
|
||||
{
|
||||
bool fHaveSyncNode = false;
|
||||
|
||||
vector<CNode*> vNodesCopy;
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
vNodesCopy = vNodes;
|
||||
BOOST_FOREACH(CNode* pnode, vNodesCopy) {
|
||||
pnode->AddRef();
|
||||
if (pnode == pnodeSync)
|
||||
fHaveSyncNode = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fHaveSyncNode)
|
||||
StartSync(vNodesCopy);
|
||||
|
||||
// Poll the connected nodes for messages
|
||||
CNode* pnodeTrickle = NULL;
|
||||
if (!vNodesCopy.empty())
|
||||
|
@ -2078,10 +2031,7 @@ CNode::CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn, bool fIn
|
|||
nSendSize = 0;
|
||||
nSendOffset = 0;
|
||||
hashContinue = 0;
|
||||
pindexLastGetBlocksBegin = 0;
|
||||
hashLastGetBlocksEnd = 0;
|
||||
nStartingHeight = -1;
|
||||
fStartSync = false;
|
||||
fGetAddr = false;
|
||||
fRelayTxes = false;
|
||||
setInventoryKnown.max_size(SendBufferSize() / 1000);
|
||||
|
|
|
@ -158,7 +158,6 @@ public:
|
|||
int nStartingHeight;
|
||||
uint64_t nSendBytes;
|
||||
uint64_t nRecvBytes;
|
||||
bool fSyncNode;
|
||||
bool fWhitelisted;
|
||||
double dPingTime;
|
||||
double dPingWait;
|
||||
|
@ -276,10 +275,7 @@ protected:
|
|||
|
||||
public:
|
||||
uint256 hashContinue;
|
||||
CBlockIndex* pindexLastGetBlocksBegin;
|
||||
uint256 hashLastGetBlocksEnd;
|
||||
int nStartingHeight;
|
||||
bool fStartSync;
|
||||
|
||||
// flood relay
|
||||
std::vector<CAddress> vAddrToSend;
|
||||
|
|
33
src/pow.cpp
33
src/pow.cpp
|
@ -98,39 +98,6 @@ bool CheckProofOfWork(uint256 hash, unsigned int nBits)
|
|||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// true if nBits is greater than the minimum amount of work that could
|
||||
// possibly be required deltaTime after minimum work required was nBase
|
||||
//
|
||||
bool CheckMinWork(unsigned int nBits, unsigned int nBase, int64_t deltaTime)
|
||||
{
|
||||
bool fOverflow = false;
|
||||
uint256 bnNewBlock;
|
||||
bnNewBlock.SetCompact(nBits, NULL, &fOverflow);
|
||||
if (fOverflow)
|
||||
return false;
|
||||
|
||||
const uint256 &bnLimit = Params().ProofOfWorkLimit();
|
||||
// Testnet has min-difficulty blocks
|
||||
// after Params().TargetSpacing()*2 time between blocks:
|
||||
if (Params().AllowMinDifficultyBlocks() && deltaTime > Params().TargetSpacing()*2)
|
||||
return bnNewBlock <= bnLimit;
|
||||
|
||||
uint256 bnResult;
|
||||
bnResult.SetCompact(nBase);
|
||||
while (deltaTime > 0 && bnResult < bnLimit)
|
||||
{
|
||||
// Maximum 400% adjustment...
|
||||
bnResult *= 4;
|
||||
// ... in best-case exactly 4-times-normal target time
|
||||
deltaTime -= Params().TargetTimespan()*4;
|
||||
}
|
||||
if (bnResult > bnLimit)
|
||||
bnResult = bnLimit;
|
||||
|
||||
return bnNewBlock <= bnResult;
|
||||
}
|
||||
|
||||
void UpdateTime(CBlockHeader* pblock, const CBlockIndex* pindexPrev)
|
||||
{
|
||||
pblock->nTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
|
||||
|
|
|
@ -16,8 +16,6 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead
|
|||
|
||||
/** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */
|
||||
bool CheckProofOfWork(uint256 hash, unsigned int nBits);
|
||||
/** Check the work is more than the minimum a received block needs, without knowing its direct parent */
|
||||
bool CheckMinWork(unsigned int nBits, unsigned int nBase, int64_t deltaTime);
|
||||
|
||||
void UpdateTime(CBlockHeader* block, const CBlockIndex* pindexPrev);
|
||||
|
||||
|
|
|
@ -836,29 +836,6 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_25">
|
||||
<property name="text">
|
||||
<string>Sync Node</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="QLabel" name="peerSyncNode">
|
||||
<property name="cursor">
|
||||
<cursorShape>IBeamCursor</cursorShape>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>N/A</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::PlainText</enum>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_29">
|
||||
<property name="text">
|
||||
|
|
|
@ -611,7 +611,6 @@ void RPCConsole::updateNodeDetail(const CNodeCombinedStats *stats)
|
|||
ui->peerSubversion->setText(QString::fromStdString(stats->nodeStats.cleanSubVer));
|
||||
ui->peerDirection->setText(stats->nodeStats.fInbound ? tr("Inbound") : tr("Outbound"));
|
||||
ui->peerHeight->setText(QString("%1").arg(stats->nodeStats.nStartingHeight));
|
||||
ui->peerSyncNode->setText(stats->nodeStats.fSyncNode ? tr("Yes") : tr("No"));
|
||||
|
||||
// This check fails for example if the lock was busy and
|
||||
// nodeStateStats couldn't be fetched.
|
||||
|
|
|
@ -445,6 +445,7 @@ Value getblockchaininfo(const Array& params, bool fHelp)
|
|||
"{\n"
|
||||
" \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
|
||||
" \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n"
|
||||
" \"headers\": xxxxxx, (numeric) the current number of headers we have validated\n"
|
||||
" \"bestblockhash\": \"...\", (string) the hash of the currently best block\n"
|
||||
" \"difficulty\": xxxxxx, (numeric) the current difficulty\n"
|
||||
" \"verificationprogress\": xxxx, (numeric) estimate of verification progress [0..1]\n"
|
||||
|
@ -458,6 +459,7 @@ Value getblockchaininfo(const Array& params, bool fHelp)
|
|||
Object obj;
|
||||
obj.push_back(Pair("chain", Params().NetworkIDString()));
|
||||
obj.push_back(Pair("blocks", (int)chainActive.Height()));
|
||||
obj.push_back(Pair("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1));
|
||||
obj.push_back(Pair("bestblockhash", chainActive.Tip()->GetBlockHash().GetHex()));
|
||||
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
|
||||
obj.push_back(Pair("verificationprogress", Checkpoints::GuessVerificationProgress(chainActive.Tip())));
|
||||
|
|
|
@ -97,7 +97,12 @@ Value getpeerinfo(const Array& params, bool fHelp)
|
|||
" \"inbound\": true|false, (boolean) Inbound (true) or Outbound (false)\n"
|
||||
" \"startingheight\": n, (numeric) The starting height (block) of the peer\n"
|
||||
" \"banscore\": n, (numeric) The ban score\n"
|
||||
" \"syncnode\": true|false (boolean) if sync node\n"
|
||||
" \"synced_headers\": n, (numeric) The last header we have in common with this peer\n"
|
||||
" \"synced_blocks\": n, (numeric) The last block we have in common with this peer\n"
|
||||
" \"inflight\": [\n"
|
||||
" n, (numeric) The heights of blocks we're currently asking from this peer\n"
|
||||
" ...\n"
|
||||
" ]\n"
|
||||
" }\n"
|
||||
" ,...\n"
|
||||
"]\n"
|
||||
|
@ -137,9 +142,14 @@ Value getpeerinfo(const Array& params, bool fHelp)
|
|||
obj.push_back(Pair("startingheight", stats.nStartingHeight));
|
||||
if (fStateStats) {
|
||||
obj.push_back(Pair("banscore", statestats.nMisbehavior));
|
||||
obj.push_back(Pair("syncheight", statestats.nSyncHeight));
|
||||
obj.push_back(Pair("synced_headers", statestats.nSyncHeight));
|
||||
obj.push_back(Pair("synced_blocks", statestats.nCommonHeight));
|
||||
Array heights;
|
||||
BOOST_FOREACH(int height, statestats.vHeightInFlight) {
|
||||
heights.push_back(height);
|
||||
}
|
||||
obj.push_back(Pair("inflight", heights));
|
||||
}
|
||||
obj.push_back(Pair("syncnode", stats.fSyncNode));
|
||||
obj.push_back(Pair("whitelisted", stats.fWhitelisted));
|
||||
|
||||
ret.push_back(obj);
|
||||
|
|
|
@ -106,51 +106,6 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
|
|||
BOOST_CHECK(!CNode::IsBanned(addr));
|
||||
}
|
||||
|
||||
static bool CheckNBits(unsigned int nbits1, int64_t time1, unsigned int nbits2, int64_t time2)\
|
||||
{
|
||||
if (time1 > time2)
|
||||
return CheckNBits(nbits2, time2, nbits1, time1);
|
||||
int64_t deltaTime = time2-time1;
|
||||
|
||||
return CheckMinWork(nbits2, nbits1, deltaTime);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(DoS_checknbits)
|
||||
{
|
||||
using namespace boost::assign; // for 'map_list_of()'
|
||||
|
||||
// Timestamps,nBits from the bitcoin block chain.
|
||||
// These are the block-chain checkpoint blocks
|
||||
typedef std::map<int64_t, unsigned int> BlockData;
|
||||
BlockData chainData =
|
||||
map_list_of(1239852051,486604799)(1262749024,486594666)
|
||||
(1279305360,469854461)(1280200847,469830746)(1281678674,469809688)
|
||||
(1296207707,453179945)(1302624061,453036989)(1309640330,437004818)
|
||||
(1313172719,436789733);
|
||||
|
||||
// Make sure CheckNBits considers every combination of block-chain-lock-in-points
|
||||
// "sane":
|
||||
BOOST_FOREACH(const BlockData::value_type& i, chainData)
|
||||
{
|
||||
BOOST_FOREACH(const BlockData::value_type& j, chainData)
|
||||
{
|
||||
BOOST_CHECK(CheckNBits(i.second, i.first, j.second, j.first));
|
||||
}
|
||||
}
|
||||
|
||||
// Test a couple of insane combinations:
|
||||
BlockData::value_type firstcheck = *(chainData.begin());
|
||||
BlockData::value_type lastcheck = *(chainData.rbegin());
|
||||
|
||||
// First checkpoint difficulty at or a while after the last checkpoint time should fail when
|
||||
// compared to last checkpoint
|
||||
BOOST_CHECK(!CheckNBits(firstcheck.second, lastcheck.first+60*10, lastcheck.second, lastcheck.first));
|
||||
BOOST_CHECK(!CheckNBits(firstcheck.second, lastcheck.first+60*60*24*14, lastcheck.second, lastcheck.first));
|
||||
|
||||
// ... but OK if enough time passed for difficulty to adjust downward:
|
||||
BOOST_CHECK(CheckNBits(firstcheck.second, lastcheck.first+60*60*24*365*4, lastcheck.second, lastcheck.first));
|
||||
}
|
||||
|
||||
CTransaction RandomOrphan()
|
||||
{
|
||||
std::map<uint256, COrphanTx>::iterator it;
|
||||
|
|
|
@ -33,8 +33,11 @@ static const int PROTOCOL_VERSION = 70002;
|
|||
// initial proto version, to be increased after version/verack negotiation
|
||||
static const int INIT_PROTO_VERSION = 209;
|
||||
|
||||
// In this version, 'getheaders' was introduced.
|
||||
static const int GETHEADERS_VERSION = 31800;
|
||||
|
||||
// disconnect from peers older than this proto version
|
||||
static const int MIN_PEER_PROTO_VERSION = 209;
|
||||
static const int MIN_PEER_PROTO_VERSION = GETHEADERS_VERSION;
|
||||
|
||||
// nTime field added to CAddress, starting with this version;
|
||||
// if possible, avoid requesting addresses nodes older than this
|
||||
|
|
Loading…
Reference in a new issue