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" &
|
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.
|
||||||
|
|
32
src/chain.h
32
src/chain.h
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
719
src/main.cpp
719
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) */
|
/** -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);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
50
src/net.cpp
50
src/net.cpp
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
33
src/pow.cpp
33
src/pow.cpp
|
@ -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());
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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())));
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue