mirror of
https://github.com/dashpay/dash.git
synced 2024-12-26 04:22:55 +01:00
Merge pull request #3376 from UdjinM6/merge_11824
Merge remaining bits of #11824: Block ActivateBestChain to empty validationinterface queue
This commit is contained in:
commit
fa9b91b50f
@ -1184,16 +1184,16 @@ void static ProcessGetBlockData(CNode* pfrom, const Consensus::Params& consensus
|
|||||||
send = false;
|
send = false;
|
||||||
}
|
}
|
||||||
// Avoid leaking prune-height by never sending blocks below the NODE_NETWORK_LIMITED threshold
|
// Avoid leaking prune-height by never sending blocks below the NODE_NETWORK_LIMITED threshold
|
||||||
if (send && !pfrom->fWhitelisted && (
|
if (send && !pfrom->fWhitelisted && (
|
||||||
(((pfrom->GetLocalServices() & NODE_NETWORK_LIMITED) == NODE_NETWORK_LIMITED) && ((pfrom->GetLocalServices() & NODE_NETWORK) != NODE_NETWORK) && (chainActive.Tip()->nHeight - mi->second->nHeight > (int)NODE_NETWORK_LIMITED_MIN_BLOCKS + 2 /* add two blocks buffer extension for possible races */) )
|
(((pfrom->GetLocalServices() & NODE_NETWORK_LIMITED) == NODE_NETWORK_LIMITED) && ((pfrom->GetLocalServices() & NODE_NETWORK) != NODE_NETWORK) && (chainActive.Tip()->nHeight - mi->second->nHeight > (int)NODE_NETWORK_LIMITED_MIN_BLOCKS + 2 /* add two blocks buffer extension for possible races */) )
|
||||||
)) {
|
)) {
|
||||||
LogPrint(BCLog::NET, "Ignore block request below NODE_NETWORK_LIMITED threshold from peer=%d\n", pfrom->GetId());
|
LogPrint(BCLog::NET, "Ignore block request below NODE_NETWORK_LIMITED threshold from peer=%d\n", pfrom->GetId());
|
||||||
|
|
||||||
//disconnect node and prevent it from stalling (would otherwise wait for the missing block)
|
//disconnect node and prevent it from stalling (would otherwise wait for the missing block)
|
||||||
pfrom->fDisconnect = true;
|
pfrom->fDisconnect = true;
|
||||||
send = false;
|
send = false;
|
||||||
}
|
}
|
||||||
// Pruned nodes may have deleted the block, so check whether
|
// Pruned nodes may have deleted the block, so check whether
|
||||||
// it's available before trying to send.
|
// it's available before trying to send.
|
||||||
if (send && (mi->second->nStatus & BLOCK_HAVE_DATA))
|
if (send && (mi->second->nStatus & BLOCK_HAVE_DATA))
|
||||||
{
|
{
|
||||||
|
@ -206,3 +206,8 @@ void SingleThreadedSchedulerClient::EmptyQueue() {
|
|||||||
should_continue = !m_callbacks_pending.empty();
|
should_continue = !m_callbacks_pending.empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t SingleThreadedSchedulerClient::CallbacksPending() {
|
||||||
|
LOCK(m_cs_callbacks_pending);
|
||||||
|
return m_callbacks_pending.size();
|
||||||
|
}
|
||||||
|
@ -108,6 +108,8 @@ public:
|
|||||||
// Processes all remaining queue members on the calling thread, blocking until queue is empty
|
// Processes all remaining queue members on the calling thread, blocking until queue is empty
|
||||||
// Must be called after the CScheduler has no remaining processing threads!
|
// Must be called after the CScheduler has no remaining processing threads!
|
||||||
void EmptyQueue();
|
void EmptyQueue();
|
||||||
|
|
||||||
|
size_t CallbacksPending();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -86,9 +86,9 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
|
|||||||
fs::create_directories(pathTemp);
|
fs::create_directories(pathTemp);
|
||||||
gArgs.ForceSetArg("-datadir", pathTemp.string());
|
gArgs.ForceSetArg("-datadir", pathTemp.string());
|
||||||
|
|
||||||
// Note that because we don't bother running a scheduler thread here,
|
// We have to run a scheduler thread to prevent ActivateBestChain
|
||||||
// callbacks via CValidationInterface are unreliable, but that's OK,
|
// from blocking due to queue overrun.
|
||||||
// our unit tests aren't testing multiple parts of the code at once.
|
threadGroup.create_thread(boost::bind(&CScheduler::serviceQueue, &scheduler));
|
||||||
GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
|
GetMainSignals().RegisterBackgroundSignalScheduler(scheduler);
|
||||||
mempool.setSanityCheck(1.0);
|
mempool.setSanityCheck(1.0);
|
||||||
g_connman = std::unique_ptr<CConnman>(new CConnman(0x1337, 0x1337)); // Deterministic randomness for tests.
|
g_connman = std::unique_ptr<CConnman>(new CConnman(0x1337, 0x1337)); // Deterministic randomness for tests.
|
||||||
|
@ -206,8 +206,9 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
|
|||||||
// under other (eg consensus) flags.
|
// under other (eg consensus) flags.
|
||||||
// spend_tx is invalid according to DERSIG
|
// spend_tx is invalid according to DERSIG
|
||||||
{
|
{
|
||||||
CValidationState state;
|
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
|
|
||||||
|
CValidationState state;
|
||||||
PrecomputedTransactionData ptd_spend_tx(spend_tx);
|
PrecomputedTransactionData ptd_spend_tx(spend_tx);
|
||||||
|
|
||||||
BOOST_CHECK(!CheckInputs(spend_tx, state, pcoinsTip.get(), true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, nullptr));
|
BOOST_CHECK(!CheckInputs(spend_tx, state, pcoinsTip.get(), true, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, nullptr));
|
||||||
|
@ -54,6 +54,7 @@
|
|||||||
#include <llmq/quorums_chainlocks.h>
|
#include <llmq/quorums_chainlocks.h>
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <future>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#include <boost/algorithm/string/replace.hpp>
|
#include <boost/algorithm/string/replace.hpp>
|
||||||
@ -2849,6 +2850,14 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
|
|||||||
do {
|
do {
|
||||||
boost::this_thread::interruption_point();
|
boost::this_thread::interruption_point();
|
||||||
|
|
||||||
|
if (GetMainSignals().CallbacksPending() > 10) {
|
||||||
|
// Block until the validation queue drains. This should largely
|
||||||
|
// never happen in normal operation, however may happen during
|
||||||
|
// reindex, causing memory blowup if we run too far ahead.
|
||||||
|
SyncWithValidationInterfaceQueue();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const CBlockIndex *pindexFork;
|
const CBlockIndex *pindexFork;
|
||||||
bool fInitialDownload;
|
bool fInitialDownload;
|
||||||
{
|
{
|
||||||
|
@ -11,9 +11,11 @@
|
|||||||
#include <sync.h>
|
#include <sync.h>
|
||||||
#include <txmempool.h>
|
#include <txmempool.h>
|
||||||
#include <util.h>
|
#include <util.h>
|
||||||
|
#include <validation.h>
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <future>
|
||||||
|
|
||||||
#include <boost/signals2/signal.hpp>
|
#include <boost/signals2/signal.hpp>
|
||||||
|
|
||||||
@ -62,6 +64,11 @@ void CMainSignals::FlushBackgroundCallbacks() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t CMainSignals::CallbacksPending() {
|
||||||
|
if (!m_internals) return 0;
|
||||||
|
return m_internals->m_schedulerClient.CallbacksPending();
|
||||||
|
}
|
||||||
|
|
||||||
void CMainSignals::RegisterWithMempoolSignals(CTxMemPool& pool) {
|
void CMainSignals::RegisterWithMempoolSignals(CTxMemPool& pool) {
|
||||||
pool.NotifyEntryRemoved.connect(boost::bind(&CMainSignals::MempoolEntryRemoved, this, _1, _2));
|
pool.NotifyEntryRemoved.connect(boost::bind(&CMainSignals::MempoolEntryRemoved, this, _1, _2));
|
||||||
}
|
}
|
||||||
@ -148,6 +155,16 @@ void CallFunctionInValidationInterfaceQueue(std::function<void ()> func) {
|
|||||||
g_signals.m_internals->m_schedulerClient.AddToProcessQueue(std::move(func));
|
g_signals.m_internals->m_schedulerClient.AddToProcessQueue(std::move(func));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SyncWithValidationInterfaceQueue() {
|
||||||
|
AssertLockNotHeld(cs_main);
|
||||||
|
// Block until the validation queue drains
|
||||||
|
std::promise<void> promise;
|
||||||
|
CallFunctionInValidationInterfaceQueue([&promise] {
|
||||||
|
promise.set_value();
|
||||||
|
});
|
||||||
|
promise.get_future().wait();
|
||||||
|
}
|
||||||
|
|
||||||
void CMainSignals::MempoolEntryRemoved(CTransactionRef ptx, MemPoolRemovalReason reason) {
|
void CMainSignals::MempoolEntryRemoved(CTransactionRef ptx, MemPoolRemovalReason reason) {
|
||||||
if (reason != MemPoolRemovalReason::BLOCK && reason != MemPoolRemovalReason::CONFLICT) {
|
if (reason != MemPoolRemovalReason::BLOCK && reason != MemPoolRemovalReason::CONFLICT) {
|
||||||
m_internals->m_schedulerClient.AddToProcessQueue([ptx, this] {
|
m_internals->m_schedulerClient.AddToProcessQueue([ptx, this] {
|
||||||
|
@ -50,6 +50,16 @@ void UnregisterAllValidationInterfaces();
|
|||||||
* will result in a deadlock (that DEBUG_LOCKORDER will miss).
|
* will result in a deadlock (that DEBUG_LOCKORDER will miss).
|
||||||
*/
|
*/
|
||||||
void CallFunctionInValidationInterfaceQueue(std::function<void ()> func);
|
void CallFunctionInValidationInterfaceQueue(std::function<void ()> func);
|
||||||
|
/**
|
||||||
|
* This is a synonym for the following, which asserts certain locks are not
|
||||||
|
* held:
|
||||||
|
* std::promise<void> promise;
|
||||||
|
* CallFunctionInValidationInterfaceQueue([&promise] {
|
||||||
|
* promise.set_value();
|
||||||
|
* });
|
||||||
|
* promise.get_future().wait();
|
||||||
|
*/
|
||||||
|
void SyncWithValidationInterfaceQueue();
|
||||||
|
|
||||||
class CValidationInterface {
|
class CValidationInterface {
|
||||||
protected:
|
protected:
|
||||||
@ -151,6 +161,8 @@ public:
|
|||||||
/** Call any remaining callbacks on the calling thread */
|
/** Call any remaining callbacks on the calling thread */
|
||||||
void FlushBackgroundCallbacks();
|
void FlushBackgroundCallbacks();
|
||||||
|
|
||||||
|
size_t CallbacksPending();
|
||||||
|
|
||||||
/** Register with mempool to call TransactionRemovedFromMempool callbacks */
|
/** Register with mempool to call TransactionRemovedFromMempool callbacks */
|
||||||
void RegisterWithMempoolSignals(CTxMemPool& pool);
|
void RegisterWithMempoolSignals(CTxMemPool& pool);
|
||||||
/** Unregister with mempool */
|
/** Unregister with mempool */
|
||||||
|
@ -1485,12 +1485,7 @@ void CWallet::BlockUntilSyncedToCurrentChain() {
|
|||||||
// ...otherwise put a callback in the validation interface queue and wait
|
// ...otherwise put a callback in the validation interface queue and wait
|
||||||
// for the queue to drain enough to execute it (indicating we are caught up
|
// for the queue to drain enough to execute it (indicating we are caught up
|
||||||
// at least with the time we entered this function).
|
// at least with the time we entered this function).
|
||||||
|
SyncWithValidationInterfaceQueue();
|
||||||
std::promise<void> promise;
|
|
||||||
CallFunctionInValidationInterfaceQueue([&promise] {
|
|
||||||
promise.set_value();
|
|
||||||
});
|
|
||||||
promise.get_future().wait();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user