Skip to content

Commit 9bb1b10

Browse files
authored
refactor: improved initialization of members of LLMQContext and related changes (dashpay#5150)
LLMQContext uses RAII to initialize all members. Ensured that all members always initialized correctly in proper order if LLMQContext exists. BlockAssembler, CChainState use too many agruments and they are making wrong assumption that members of LLMQContext can be constructed and used independently, but that's not true. Instead, let's pass LLMQContext whenever possible. ## Issue being fixed or feature implemented dashpay/dash-issues#52 ## How Has This Been Tested? Run unit/functional test and introduce no breaking changes. ## Checklist: - [x] I have performed a self-review of my own code - [x] I have made corresponding changes to the documentation - [x] I have assigned this pull request to a milestone
1 parent 5c9896e commit 9bb1b10

13 files changed

+110
-129
lines changed

src/llmq/context.cpp

Lines changed: 59 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -20,108 +20,85 @@
2020
#include <masternode/sync.h>
2121

2222
LLMQContext::LLMQContext(CEvoDB& evo_db, CTxMemPool& mempool, CConnman& connman, CSporkManager& sporkman,
23-
const std::unique_ptr<PeerManager>& peerman, bool unit_tests, bool wipe) {
24-
Create(evo_db, mempool, connman, sporkman, peerman, unit_tests, wipe);
25-
26-
/* Context aliases to globals used by the LLMQ system */
27-
quorum_block_processor = llmq::quorumBlockProcessor.get();
28-
qman = llmq::quorumManager.get();
29-
clhandler = llmq::chainLocksHandler.get();
30-
isman = llmq::quorumInstantSendManager.get();
31-
}
32-
33-
LLMQContext::~LLMQContext() {
34-
isman = nullptr;
35-
clhandler = nullptr;
36-
qman = nullptr;
37-
quorum_block_processor = nullptr;
38-
39-
Destroy();
40-
}
41-
42-
void LLMQContext::Create(CEvoDB& evo_db, CTxMemPool& mempool, CConnman& connman, CSporkManager& sporkman,
43-
const std::unique_ptr<PeerManager>& peerman, bool unit_tests, bool wipe) {
44-
bls_worker = std::make_shared<CBLSWorker>();
45-
46-
dkg_debugman = std::make_unique<llmq::CDKGDebugManager>();
47-
llmq::quorumBlockProcessor = std::make_unique<llmq::CQuorumBlockProcessor>(evo_db, connman, peerman);
48-
qdkgsman = std::make_unique<llmq::CDKGSessionManager>(connman, *bls_worker, *dkg_debugman, *llmq::quorumBlockProcessor, sporkman, peerman, unit_tests, wipe);
49-
llmq::quorumManager = std::make_unique<llmq::CQuorumManager>(evo_db, connman, *bls_worker, *llmq::quorumBlockProcessor, *qdkgsman, ::masternodeSync, peerman);
50-
sigman = std::make_unique<llmq::CSigningManager>(connman, *llmq::quorumManager, peerman, unit_tests, wipe);
51-
shareman = std::make_unique<llmq::CSigSharesManager>(connman, *llmq::quorumManager, *sigman, peerman);
52-
llmq::chainLocksHandler = std::make_unique<llmq::CChainLocksHandler>(mempool, connman, sporkman, *sigman, *shareman, *llmq::quorumManager, *::masternodeSync, peerman);
53-
llmq::quorumInstantSendManager = std::make_unique<llmq::CInstantSendManager>(mempool, connman, sporkman, *llmq::quorumManager, *sigman, *shareman, *llmq::chainLocksHandler, *::masternodeSync, peerman, unit_tests, wipe);
54-
23+
const std::unique_ptr<PeerManager>& peerman, bool unit_tests, bool wipe) :
24+
bls_worker{std::make_shared<CBLSWorker>()},
25+
dkg_debugman{std::make_unique<llmq::CDKGDebugManager>()},
26+
quorum_block_processor{[&]() -> llmq::CQuorumBlockProcessor* const {
27+
assert(llmq::quorumBlockProcessor == nullptr);
28+
llmq::quorumBlockProcessor = std::make_unique<llmq::CQuorumBlockProcessor>(evo_db, connman, peerman);
29+
return llmq::quorumBlockProcessor.get();
30+
}()},
31+
qdkgsman{std::make_unique<llmq::CDKGSessionManager>(connman, *bls_worker, *dkg_debugman, *quorum_block_processor, sporkman, peerman, unit_tests, wipe)},
32+
qman{[&]() -> llmq::CQuorumManager* const {
33+
assert(llmq::quorumManager == nullptr);
34+
llmq::quorumManager = std::make_unique<llmq::CQuorumManager>(evo_db, connman, *bls_worker, *quorum_block_processor, *qdkgsman, ::masternodeSync, peerman);
35+
return llmq::quorumManager.get();
36+
}()},
37+
sigman{std::make_unique<llmq::CSigningManager>(connman, *llmq::quorumManager, peerman, unit_tests, wipe)},
38+
shareman{std::make_unique<llmq::CSigSharesManager>(connman, *llmq::quorumManager, *sigman, peerman)},
39+
clhandler{[&]() -> llmq::CChainLocksHandler* const {
40+
assert(llmq::chainLocksHandler == nullptr);
41+
llmq::chainLocksHandler = std::make_unique<llmq::CChainLocksHandler>(mempool, connman, sporkman, *sigman, *shareman, *llmq::quorumManager, *::masternodeSync, peerman);
42+
return llmq::chainLocksHandler.get();
43+
}()},
44+
isman{[&]() -> llmq::CInstantSendManager* const {
45+
assert(llmq::quorumInstantSendManager == nullptr);
46+
llmq::quorumInstantSendManager = std::make_unique<llmq::CInstantSendManager>(mempool, connman, sporkman, *llmq::quorumManager, *sigman, *shareman, *llmq::chainLocksHandler, *::masternodeSync, peerman, unit_tests, wipe);
47+
return llmq::quorumInstantSendManager.get();
48+
}()}
49+
{
5550
// NOTE: we use this only to wipe the old db, do NOT use it for anything else
5651
// TODO: remove it in some future version
5752
auto llmqDbTmp = std::make_unique<CDBWrapper>(unit_tests ? "" : (GetDataDir() / "llmq"), 1 << 20, unit_tests, true);
5853
}
5954

60-
void LLMQContext::Destroy() {
55+
LLMQContext::~LLMQContext() {
56+
// LLMQContext doesn't own these objects, but still need to care of them for consistancy:
6157
llmq::quorumInstantSendManager.reset();
6258
llmq::chainLocksHandler.reset();
63-
shareman.reset();
64-
sigman.reset();
6559
llmq::quorumManager.reset();
66-
qdkgsman.reset();
6760
llmq::quorumBlockProcessor.reset();
68-
dkg_debugman.reset();
69-
bls_worker.reset();
7061
{
7162
LOCK(llmq::cs_llmq_vbc);
7263
llmq::llmq_versionbitscache.Clear();
7364
}
7465
}
7566

7667
void LLMQContext::Interrupt() {
77-
if (shareman != nullptr) {
78-
shareman->InterruptWorkerThread();
79-
}
80-
if (llmq::quorumInstantSendManager != nullptr) {
81-
llmq::quorumInstantSendManager->InterruptWorkerThread();
82-
}
68+
shareman->InterruptWorkerThread();
69+
70+
assert(isman == llmq::quorumInstantSendManager.get());
71+
llmq::quorumInstantSendManager->InterruptWorkerThread();
8372
}
8473

8574
void LLMQContext::Start() {
86-
if (bls_worker != nullptr) {
87-
bls_worker->Start();
88-
}
89-
if (qdkgsman != nullptr) {
90-
qdkgsman->StartThreads();
91-
}
92-
if (llmq::quorumManager != nullptr) {
93-
llmq::quorumManager->Start();
94-
}
95-
if (shareman != nullptr) {
96-
shareman->RegisterAsRecoveredSigsListener();
97-
shareman->StartWorkerThread();
98-
}
99-
if (llmq::chainLocksHandler != nullptr) {
100-
llmq::chainLocksHandler->Start();
101-
}
102-
if (llmq::quorumInstantSendManager != nullptr) {
103-
llmq::quorumInstantSendManager->Start();
104-
}
75+
assert(quorum_block_processor == llmq::quorumBlockProcessor.get());
76+
assert(qman == llmq::quorumManager.get());
77+
assert(clhandler == llmq::chainLocksHandler.get());
78+
assert(isman == llmq::quorumInstantSendManager.get());
79+
80+
bls_worker->Start();
81+
qdkgsman->StartThreads();
82+
qman->Start();
83+
shareman->RegisterAsRecoveredSigsListener();
84+
shareman->StartWorkerThread();
85+
86+
llmq::chainLocksHandler->Start();
87+
llmq::quorumInstantSendManager->Start();
10588
}
10689

10790
void LLMQContext::Stop() {
108-
if (llmq::quorumInstantSendManager != nullptr) {
109-
llmq::quorumInstantSendManager->Stop();
110-
}
111-
if (llmq::chainLocksHandler != nullptr) {
112-
llmq::chainLocksHandler->Stop();
113-
}
114-
if (shareman != nullptr) {
115-
shareman->StopWorkerThread();
116-
shareman->UnregisterAsRecoveredSigsListener();
117-
}
118-
if (llmq::quorumManager != nullptr) {
119-
llmq::quorumManager->Stop();
120-
}
121-
if (qdkgsman != nullptr) {
122-
qdkgsman->StopThreads();
123-
}
124-
if (bls_worker != nullptr) {
125-
bls_worker->Stop();
126-
}
91+
assert(quorum_block_processor == llmq::quorumBlockProcessor.get());
92+
assert(qman == llmq::quorumManager.get());
93+
assert(clhandler == llmq::chainLocksHandler.get());
94+
assert(isman == llmq::quorumInstantSendManager.get());
95+
96+
llmq::quorumInstantSendManager->Stop();
97+
llmq::chainLocksHandler->Stop();
98+
99+
shareman->StopWorkerThread();
100+
shareman->UnregisterAsRecoveredSigsListener();
101+
qman->Stop();
102+
qdkgsman->StopThreads();
103+
bls_worker->Stop();
127104
}

src/llmq/context.h

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,27 +27,35 @@ class CInstantSendManager;
2727
}
2828

2929
struct LLMQContext {
30+
LLMQContext() = delete;
31+
LLMQContext(const LLMQContext&) = delete;
3032
LLMQContext(CEvoDB& evo_db, CTxMemPool& mempool, CConnman& connman, CSporkManager& sporkman,
3133
const std::unique_ptr<PeerManager>& peerman, bool unit_tests, bool wipe);
3234
~LLMQContext();
3335

34-
void Create(CEvoDB& evo_db, CTxMemPool& mempool, CConnman& connman, CSporkManager& sporkman,
35-
const std::unique_ptr<PeerManager>& peerman, bool unit_tests, bool wipe);
36-
void Destroy();
3736
void Interrupt();
3837
void Start();
3938
void Stop();
4039

41-
std::shared_ptr<CBLSWorker> bls_worker;
42-
std::unique_ptr<llmq::CDKGDebugManager> dkg_debugman;
43-
std::unique_ptr<llmq::CDKGSessionManager> qdkgsman;
44-
std::unique_ptr<llmq::CSigSharesManager> shareman;
45-
std::unique_ptr<llmq::CSigningManager> sigman;
46-
47-
llmq::CQuorumBlockProcessor* quorum_block_processor{nullptr};
48-
llmq::CQuorumManager* qman{nullptr};
49-
llmq::CChainLocksHandler* clhandler{nullptr};
50-
llmq::CInstantSendManager* isman{nullptr};
40+
/** Guaranteed if LLMQContext is initialized then all members are valid too
41+
*
42+
* Please note, that members here should not be re-ordered, because initialization
43+
* some of them requires other member initialized.
44+
* For example, constructor `quorumManager` requires `bls_worker`.
45+
*
46+
* Some objects are still global variables and their de-globalization is not trivial
47+
* at this point. LLMQContext keeps just a pointer to them and doesn't own these objects,
48+
* but it still guarantees that objects are created and valid
49+
*/
50+
const std::shared_ptr<CBLSWorker> bls_worker;
51+
const std::unique_ptr<llmq::CDKGDebugManager> dkg_debugman;
52+
llmq::CQuorumBlockProcessor* const quorum_block_processor;
53+
const std::unique_ptr<llmq::CDKGSessionManager> qdkgsman;
54+
llmq::CQuorumManager* const qman;
55+
const std::unique_ptr<llmq::CSigningManager> sigman;
56+
const std::unique_ptr<llmq::CSigSharesManager> shareman;
57+
llmq::CChainLocksHandler* const clhandler;
58+
llmq::CInstantSendManager* const isman;
5159
};
5260

5361
#endif // BITCOIN_LLMQ_CONTEXT_H

src/miner.cpp

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <governance/governance.h>
2929
#include <llmq/blockprocessor.h>
3030
#include <llmq/chainlocks.h>
31+
#include <llmq/context.h>
3132
#include <llmq/instantsend.h>
3233
#include <llmq/utils.h>
3334
#include <masternode/payments.h>
@@ -57,16 +58,15 @@ BlockAssembler::Options::Options() {
5758
}
5859

5960
BlockAssembler::BlockAssembler(const CSporkManager& sporkManager, CGovernanceManager& governanceManager,
60-
const llmq::CQuorumBlockProcessor& quorumBlockProcessor, llmq::CChainLocksHandler& clhandler,
61-
llmq::CInstantSendManager& isman, CEvoDB& evoDb, CChainState& chainstate, const CTxMemPool& mempool, const CChainParams& params, const Options& options) :
61+
LLMQContext& llmq_ctx, CEvoDB& evoDb, CChainState& chainstate, const CTxMemPool& mempool, const CChainParams& params, const Options& options) :
6262
chainparams(params),
6363
m_mempool(mempool),
6464
m_chainstate(chainstate),
6565
spork_manager(sporkManager),
6666
governance_manager(governanceManager),
67-
quorum_block_processor(quorumBlockProcessor),
68-
m_clhandler(clhandler),
69-
m_isman(isman),
67+
quorum_block_processor(*llmq_ctx.quorum_block_processor),
68+
m_clhandler(*llmq_ctx.clhandler),
69+
m_isman(*llmq_ctx.isman),
7070
m_evoDb(evoDb)
7171
{
7272
blockMinFeeRate = options.blockMinFeeRate;
@@ -92,9 +92,8 @@ static BlockAssembler::Options DefaultOptions()
9292
}
9393

9494
BlockAssembler::BlockAssembler(const CSporkManager& sporkManager, CGovernanceManager& governanceManager,
95-
const llmq::CQuorumBlockProcessor& quorumBlockProcessor, llmq::CChainLocksHandler& clhandler,
96-
llmq::CInstantSendManager& isman, CEvoDB& evoDb, CChainState& chainstate, const CTxMemPool& mempool, const CChainParams& params)
97-
: BlockAssembler(sporkManager, governanceManager, quorumBlockProcessor, clhandler, isman, evoDb, chainstate, mempool, params, DefaultOptions()) {}
95+
LLMQContext& llmq_ctx, CEvoDB& evoDb, CChainState& chainstate, const CTxMemPool& mempool, const CChainParams& params)
96+
: BlockAssembler(sporkManager, governanceManager, llmq_ctx, evoDb, chainstate, mempool, params, DefaultOptions()) {}
9897

9998
void BlockAssembler::resetBlock()
10099
{

src/miner.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class CCreditPoolDiff;
2424
class CGovernanceManager;
2525
class CScript;
2626
class CSporkManager;
27+
struct LLMQContext;
2728

2829
namespace Consensus { struct Params; };
2930
namespace llmq {
@@ -172,11 +173,9 @@ class BlockAssembler
172173
};
173174

174175
explicit BlockAssembler(const CSporkManager& sporkManager, CGovernanceManager& governanceManager,
175-
const llmq::CQuorumBlockProcessor& quorumBlockProcessor, llmq::CChainLocksHandler& clhandler,
176-
llmq::CInstantSendManager& isman, CEvoDB& evoDb, CChainState& chainstate, const CTxMemPool& mempool, const CChainParams& params);
176+
LLMQContext& llmq_ctx, CEvoDB& evoDb, CChainState& chainstate, const CTxMemPool& mempool, const CChainParams& params);
177177
explicit BlockAssembler(const CSporkManager& sporkManager, CGovernanceManager& governanceManager,
178-
const llmq::CQuorumBlockProcessor& quorumBlockProcessor, llmq::CChainLocksHandler& clhandler,
179-
llmq::CInstantSendManager& isman, CEvoDB& evoDb, CChainState& chainstate, const CTxMemPool& mempool, const CChainParams& params, const Options& options);
178+
LLMQContext& llmq_ctx, CEvoDB& evoDb, CChainState& chainstate, const CTxMemPool& mempool, const CChainParams& params, const Options& options);
180179

181180
/** Construct a new block template with coinbase to scriptPubKeyIn */
182181
std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn);

src/rpc/evo.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1471,7 +1471,7 @@ static UniValue protx_diff(const JSONRPCRequest& request, const ChainstateManage
14711471

14721472
CSimplifiedMNListDiff mnListDiff;
14731473
std::string strError;
1474-
LLMQContext& llmq_ctx = EnsureAnyLLMQContext(request.context);
1474+
const LLMQContext& llmq_ctx = EnsureAnyLLMQContext(request.context);
14751475

14761476
if (!BuildSimplifiedMNListDiff(baseBlockHash, blockHash, mnListDiff, *llmq_ctx.quorum_block_processor, strError, extended)) {
14771477
throw std::runtime_error(strError);

src/rpc/mining.cpp

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,7 @@ static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t&
149149
}
150150

151151
static UniValue generateBlocks(ChainstateManager& chainman, const CTxMemPool& mempool, CEvoDB& evodb,
152-
llmq::CQuorumBlockProcessor& quorum_block_processor, llmq::CChainLocksHandler& clhandler,
153-
llmq::CInstantSendManager& isman, const CScript& coinbase_script, int nGenerate, uint64_t nMaxTries)
152+
LLMQContext& llmq_ctx, const CScript& coinbase_script, int nGenerate, uint64_t nMaxTries)
154153
{
155154
int nHeightEnd = 0;
156155
int nHeight = 0;
@@ -165,7 +164,7 @@ static UniValue generateBlocks(ChainstateManager& chainman, const CTxMemPool& me
165164
UniValue blockHashes(UniValue::VARR);
166165
while (nHeight < nHeightEnd && !ShutdownRequested())
167166
{
168-
std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler(*sporkManager, *governance, quorum_block_processor, clhandler, isman, evodb, chainman.ActiveChainstate(), mempool, Params()).CreateNewBlock(coinbase_script));
167+
std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler(*sporkManager, *governance, llmq_ctx, evodb, chainman.ActiveChainstate(), mempool, Params()).CreateNewBlock(coinbase_script));
169168
if (!pblocktemplate.get())
170169
throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
171170
CBlock *pblock = &pblocktemplate->block;
@@ -252,7 +251,7 @@ static UniValue generatetodescriptor(const JSONRPCRequest& request)
252251
ChainstateManager& chainman = EnsureChainman(node);
253252
LLMQContext& llmq_ctx = EnsureLLMQContext(node);
254253

255-
return generateBlocks(chainman, mempool, *node.evodb, *llmq_ctx.quorum_block_processor, *llmq_ctx.clhandler, *llmq_ctx.isman, coinbase_script, num_blocks, max_tries);
254+
return generateBlocks(chainman, mempool, *node.evodb, llmq_ctx, coinbase_script, num_blocks, max_tries);
256255
}
257256

258257
static UniValue generatetoaddress(const JSONRPCRequest& request)
@@ -291,7 +290,7 @@ static UniValue generatetoaddress(const JSONRPCRequest& request)
291290

292291
CScript coinbase_script = GetScriptForDestination(destination);
293292

294-
return generateBlocks(chainman, mempool, *node.evodb, *llmq_ctx.quorum_block_processor, *llmq_ctx.clhandler, *llmq_ctx.isman, coinbase_script, num_blocks, max_tries);
293+
return generateBlocks(chainman, mempool, *node.evodb, llmq_ctx, coinbase_script, num_blocks, max_tries);
295294
}
296295

297296
static UniValue generateblock(const JSONRPCRequest& request)
@@ -371,7 +370,7 @@ static UniValue generateblock(const JSONRPCRequest& request)
371370
LOCK(cs_main);
372371

373372
CTxMemPool empty_mempool;
374-
std::unique_ptr<CBlockTemplate> blocktemplate(BlockAssembler(*sporkManager, *governance, *llmq_ctx.quorum_block_processor, *llmq_ctx.clhandler, *llmq_ctx.isman, *node.evodb, active_chainstate, empty_mempool, chainparams).CreateNewBlock(coinbase_script));
373+
std::unique_ptr<CBlockTemplate> blocktemplate(BlockAssembler(*sporkManager, *governance, llmq_ctx, *node.evodb, active_chainstate, empty_mempool, chainparams).CreateNewBlock(coinbase_script));
375374
if (!blocktemplate) {
376375
throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
377376
}
@@ -787,7 +786,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
787786
// Create new block
788787
CScript scriptDummy = CScript() << OP_TRUE;
789788
LLMQContext& llmq_ctx = EnsureAnyLLMQContext(request.context);
790-
pblocktemplate = BlockAssembler(*sporkManager, *governance, *llmq_ctx.quorum_block_processor, *llmq_ctx.clhandler, *llmq_ctx.isman, *node.evodb, active_chainstate, mempool, Params()).CreateNewBlock(scriptDummy);
789+
pblocktemplate = BlockAssembler(*sporkManager, *governance, llmq_ctx, *node.evodb, active_chainstate, mempool, Params()).CreateNewBlock(scriptDummy);
791790
if (!pblocktemplate)
792791
throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory");
793792

0 commit comments

Comments
 (0)