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:
Wladimir J. van der Laan 2014-10-17 12:24:29 +02:00
commit 84d13eef88
No known key found for this signature in database
GPG key ID: 74810B012346C9A6
15 changed files with 479 additions and 501 deletions

View file

@ -10,7 +10,7 @@ touch "$DATADIR/regtest/debug.log"
tail -q -n 1 -F "$DATADIR/regtest/debug.log" | grep -m 1 -q "Done loading" & tail -q -n 1 -F "$DATADIR/regtest/debug.log" | grep -m 1 -q "Done loading" &
WAITER=$! WAITER=$!
PORT=`expr 10000 + $$ % 55536` 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=$! BITCOIND=$!
#Install a watchdog. #Install a watchdog.

View file

@ -49,12 +49,29 @@ struct CDiskBlockPos
}; };
enum BlockStatus { enum BlockStatus {
// Unused.
BLOCK_VALID_UNKNOWN = 0, 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 // Parsed, version ok, hash satisfies claimed PoW, 1 <= vtx count <= max, timestamp not in future
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_HEADER = 1,
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 // 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_MASK = BLOCK_VALID_HEADER | BLOCK_VALID_TREE | BLOCK_VALID_TRANSACTIONS |
BLOCK_VALID_CHAIN | BLOCK_VALID_SCRIPTS, BLOCK_VALID_CHAIN | BLOCK_VALID_SCRIPTS,
@ -103,7 +120,8 @@ public:
// Note: in a potential headers-first mode, this number cannot be relied upon // Note: in a potential headers-first mode, this number cannot be relied upon
unsigned int nTx; 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 unsigned int nChainTx; // change to 64-bit type when necessary; won't happen before 2030
// Verification status of this block. See enum BlockStatus // Verification status of this block. See enum BlockStatus
@ -146,7 +164,7 @@ public:
SetNull(); SetNull();
} }
CBlockIndex(CBlockHeader& block) CBlockIndex(const CBlockHeader& block)
{ {
SetNull(); SetNull();

View file

@ -974,7 +974,7 @@ bool AppInit2(boost::thread_group& threadGroup)
// If the loaded chain has a wrong genesis, bail out immediately // If the loaded chain has a wrong genesis, bail out immediately
// (we're likely using a testnet datadir, or the other way around). // (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?")); 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) // Initialize the block index (no-op if non-empty database was already loaded)

File diff suppressed because it is too large Load diff

View file

@ -72,9 +72,17 @@ static const int MAX_SCRIPTCHECK_THREADS = 16;
/** -par default (number of script-checking threads, 0 = auto) */ /** -par default (number of script-checking threads, 0 = auto) */
static const int DEFAULT_SCRIPTCHECK_THREADS = 0; static const int DEFAULT_SCRIPTCHECK_THREADS = 0;
/** Number of blocks that can be requested at any given time from a single peer. */ /** 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; static const int MAX_BLOCKS_IN_TRANSIT_PER_PEER = 16;
/** Timeout in seconds before considering a block download peer unresponsive. */ /** Timeout in seconds during which a peer must stall block download progress before being disconnected. */
static const unsigned int BLOCK_DOWNLOAD_TIMEOUT = 60; 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 **/ /** "reject" message codes **/
static const unsigned char REJECT_MALFORMED = 0x01; static const unsigned char REJECT_MALFORMED = 0x01;
@ -110,6 +118,9 @@ extern bool fIsBareMultisigStd;
extern unsigned int nCoinCacheSize; extern unsigned int nCoinCacheSize;
extern CFeeRate minRelayTxFee; 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() // Minimum disk space required - used in CheckDiskSpace()
static const uint64_t nMinDiskSpace = 52428800; static const uint64_t nMinDiskSpace = 52428800;
@ -137,8 +148,6 @@ void RegisterNodeSignals(CNodeSignals& nodeSignals);
/** Unregister a network node */ /** Unregister a network node */
void UnregisterNodeSignals(CNodeSignals& nodeSignals); void UnregisterNodeSignals(CNodeSignals& nodeSignals);
void PushGetBlocks(CNode* pnode, CBlockIndex* pindexBegin, uint256 hashEnd);
/** Process an incoming block */ /** Process an incoming block */
bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp = NULL); bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp = NULL);
/** Check whether enough disk space is available for an incoming block */ /** 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 { struct CNodeStateStats {
int nMisbehavior; int nMisbehavior;
int nSyncHeight; int nSyncHeight;
int nCommonHeight;
std::vector<int> vHeightInFlight;
}; };
struct CDiskTxPos : public CDiskBlockPos 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 // 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); 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 // Context-independent validity checks
bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW = true); bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW = true);
bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW = true, bool fCheckMerkleRoot = 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 // Store block on disk
// if dbp is provided, the file is known to already reside 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 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);

View file

@ -73,7 +73,6 @@ map<CNetAddr, LocalServiceInfo> mapLocalHost;
static bool vfReachable[NET_MAX] = {}; static bool vfReachable[NET_MAX] = {};
static bool vfLimited[NET_MAX] = {}; static bool vfLimited[NET_MAX] = {};
static CNode* pnodeLocalHost = NULL; static CNode* pnodeLocalHost = NULL;
static CNode* pnodeSync = NULL;
uint64_t nLocalHostNonce = 0; uint64_t nLocalHostNonce = 0;
static std::vector<ListenSocket> vhListenSocket; static std::vector<ListenSocket> vhListenSocket;
CAddrMan addrman; CAddrMan addrman;
@ -519,10 +518,6 @@ void CNode::CloseSocketDisconnect()
TRY_LOCK(cs_vRecvMsg, lockRecv); TRY_LOCK(cs_vRecvMsg, lockRecv);
if (lockRecv) if (lockRecv)
vRecvMsg.clear(); vRecvMsg.clear();
// if this was the sync node, we'll need a new one
if (this == pnodeSync)
pnodeSync = NULL;
} }
void CNode::PushVersion() void CNode::PushVersion()
@ -615,7 +610,6 @@ void CNode::copyStats(CNodeStats &stats)
X(nSendBytes); X(nSendBytes);
X(nRecvBytes); X(nRecvBytes);
X(fWhitelisted); X(fWhitelisted);
stats.fSyncNode = (this == pnodeSync);
// It is common for nodes with good ping times to suddenly become lagged, // It is common for nodes with good ping times to suddenly become lagged,
// due to a new block arriving or other large transfer. // 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() void ThreadMessageHandler()
{ {
SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL); SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
while (true) while (true)
{ {
bool fHaveSyncNode = false;
vector<CNode*> vNodesCopy; vector<CNode*> vNodesCopy;
{ {
LOCK(cs_vNodes); LOCK(cs_vNodes);
vNodesCopy = vNodes; vNodesCopy = vNodes;
BOOST_FOREACH(CNode* pnode, vNodesCopy) { BOOST_FOREACH(CNode* pnode, vNodesCopy) {
pnode->AddRef(); pnode->AddRef();
if (pnode == pnodeSync)
fHaveSyncNode = true;
} }
} }
if (!fHaveSyncNode)
StartSync(vNodesCopy);
// Poll the connected nodes for messages // Poll the connected nodes for messages
CNode* pnodeTrickle = NULL; CNode* pnodeTrickle = NULL;
if (!vNodesCopy.empty()) if (!vNodesCopy.empty())
@ -2078,10 +2031,7 @@ CNode::CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn, bool fIn
nSendSize = 0; nSendSize = 0;
nSendOffset = 0; nSendOffset = 0;
hashContinue = 0; hashContinue = 0;
pindexLastGetBlocksBegin = 0;
hashLastGetBlocksEnd = 0;
nStartingHeight = -1; nStartingHeight = -1;
fStartSync = false;
fGetAddr = false; fGetAddr = false;
fRelayTxes = false; fRelayTxes = false;
setInventoryKnown.max_size(SendBufferSize() / 1000); setInventoryKnown.max_size(SendBufferSize() / 1000);

View file

@ -158,7 +158,6 @@ public:
int nStartingHeight; int nStartingHeight;
uint64_t nSendBytes; uint64_t nSendBytes;
uint64_t nRecvBytes; uint64_t nRecvBytes;
bool fSyncNode;
bool fWhitelisted; bool fWhitelisted;
double dPingTime; double dPingTime;
double dPingWait; double dPingWait;
@ -276,10 +275,7 @@ protected:
public: public:
uint256 hashContinue; uint256 hashContinue;
CBlockIndex* pindexLastGetBlocksBegin;
uint256 hashLastGetBlocksEnd;
int nStartingHeight; int nStartingHeight;
bool fStartSync;
// flood relay // flood relay
std::vector<CAddress> vAddrToSend; std::vector<CAddress> vAddrToSend;

View file

@ -98,39 +98,6 @@ bool CheckProofOfWork(uint256 hash, unsigned int nBits)
return true; 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) void UpdateTime(CBlockHeader* pblock, const CBlockIndex* pindexPrev)
{ {
pblock->nTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); pblock->nTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());

View file

@ -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 */ /** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */
bool CheckProofOfWork(uint256 hash, unsigned int 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); void UpdateTime(CBlockHeader* block, const CBlockIndex* pindexPrev);

View file

@ -836,29 +836,6 @@
</property> </property>
</widget> </widget>
</item> </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"> <item row="5" column="0">
<widget class="QLabel" name="label_29"> <widget class="QLabel" name="label_29">
<property name="text"> <property name="text">

View file

@ -611,7 +611,6 @@ void RPCConsole::updateNodeDetail(const CNodeCombinedStats *stats)
ui->peerSubversion->setText(QString::fromStdString(stats->nodeStats.cleanSubVer)); ui->peerSubversion->setText(QString::fromStdString(stats->nodeStats.cleanSubVer));
ui->peerDirection->setText(stats->nodeStats.fInbound ? tr("Inbound") : tr("Outbound")); ui->peerDirection->setText(stats->nodeStats.fInbound ? tr("Inbound") : tr("Outbound"));
ui->peerHeight->setText(QString("%1").arg(stats->nodeStats.nStartingHeight)); 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 // This check fails for example if the lock was busy and
// nodeStateStats couldn't be fetched. // nodeStateStats couldn't be fetched.

View file

@ -445,6 +445,7 @@ Value getblockchaininfo(const Array& params, bool fHelp)
"{\n" "{\n"
" \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\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" " \"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" " \"bestblockhash\": \"...\", (string) the hash of the currently best block\n"
" \"difficulty\": xxxxxx, (numeric) the current difficulty\n" " \"difficulty\": xxxxxx, (numeric) the current difficulty\n"
" \"verificationprogress\": xxxx, (numeric) estimate of verification progress [0..1]\n" " \"verificationprogress\": xxxx, (numeric) estimate of verification progress [0..1]\n"
@ -458,6 +459,7 @@ Value getblockchaininfo(const Array& params, bool fHelp)
Object obj; Object obj;
obj.push_back(Pair("chain", Params().NetworkIDString())); obj.push_back(Pair("chain", Params().NetworkIDString()));
obj.push_back(Pair("blocks", (int)chainActive.Height())); 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("bestblockhash", chainActive.Tip()->GetBlockHash().GetHex()));
obj.push_back(Pair("difficulty", (double)GetDifficulty())); obj.push_back(Pair("difficulty", (double)GetDifficulty()));
obj.push_back(Pair("verificationprogress", Checkpoints::GuessVerificationProgress(chainActive.Tip()))); obj.push_back(Pair("verificationprogress", Checkpoints::GuessVerificationProgress(chainActive.Tip())));

View file

@ -97,7 +97,12 @@ Value getpeerinfo(const Array& params, bool fHelp)
" \"inbound\": true|false, (boolean) Inbound (true) or Outbound (false)\n" " \"inbound\": true|false, (boolean) Inbound (true) or Outbound (false)\n"
" \"startingheight\": n, (numeric) The starting height (block) of the peer\n" " \"startingheight\": n, (numeric) The starting height (block) of the peer\n"
" \"banscore\": n, (numeric) The ban score\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" " ,...\n"
"]\n" "]\n"
@ -137,9 +142,14 @@ Value getpeerinfo(const Array& params, bool fHelp)
obj.push_back(Pair("startingheight", stats.nStartingHeight)); obj.push_back(Pair("startingheight", stats.nStartingHeight));
if (fStateStats) { if (fStateStats) {
obj.push_back(Pair("banscore", statestats.nMisbehavior)); 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)); obj.push_back(Pair("whitelisted", stats.fWhitelisted));
ret.push_back(obj); ret.push_back(obj);

View file

@ -106,51 +106,6 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
BOOST_CHECK(!CNode::IsBanned(addr)); 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() CTransaction RandomOrphan()
{ {
std::map<uint256, COrphanTx>::iterator it; std::map<uint256, COrphanTx>::iterator it;

View file

@ -33,8 +33,11 @@ static const int PROTOCOL_VERSION = 70002;
// initial proto version, to be increased after version/verack negotiation // initial proto version, to be increased after version/verack negotiation
static const int INIT_PROTO_VERSION = 209; 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 // 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; // nTime field added to CAddress, starting with this version;
// if possible, avoid requesting addresses nodes older than this // if possible, avoid requesting addresses nodes older than this