mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 03:52:49 +01:00
merge bitcoin#19064: Cleanup thread ctor calls
Co-authored-by: UdjinM6 <UdjinM6@users.noreply.github.com>
This commit is contained in:
parent
8c742e9d15
commit
a2dcf74cf4
@ -332,6 +332,7 @@ BITCOIN_CORE_H = \
|
|||||||
util/sock.h \
|
util/sock.h \
|
||||||
util/string.h \
|
util/string.h \
|
||||||
util/time.h \
|
util/time.h \
|
||||||
|
util/thread.h \
|
||||||
util/threadnames.h \
|
util/threadnames.h \
|
||||||
util/trace.h \
|
util/trace.h \
|
||||||
util/translation.h \
|
util/translation.h \
|
||||||
@ -755,6 +756,7 @@ libbitcoin_util_a_SOURCES = \
|
|||||||
util/time.cpp \
|
util/time.cpp \
|
||||||
util/serfloat.cpp \
|
util/serfloat.cpp \
|
||||||
util/string.cpp \
|
util/string.cpp \
|
||||||
|
util/thread.cpp \
|
||||||
util/threadnames.cpp \
|
util/threadnames.cpp \
|
||||||
$(BITCOIN_CORE_H)
|
$(BITCOIN_CORE_H)
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <shutdown.h>
|
#include <shutdown.h>
|
||||||
#include <tinyformat.h>
|
#include <tinyformat.h>
|
||||||
#include <ui_interface.h>
|
#include <ui_interface.h>
|
||||||
|
#include <util/thread.h>
|
||||||
#include <util/translation.h>
|
#include <util/translation.h>
|
||||||
#include <validation.h> // For g_chainman
|
#include <validation.h> // For g_chainman
|
||||||
#include <warnings.h>
|
#include <warnings.h>
|
||||||
@ -353,8 +354,7 @@ bool BaseIndex::Start(CChainState& active_chainstate)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_thread_sync = std::thread(&TraceThread<std::function<void()>>, GetName(),
|
m_thread_sync = std::thread(&util::TraceThread, GetName(), [this] { ThreadSync(); });
|
||||||
std::bind(&BaseIndex::ThreadSync, this));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +61,7 @@
|
|||||||
#include <util/strencodings.h>
|
#include <util/strencodings.h>
|
||||||
#include <util/string.h>
|
#include <util/string.h>
|
||||||
#include <util/system.h>
|
#include <util/system.h>
|
||||||
|
#include <util/thread.h>
|
||||||
#include <util/threadnames.h>
|
#include <util/threadnames.h>
|
||||||
#include <util/translation.h>
|
#include <util/translation.h>
|
||||||
#include <validation.h>
|
#include <validation.h>
|
||||||
@ -1618,7 +1619,7 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc
|
|||||||
node.scheduler = std::make_unique<CScheduler>();
|
node.scheduler = std::make_unique<CScheduler>();
|
||||||
|
|
||||||
// Start the lightweight task scheduler thread
|
// Start the lightweight task scheduler thread
|
||||||
node.scheduler->m_service_thread = std::thread([&] { TraceThread("scheduler", [&] { node.scheduler->serviceQueue(); }); });
|
node.scheduler->m_service_thread = std::thread(util::TraceThread, "scheduler", [&] { node.scheduler->serviceQueue(); });
|
||||||
|
|
||||||
// Gather some entropy once per minute.
|
// Gather some entropy once per minute.
|
||||||
node.scheduler->scheduleEvery([]{
|
node.scheduler->scheduleEvery([]{
|
||||||
@ -2391,7 +2392,7 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc
|
|||||||
vImportFiles.push_back(strFile);
|
vImportFiles.push_back(strFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
chainman.m_load_block = std::thread(&TraceThread<std::function<void()>>, "loadblk", [=, &chainman, &args] {
|
chainman.m_load_block = std::thread(&util::TraceThread, "loadblk", [=, &chainman, &args] {
|
||||||
ThreadImport(chainman, *pdsNotificationInterface ,vImportFiles, args);
|
ThreadImport(chainman, *pdsNotificationInterface ,vImportFiles, args);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include <spork.h>
|
#include <spork.h>
|
||||||
#include <txmempool.h>
|
#include <txmempool.h>
|
||||||
#include <ui_interface.h>
|
#include <ui_interface.h>
|
||||||
|
#include <util/thread.h>
|
||||||
#include <validation.h>
|
#include <validation.h>
|
||||||
|
|
||||||
namespace llmq
|
namespace llmq
|
||||||
@ -37,7 +38,7 @@ CChainLocksHandler::CChainLocksHandler(CChainState& chainstate, CConnman& _connm
|
|||||||
mempool(_mempool),
|
mempool(_mempool),
|
||||||
m_peerman(peerman),
|
m_peerman(peerman),
|
||||||
scheduler(std::make_unique<CScheduler>()),
|
scheduler(std::make_unique<CScheduler>()),
|
||||||
scheduler_thread(std::make_unique<std::thread>([&] { TraceThread("cl-schdlr", [&] { scheduler->serviceQueue(); }); }))
|
scheduler_thread(std::make_unique<std::thread>(std::thread(util::TraceThread, "cl-schdlr", [&] { scheduler->serviceQueue(); })))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include <chainparams.h>
|
#include <chainparams.h>
|
||||||
#include <net_processing.h>
|
#include <net_processing.h>
|
||||||
#include <validation.h>
|
#include <validation.h>
|
||||||
|
#include <util/thread.h>
|
||||||
#include <util/underlying.h>
|
#include <util/underlying.h>
|
||||||
|
|
||||||
namespace llmq
|
namespace llmq
|
||||||
@ -151,8 +152,8 @@ void CDKGSessionHandler::StartThread()
|
|||||||
throw std::runtime_error("Tried to start an already started CDKGSessionHandler thread.");
|
throw std::runtime_error("Tried to start an already started CDKGSessionHandler thread.");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string threadName = strprintf("llmq-%d-%d", ToUnderlying(params.type), quorumIndex);
|
m_thread_name = strprintf("llmq-%d-%d", ToUnderlying(params.type), quorumIndex);
|
||||||
phaseHandlerThread = std::thread(&TraceThread<std::function<void()> >, threadName, std::function<void()>(std::bind(&CDKGSessionHandler::PhaseHandlerThread, this)));
|
phaseHandlerThread = std::thread(util::TraceThread, m_thread_name.c_str(), [this] { PhaseHandlerThread(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDKGSessionHandler::StopThread()
|
void CDKGSessionHandler::StopThread()
|
||||||
|
@ -127,6 +127,7 @@ private:
|
|||||||
|
|
||||||
std::unique_ptr<CDKGSession> curSession;
|
std::unique_ptr<CDKGSession> curSession;
|
||||||
std::thread phaseHandlerThread;
|
std::thread phaseHandlerThread;
|
||||||
|
std::string m_thread_name;
|
||||||
|
|
||||||
// Do not guard these, they protect their internals themselves
|
// Do not guard these, they protect their internals themselves
|
||||||
CDKGPendingMessages pendingContributions;
|
CDKGPendingMessages pendingContributions;
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include <txmempool.h>
|
#include <txmempool.h>
|
||||||
#include <util/irange.h>
|
#include <util/irange.h>
|
||||||
#include <util/ranges.h>
|
#include <util/ranges.h>
|
||||||
|
#include <util/thread.h>
|
||||||
#include <validation.h>
|
#include <validation.h>
|
||||||
|
|
||||||
#include <cxxtimer.hpp>
|
#include <cxxtimer.hpp>
|
||||||
@ -459,7 +460,7 @@ void CInstantSendManager::Start()
|
|||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
workThread = std::thread(&TraceThread<std::function<void()> >, "isman", std::function<void()>(std::bind(&CInstantSendManager::WorkThreadMain, this)));
|
workThread = std::thread(&util::TraceThread, "isman", [this] { WorkThreadMain(); });
|
||||||
|
|
||||||
sigman.RegisterRecoveredSigsListener(this);
|
sigman.RegisterRecoveredSigsListener(this);
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include <netmessagemaker.h>
|
#include <netmessagemaker.h>
|
||||||
#include <spork.h>
|
#include <spork.h>
|
||||||
#include <util/irange.h>
|
#include <util/irange.h>
|
||||||
|
#include <util/thread.h>
|
||||||
#include <util/underlying.h>
|
#include <util/underlying.h>
|
||||||
|
|
||||||
#include <cxxtimer.hpp>
|
#include <cxxtimer.hpp>
|
||||||
@ -183,9 +184,7 @@ void CSigSharesManager::StartWorkerThread()
|
|||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
workThread = std::thread(&TraceThread<std::function<void()> >,
|
workThread = std::thread(&util::TraceThread, "sigshares", [this] { WorkThreadMain(); });
|
||||||
"sigshares",
|
|
||||||
std::function<void()>(std::bind(&CSigSharesManager::WorkThreadMain, this)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSigSharesManager::StopWorkerThread()
|
void CSigSharesManager::StopWorkerThread()
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include <netbase.h>
|
#include <netbase.h>
|
||||||
#include <threadinterrupt.h>
|
#include <threadinterrupt.h>
|
||||||
#include <util/system.h>
|
#include <util/system.h>
|
||||||
|
#include <util/thread.h>
|
||||||
|
|
||||||
#ifdef USE_NATPMP
|
#ifdef USE_NATPMP
|
||||||
#include <compat.h>
|
#include <compat.h>
|
||||||
@ -255,7 +256,7 @@ void StartThreadMapPort()
|
|||||||
{
|
{
|
||||||
if (!g_mapport_thread.joinable()) {
|
if (!g_mapport_thread.joinable()) {
|
||||||
assert(!g_mapport_interrupt);
|
assert(!g_mapport_interrupt);
|
||||||
g_mapport_thread = std::thread(std::bind(&TraceThread<void (*)()>, "mapport", &ThreadMapPort));
|
g_mapport_thread = std::thread(&util::TraceThread, "mapport", &ThreadMapPort);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
21
src/net.cpp
21
src/net.cpp
@ -25,6 +25,7 @@
|
|||||||
#include <ui_interface.h>
|
#include <ui_interface.h>
|
||||||
#include <util/sock.h>
|
#include <util/sock.h>
|
||||||
#include <util/strencodings.h>
|
#include <util/strencodings.h>
|
||||||
|
#include <util/thread.h>
|
||||||
#include <util/translation.h>
|
#include <util/translation.h>
|
||||||
#include <validation.h>
|
#include <validation.h>
|
||||||
|
|
||||||
@ -3195,15 +3196,15 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Send and receive from sockets, accept connections
|
// Send and receive from sockets, accept connections
|
||||||
threadSocketHandler = std::thread(&TraceThread<std::function<void()> >, "net", std::function<void()>(std::bind(&CConnman::ThreadSocketHandler, this)));
|
threadSocketHandler = std::thread(&util::TraceThread, "net", [this] { ThreadSocketHandler(); });
|
||||||
|
|
||||||
if (!gArgs.GetBoolArg("-dnsseed", true))
|
if (!gArgs.GetBoolArg("-dnsseed", true))
|
||||||
LogPrintf("DNS seeding disabled\n");
|
LogPrintf("DNS seeding disabled\n");
|
||||||
else
|
else
|
||||||
threadDNSAddressSeed = std::thread(&TraceThread<std::function<void()> >, "dnsseed", std::function<void()>(std::bind(&CConnman::ThreadDNSAddressSeed, this)));
|
threadDNSAddressSeed = std::thread(&util::TraceThread, "dnsseed", [this] { ThreadDNSAddressSeed(); });
|
||||||
|
|
||||||
// Initiate outbound connections from -addnode
|
// Initiate outbound connections from -addnode
|
||||||
threadOpenAddedConnections = std::thread(&TraceThread<std::function<void()> >, "addcon", std::function<void()>(std::bind(&CConnman::ThreadOpenAddedConnections, this)));
|
threadOpenAddedConnections = std::thread(&util::TraceThread, "addcon", [this] { ThreadOpenAddedConnections(); });
|
||||||
|
|
||||||
if (connOptions.m_use_addrman_outgoing && !connOptions.m_specified_outgoing.empty()) {
|
if (connOptions.m_use_addrman_outgoing && !connOptions.m_specified_outgoing.empty()) {
|
||||||
if (clientInterface) {
|
if (clientInterface) {
|
||||||
@ -3213,19 +3214,21 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (connOptions.m_use_addrman_outgoing || !connOptions.m_specified_outgoing.empty())
|
if (connOptions.m_use_addrman_outgoing || !connOptions.m_specified_outgoing.empty()) {
|
||||||
threadOpenConnections = std::thread(&TraceThread<std::function<void()> >, "opencon", std::function<void()>(std::bind(&CConnman::ThreadOpenConnections, this, connOptions.m_specified_outgoing)));
|
threadOpenConnections = std::thread(
|
||||||
|
&util::TraceThread, "opencon",
|
||||||
|
[this, connect = connOptions.m_specified_outgoing] { ThreadOpenConnections(connect); });
|
||||||
|
}
|
||||||
|
|
||||||
// Initiate masternode connections
|
// Initiate masternode connections
|
||||||
threadOpenMasternodeConnections = std::thread(&TraceThread<std::function<void()> >, "mncon", std::function<void()>(std::bind(&CConnman::ThreadOpenMasternodeConnections, this)));
|
threadOpenMasternodeConnections = std::thread(&util::TraceThread, "mncon", [this] { ThreadOpenMasternodeConnections(); });
|
||||||
|
|
||||||
// Process messages
|
// Process messages
|
||||||
threadMessageHandler = std::thread(&TraceThread<std::function<void()> >, "msghand", std::function<void()>(std::bind(&CConnman::ThreadMessageHandler, this)));
|
threadMessageHandler = std::thread(&util::TraceThread, "msghand", [this] { ThreadMessageHandler(); });
|
||||||
|
|
||||||
if (connOptions.m_i2p_accept_incoming && m_i2p_sam_session.get() != nullptr) {
|
if (connOptions.m_i2p_accept_incoming && m_i2p_sam_session.get() != nullptr) {
|
||||||
threadI2PAcceptIncoming =
|
threadI2PAcceptIncoming =
|
||||||
std::thread(&TraceThread<std::function<void()>>, "i2paccept",
|
std::thread(&util::TraceThread, "i2paccept", [this] { ThreadI2PAcceptIncoming(); });
|
||||||
std::function<void()>(std::bind(&CConnman::ThreadI2PAcceptIncoming, this)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dump network addresses
|
// Dump network addresses
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#include <ui_interface.h>
|
#include <ui_interface.h>
|
||||||
#include <uint256.h>
|
#include <uint256.h>
|
||||||
#include <util/system.h>
|
#include <util/system.h>
|
||||||
|
#include <util/threadnames.h>
|
||||||
#include <util/translation.h>
|
#include <util/translation.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
@ -43,6 +43,8 @@
|
|||||||
#include <txdb.h>
|
#include <txdb.h>
|
||||||
#include <util/strencodings.h>
|
#include <util/strencodings.h>
|
||||||
#include <util/string.h>
|
#include <util/string.h>
|
||||||
|
#include <util/thread.h>
|
||||||
|
#include <util/threadnames.h>
|
||||||
#include <util/time.h>
|
#include <util/time.h>
|
||||||
#include <util/translation.h>
|
#include <util/translation.h>
|
||||||
#include <util/url.h>
|
#include <util/url.h>
|
||||||
@ -188,7 +190,7 @@ ChainTestingSetup::ChainTestingSetup(const std::string& chainName, const std::ve
|
|||||||
// We have to run a scheduler thread to prevent ActivateBestChain
|
// We have to run a scheduler thread to prevent ActivateBestChain
|
||||||
// from blocking due to queue overrun.
|
// from blocking due to queue overrun.
|
||||||
m_node.scheduler = std::make_unique<CScheduler>();
|
m_node.scheduler = std::make_unique<CScheduler>();
|
||||||
m_node.scheduler->m_service_thread = std::thread([&] { TraceThread("scheduler", [&] { m_node.scheduler->serviceQueue(); }); });
|
m_node.scheduler->m_service_thread = std::thread(util::TraceThread, "scheduler", [&] { m_node.scheduler->serviceQueue(); });
|
||||||
GetMainSignals().RegisterBackgroundSignalScheduler(*m_node.scheduler);
|
GetMainSignals().RegisterBackgroundSignalScheduler(*m_node.scheduler);
|
||||||
|
|
||||||
pblocktree.reset(new CBlockTreeDB(1 << 20, true));
|
pblocktree.reset(new CBlockTreeDB(1 << 20, true));
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include <util/readwritefile.h>
|
#include <util/readwritefile.h>
|
||||||
#include <util/strencodings.h>
|
#include <util/strencodings.h>
|
||||||
#include <util/system.h>
|
#include <util/system.h>
|
||||||
|
#include <util/thread.h>
|
||||||
#include <util/time.h>
|
#include <util/time.h>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -601,7 +602,7 @@ void StartTorControl(CService onion_service_target)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
torControlThread = std::thread(&TraceThread<std::function<void()>>, "torcontrol", [onion_service_target] {
|
torControlThread = std::thread(&util::TraceThread, "torcontrol", [onion_service_target] {
|
||||||
TorControlThread(onion_service_target);
|
TorControlThread(onion_service_target);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include <evo/deterministicmns.h>
|
#include <evo/deterministicmns.h>
|
||||||
#include <llmq/instantsend.h>
|
#include <llmq/instantsend.h>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee,
|
CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee,
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include <util/getuniquepath.h>
|
#include <util/getuniquepath.h>
|
||||||
#include <util/strencodings.h>
|
#include <util/strencodings.h>
|
||||||
#include <util/string.h>
|
#include <util/string.h>
|
||||||
|
#include <util/threadnames.h>
|
||||||
#include <util/translation.h>
|
#include <util/translation.h>
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
#include <sync.h>
|
#include <sync.h>
|
||||||
#include <tinyformat.h>
|
#include <tinyformat.h>
|
||||||
#include <util/settings.h>
|
#include <util/settings.h>
|
||||||
#include <util/threadnames.h>
|
|
||||||
#include <util/time.h>
|
#include <util/time.h>
|
||||||
#include <amount.h>
|
#include <amount.h>
|
||||||
|
|
||||||
@ -468,24 +467,6 @@ namespace ctpl {
|
|||||||
}
|
}
|
||||||
void RenameThreadPool(ctpl::thread_pool& tp, const char* baseName);
|
void RenameThreadPool(ctpl::thread_pool& tp, const char* baseName);
|
||||||
|
|
||||||
/**
|
|
||||||
* .. and a wrapper that just calls func once
|
|
||||||
*/
|
|
||||||
template <typename Callable> void TraceThread(const std::string name, Callable func)
|
|
||||||
{
|
|
||||||
util::ThreadRename(name.c_str());
|
|
||||||
try
|
|
||||||
{
|
|
||||||
LogPrintf("%s thread start\n", name);
|
|
||||||
func();
|
|
||||||
LogPrintf("%s thread exit\n", name);
|
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
PrintExceptionContinue(std::current_exception(), name.c_str());
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string CopyrightHolders(const std::string& strPrefix, unsigned int nStartYear, unsigned int nEndYear);
|
std::string CopyrightHolders(const std::string& strPrefix, unsigned int nStartYear, unsigned int nEndYear);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
24
src/util/thread.cpp
Normal file
24
src/util/thread.cpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// Copyright (c) 2021 The Bitcoin Core developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include <util/thread.h>
|
||||||
|
|
||||||
|
#include <logging.h>
|
||||||
|
#include <util/system.h>
|
||||||
|
#include <util/threadnames.h>
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
|
void util::TraceThread(const char* thread_name, std::function<void()> thread_func)
|
||||||
|
{
|
||||||
|
util::ThreadRename(thread_name);
|
||||||
|
try {
|
||||||
|
LogPrintf("%s thread start\n", thread_name);
|
||||||
|
thread_func();
|
||||||
|
LogPrintf("%s thread exit\n", thread_name);
|
||||||
|
} catch (...) {
|
||||||
|
PrintExceptionContinue(std::current_exception(), thread_name);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
18
src/util/thread.h
Normal file
18
src/util/thread.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// Copyright (c) 2021 The Bitcoin Core developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#ifndef BITCOIN_UTIL_THREAD_H
|
||||||
|
#define BITCOIN_UTIL_THREAD_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace util {
|
||||||
|
/**
|
||||||
|
* A wrapper for do-something-once thread functions.
|
||||||
|
*/
|
||||||
|
void TraceThread(const char* thread_name, std::function<void()> thread_func);
|
||||||
|
|
||||||
|
} // namespace util
|
||||||
|
|
||||||
|
#endif // BITCOIN_UTIL_THREAD_H
|
Loading…
Reference in New Issue
Block a user