Skip to content

Commit a3c8cb2

Browse files
OlegGirkoUdjinM6
authored andcommitted
Backport Bitcoin PR#8865: Decouple peer-processing-logic from block-connection-logic (#1556)
* Make validationinterface.UpdatedBlockTip more verbose In anticipation of making all the callbacks out of block processing flow through it. Note that vHashes will always have something in it since pindexFork != pindexNewTip. * Remove duplicate nBlocksEstimate cmp (we already checked IsIBD()) * Remove CConnman parameter from ProcessNewBlock/ActivateBestChain * Remove SyncWithWallets wrapper function * Move net-processing logic definitions together in main.h * Use CValidationInterface from chain logic to notify peer logic This adds a new CValidationInterface subclass, defined in main.h, to receive notifications of UpdatedBlockTip and use that to push blocks to peers, instead of doing it directly from ActivateBestChain. * Always call UpdatedBlockTip, even if blocks were only disconnected * Use BlockChecked signal to send reject messages from mapBlockSource
1 parent cc4db34 commit a3c8cb2

12 files changed

+133
-106
lines changed

src/init.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ static const bool DEFAULT_DISABLE_SAFEMODE = false;
9999
static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false;
100100

101101
std::unique_ptr<CConnman> g_connman;
102+
std::unique_ptr<PeerLogicValidation> peerLogic;
102103

103104
#if ENABLE_ZMQ
104105
static CZMQNotificationInterface* pzmqNotificationInterface = NULL;
@@ -228,6 +229,8 @@ void PrepareShutdown()
228229
#endif
229230
GenerateBitcoins(false, 0, Params(), *g_connman);
230231
MapPort(false);
232+
UnregisterValidationInterface(peerLogic.get());
233+
peerLogic.reset();
231234
g_connman.reset();
232235

233236
// STORE DATA CACHES INTO SERIALIZED DAT FILES
@@ -1316,6 +1319,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
13161319
g_connman = std::unique_ptr<CConnman>(new CConnman());
13171320
CConnman& connman = *g_connman;
13181321

1322+
peerLogic.reset(new PeerLogicValidation(&connman));
1323+
RegisterValidationInterface(peerLogic.get());
13191324
RegisterNodeSignals(GetNodeSignals());
13201325

13211326
// sanitize comments per BIP-0014, format user agent and check total size

src/main.cpp

Lines changed: 65 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1540,7 +1540,8 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
15401540
}
15411541
}
15421542

1543-
if(!fDryRun) SyncWithWallets(tx, NULL);
1543+
if(!fDryRun)
1544+
GetMainSignals().SyncTransaction(tx, NULL);
15441545

15451546
return true;
15461547
}
@@ -1966,17 +1967,6 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
19661967
}
19671968

19681969
void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) {
1969-
int nDoS = 0;
1970-
if (state.IsInvalid(nDoS)) {
1971-
std::map<uint256, NodeId>::iterator it = mapBlockSource.find(pindex->GetBlockHash());
1972-
if (it != mapBlockSource.end() && State(it->second)) {
1973-
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
1974-
CBlockReject reject = {(unsigned char)state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), pindex->GetBlockHash()};
1975-
State(it->second)->rejects.push_back(reject);
1976-
if (nDoS > 0)
1977-
Misbehaving(it->second, nDoS);
1978-
}
1979-
}
19801970
if (!state.CorruptionPossible()) {
19811971
pindex->nStatus |= BLOCK_FAILED_VALID;
19821972
setDirtyBlockIndex.insert(pindex);
@@ -3047,7 +3037,7 @@ bool static DisconnectTip(CValidationState& state, const Consensus::Params& cons
30473037
// Let wallets know transactions went from 1-confirmed to
30483038
// 0-confirmed or conflicted:
30493039
BOOST_FOREACH(const CTransaction &tx, block.vtx) {
3050-
SyncWithWallets(tx, NULL);
3040+
GetMainSignals().SyncTransaction(tx, NULL);
30513041
}
30523042
return true;
30533043
}
@@ -3086,7 +3076,6 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams,
30863076
InvalidBlockFound(pindexNew, state);
30873077
return error("ConnectTip(): ConnectBlock %s failed", pindexNew->GetBlockHash().ToString());
30883078
}
3089-
mapBlockSource.erase(pindexNew->GetBlockHash());
30903079
nTime3 = GetTimeMicros(); nTimeConnectTotal += nTime3 - nTime2;
30913080
LogPrint("bench", " - Connect total: %.2fms [%.2fs]\n", (nTime3 - nTime2) * 0.001, nTimeConnectTotal * 0.000001);
30923081
assert(view.Flush());
@@ -3106,11 +3095,11 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams,
31063095
// Tell wallet about transactions that went from mempool
31073096
// to conflicted:
31083097
BOOST_FOREACH(const CTransaction &tx, txConflicted) {
3109-
SyncWithWallets(tx, NULL);
3098+
GetMainSignals().SyncTransaction(tx, NULL);
31103099
}
31113100
// ... and about transactions that got confirmed:
31123101
BOOST_FOREACH(const CTransaction &tx, pblock->vtx) {
3113-
SyncWithWallets(tx, pblock);
3102+
GetMainSignals().SyncTransaction(tx, pblock);
31143103
}
31153104

31163105
int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1;
@@ -3336,7 +3325,7 @@ static void NotifyHeaderTip() {
33363325
* or an activated best chain. pblock is either NULL or a pointer to a block
33373326
* that is already loaded (to avoid loading it again from disk).
33383327
*/
3339-
bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, const CBlock *pblock, CConnman* connman) {
3328+
bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, const CBlock *pblock) {
33403329
CBlockIndex *pindexMostWork = NULL;
33413330
CBlockIndex *pindexNewTip = NULL;
33423331
do {
@@ -3346,7 +3335,6 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
33463335

33473336
const CBlockIndex *pindexFork;
33483337
bool fInitialDownload;
3349-
int nNewHeight;
33503338
{
33513339
LOCK(cs_main);
33523340
CBlockIndex *pindexOldTip = chainActive.Tip();
@@ -3369,49 +3357,17 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
33693357
pindexNewTip = chainActive.Tip();
33703358
pindexFork = chainActive.FindFork(pindexOldTip);
33713359
fInitialDownload = IsInitialBlockDownload();
3372-
nNewHeight = chainActive.Height();
33733360
}
33743361
// When we reach this point, we switched to a new tip (stored in pindexNewTip).
33753362

33763363
// Notifications/callbacks that can run without cs_main
3377-
if(connman)
3378-
connman->SetBestHeight(chainActive.Height());
3364+
3365+
// Notify external listeners about the new tip.
3366+
GetMainSignals().UpdatedBlockTip(pindexNewTip, pindexFork, fInitialDownload);
33793367

33803368
// Always notify the UI if a new block tip was connected
33813369
if (pindexFork != pindexNewTip) {
33823370
uiInterface.NotifyBlockTip(fInitialDownload, pindexNewTip);
3383-
3384-
if (!fInitialDownload) {
3385-
// Find the hashes of all blocks that weren't previously in the best chain.
3386-
std::vector<uint256> vHashes;
3387-
CBlockIndex *pindexToAnnounce = pindexNewTip;
3388-
while (pindexToAnnounce != pindexFork) {
3389-
vHashes.push_back(pindexToAnnounce->GetBlockHash());
3390-
pindexToAnnounce = pindexToAnnounce->pprev;
3391-
if (vHashes.size() == MAX_BLOCKS_TO_ANNOUNCE) {
3392-
// Limit announcements in case of a huge reorganization.
3393-
// Rely on the peer's synchronization mechanism in that case.
3394-
break;
3395-
}
3396-
}
3397-
// Relay inventory, but don't relay old inventory during initial block download.
3398-
int nBlockEstimate = 0;
3399-
if (fCheckpointsEnabled)
3400-
nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(chainparams.Checkpoints());
3401-
if(connman) {
3402-
connman->ForEachNode([nNewHeight, nBlockEstimate, &vHashes](CNode* pnode) {
3403-
if (nNewHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) {
3404-
BOOST_REVERSE_FOREACH(const uint256& hash, vHashes) {
3405-
pnode->PushBlockHash(hash);
3406-
}
3407-
}
3408-
});
3409-
}
3410-
// Notify external listeners about the new tip.
3411-
if (!vHashes.empty()) {
3412-
GetMainSignals().UpdatedBlockTip(pindexNewTip);
3413-
}
3414-
}
34153371
}
34163372
} while (pindexNewTip != pindexMostWork);
34173373
CheckBlockIndex(chainparams.GetConsensus());
@@ -4003,7 +3959,7 @@ static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned
40033959
}
40043960

40053961

4006-
bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp, CConnman* connman)
3962+
bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp)
40073963
{
40083964
{
40093965
LOCK(cs_main);
@@ -4025,7 +3981,7 @@ bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, C
40253981

40263982
NotifyHeaderTip();
40273983

4028-
if (!ActivateBestChain(state, chainparams, pblock, connman))
3984+
if (!ActivateBestChain(state, chainparams, pblock))
40293985
return error("%s: ActivateBestChain failed", __func__);
40303986

40313987
masternodeSync.IsBlockchainSynced(true);
@@ -4909,6 +4865,59 @@ std::string GetWarnings(const std::string& strFor)
49094865

49104866

49114867

4868+
//////////////////////////////////////////////////////////////////////////////
4869+
//
4870+
// blockchain -> download logic notification
4871+
//
4872+
4873+
void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {
4874+
const int nNewHeight = pindexNew->nHeight;
4875+
connman->SetBestHeight(nNewHeight);
4876+
4877+
if (!fInitialDownload) {
4878+
// Find the hashes of all blocks that weren't previously in the best chain.
4879+
std::vector<uint256> vHashes;
4880+
const CBlockIndex *pindexToAnnounce = pindexNew;
4881+
while (pindexToAnnounce != pindexFork) {
4882+
vHashes.push_back(pindexToAnnounce->GetBlockHash());
4883+
pindexToAnnounce = pindexToAnnounce->pprev;
4884+
if (vHashes.size() == MAX_BLOCKS_TO_ANNOUNCE) {
4885+
// Limit announcements in case of a huge reorganization.
4886+
// Rely on the peer's synchronization mechanism in that case.
4887+
break;
4888+
}
4889+
}
4890+
// Relay inventory, but don't relay old inventory during initial block download.
4891+
connman->ForEachNode([nNewHeight, &vHashes](CNode* pnode) {
4892+
if (nNewHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : 0)) {
4893+
BOOST_REVERSE_FOREACH(const uint256& hash, vHashes) {
4894+
pnode->PushBlockHash(hash);
4895+
}
4896+
}
4897+
});
4898+
}
4899+
}
4900+
4901+
void PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationState& state) {
4902+
LOCK(cs_main);
4903+
4904+
const uint256 hash(block.GetHash());
4905+
std::map<uint256, NodeId>::iterator it = mapBlockSource.find(hash);
4906+
4907+
int nDoS = 0;
4908+
if (state.IsInvalid(nDoS)) {
4909+
if (it != mapBlockSource.end() && State(it->second)) {
4910+
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
4911+
CBlockReject reject = {(unsigned char)state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), hash};
4912+
State(it->second)->rejects.push_back(reject);
4913+
if (nDoS > 0)
4914+
Misbehaving(it->second, nDoS);
4915+
}
4916+
}
4917+
if (it != mapBlockSource.end())
4918+
mapBlockSource.erase(it);
4919+
}
4920+
49124921
//////////////////////////////////////////////////////////////////////////////
49134922
//
49144923
// Messages
@@ -6107,7 +6116,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
61076116
// Such an unrequested block may still be processed, subject to the
61086117
// conditions in AcceptBlock().
61096118
bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload();
6110-
ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL, &connman);
6119+
ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL);
61116120
int nDoS;
61126121
if (state.IsInvalid(nDoS)) {
61136122
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes

src/main.h

Lines changed: 44 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "net.h"
1818
#include "script/script_error.h"
1919
#include "sync.h"
20+
#include "validationinterface.h"
2021
#include "versionbits.h"
2122
#include "spentindex.h"
2223

@@ -42,7 +43,6 @@ class CTxMemPool;
4243
class CValidationInterface;
4344
class CValidationState;
4445

45-
struct CNodeStateStats;
4646
struct LockPoints;
4747

4848
/** Default for accepting alerts from the P2P network. */
@@ -189,11 +189,6 @@ static const unsigned int DEFAULT_CHECKLEVEL = 3;
189189
// Setting the target to > than 550MB will make it likely we can respect the target.
190190
static const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES = 550 * 1024 * 1024;
191191

192-
/** Register with a network node to receive its signals */
193-
void RegisterNodeSignals(CNodeSignals& nodeSignals);
194-
/** Unregister a network node */
195-
void UnregisterNodeSignals(CNodeSignals& nodeSignals);
196-
197192
/**
198193
* Process an incoming block. This only returns after the best known valid
199194
* block is made active. Note that it does not, however, guarantee that the
@@ -206,7 +201,7 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals);
206201
* @param[out] dbp The already known disk position of pblock, or NULL if not yet stored.
207202
* @return True if state.IsValid()
208203
*/
209-
bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp, CConnman* connman);
204+
bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp);
210205
/** Check whether enough disk space is available for an incoming block */
211206
bool CheckDiskSpace(uint64_t nAdditionalBytes = 0);
212207
/** Open a block file (blk?????.dat) */
@@ -223,15 +218,6 @@ bool InitBlockIndex(const CChainParams& chainparams);
223218
bool LoadBlockIndex();
224219
/** Unload database information */
225220
void UnloadBlockIndex();
226-
/** Process protocol messages received from a given node */
227-
bool ProcessMessages(CNode* pfrom, CConnman& connman);
228-
/**
229-
* Send queued protocol messages to be sent to a give node.
230-
*
231-
* @param[in] pto The node which we are sending messages to.
232-
* @param[in] connman The connection manager for that node.
233-
*/
234-
bool SendMessages(CNode* pto, CConnman& connman);
235221
/** Run an instance of the script checking thread */
236222
void ThreadScriptCheck();
237223
/** Check whether we are doing an initial block download (synchronizing from disk or network) */
@@ -247,7 +233,7 @@ std::string GetWarnings(const std::string& strFor);
247233
/** Retrieve a transaction (from memory pool, or from disk, if possible) */
248234
bool GetTransaction(const uint256 &hash, CTransaction &tx, const Consensus::Params& params, uint256 &hashBlock, bool fAllowSlow = false);
249235
/** Find the best known block, and make it the tip of the block chain */
250-
bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, const CBlock* pblock = NULL, CConnman* connman = NULL);
236+
bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, const CBlock* pblock = NULL);
251237

252238
double ConvertBitsToDouble(unsigned int nBits);
253239
CAmount GetBlockSubsidy(int nBits, int nHeight, const Consensus::Params& consensusParams, bool fSuperblockPartOnly = false);
@@ -277,10 +263,6 @@ void UnlinkPrunedFiles(std::set<int>& setFilesToPrune);
277263

278264
/** Create a new block index entry for a given block hash */
279265
CBlockIndex * InsertBlockIndex(uint256 hash);
280-
/** Get statistics from node state */
281-
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats);
282-
/** Increase a node's misbehavior score. */
283-
void Misbehaving(NodeId nodeid, int howmuch);
284266
/** Flush all state, indexes and buffers to disk. */
285267
void FlushStateToDisk();
286268
/** Prune block files and flush state to disk. */
@@ -301,13 +283,6 @@ std::string FormatStateMessage(const CValidationState &state);
301283
/** Get the BIP9 state for a given deployment at the current tip. */
302284
ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos);
303285

304-
struct CNodeStateStats {
305-
int nMisbehavior;
306-
int nSyncHeight;
307-
int nCommonHeight;
308-
std::vector<int> vHeightInFlight;
309-
};
310-
311286
struct CTimestampIndexIteratorKey {
312287
unsigned int timestamp;
313288

@@ -863,4 +838,45 @@ static const unsigned int REJECT_ALREADY_KNOWN = 0x101;
863838
/** Transaction conflicts with a transaction already known */
864839
static const unsigned int REJECT_CONFLICT = 0x102;
865840

841+
// The following things handle network-processing logic
842+
// (and should be moved to a separate file)
843+
844+
/** Register with a network node to receive its signals */
845+
void RegisterNodeSignals(CNodeSignals& nodeSignals);
846+
/** Unregister a network node */
847+
void UnregisterNodeSignals(CNodeSignals& nodeSignals);
848+
849+
class PeerLogicValidation : public CValidationInterface {
850+
private:
851+
CConnman* connman;
852+
853+
public:
854+
PeerLogicValidation(CConnman* connmanIn) : connman(connmanIn) {}
855+
856+
virtual void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload);
857+
virtual void BlockChecked(const CBlock& block, const CValidationState& state);
858+
};
859+
860+
struct CNodeStateStats {
861+
int nMisbehavior;
862+
int nSyncHeight;
863+
int nCommonHeight;
864+
std::vector<int> vHeightInFlight;
865+
};
866+
867+
/** Get statistics from node state */
868+
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats);
869+
/** Increase a node's misbehavior score. */
870+
void Misbehaving(NodeId nodeid, int howmuch);
871+
872+
/** Process protocol messages received from a given node */
873+
bool ProcessMessages(CNode* pfrom, CConnman& connman);
874+
/**
875+
* Send queued protocol messages to be sent to a give node.
876+
*
877+
* @param[in] pto The node which we are sending messages to.
878+
* @param[in] connman The connection manager for that node.
879+
*/
880+
bool SendMessages(CNode* pto, CConnman& connman);
881+
866882
#endif // BITCOIN_MAIN_H

0 commit comments

Comments
 (0)