Skip to content

Commit a922815

Browse files
refactor: enhance thread safety for SML caching with mutex protection
1 parent fc87b86 commit a922815

File tree

2 files changed

+52
-6
lines changed

2 files changed

+52
-6
lines changed

src/evo/deterministicmns.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ std::vector<CDeterministicMNCPtr> CDeterministicMNList::GetProjectedMNPayees(gsl
266266

267267
gsl::not_null<std::shared_ptr<const CSimplifiedMNList>> CDeterministicMNList::to_sml() const
268268
{
269+
LOCK(m_cached_sml_mutex);
269270
if (!m_cached_sml) {
270271
std::vector<std::unique_ptr<CSimplifiedMNListEntry>> sml_entries;
271272
sml_entries.reserve(mnMap.size());
@@ -464,7 +465,10 @@ void CDeterministicMNList::AddMN(const CDeterministicMNCPtr& dmn, bool fBumpTota
464465

465466
mnMap = mnMap.set(dmn->proTxHash, dmn);
466467
mnInternalIdMap = mnInternalIdMap.set(dmn->GetInternalId(), dmn->proTxHash);
467-
m_cached_sml = nullptr;
468+
{
469+
LOCK(m_cached_sml_mutex);
470+
m_cached_sml = nullptr;
471+
}
468472
if (fBumpTotalCount) {
469473
// nTotalRegisteredCount acts more like a checkpoint, not as a limit,
470474
nTotalRegisteredCount = std::max(dmn->GetInternalId() + 1, (uint64_t)nTotalRegisteredCount);
@@ -535,8 +539,11 @@ void CDeterministicMNList::UpdateMN(const CDeterministicMN& oldDmn, const std::s
535539

536540
dmn->pdmnState = pdmnState;
537541
mnMap = mnMap.set(oldDmn.proTxHash, dmn);
538-
if (m_cached_sml && oldDmn.to_sml_entry() != dmn->to_sml_entry()) {
539-
m_cached_sml = nullptr;
542+
{
543+
LOCK(m_cached_sml_mutex);
544+
if (m_cached_sml && oldDmn.to_sml_entry() != dmn->to_sml_entry()) {
545+
m_cached_sml = nullptr;
546+
}
540547
}
541548
}
542549

@@ -609,7 +616,10 @@ void CDeterministicMNList::RemoveMN(const uint256& proTxHash)
609616

610617
mnMap = mnMap.erase(proTxHash);
611618
mnInternalIdMap = mnInternalIdMap.erase(dmn->GetInternalId());
612-
m_cached_sml = nullptr;
619+
{
620+
LOCK(m_cached_sml_mutex);
621+
m_cached_sml = nullptr;
622+
}
613623
}
614624

615625
bool CDeterministicMNManager::ProcessBlock(const CBlock& block, gsl::not_null<const CBlockIndex*> pindex,

src/evo/deterministicmns.h

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,9 @@ class CDeterministicMNList
179179
// for multiple CDeterministicMNList until mnMap is actually changed.
180180
// Calls of AddMN, RemoveMN and (in some cases) UpdateMN reset this cache;
181181
// it happens also for indirect calls such as ApplyDiff
182-
mutable std::shared_ptr<const CSimplifiedMNList> m_cached_sml;
182+
// Thread safety: Protected by its own mutex for thread-safe access
183+
mutable Mutex m_cached_sml_mutex;
184+
mutable std::shared_ptr<const CSimplifiedMNList> m_cached_sml GUARDED_BY(m_cached_sml_mutex);
183185

184186
public:
185187
CDeterministicMNList() = default;
@@ -191,6 +193,36 @@ class CDeterministicMNList
191193
assert(nHeight >= 0);
192194
}
193195

196+
// Copy constructor
197+
CDeterministicMNList(const CDeterministicMNList& other) :
198+
blockHash(other.blockHash),
199+
nHeight(other.nHeight),
200+
nTotalRegisteredCount(other.nTotalRegisteredCount),
201+
mnMap(other.mnMap),
202+
mnInternalIdMap(other.mnInternalIdMap),
203+
mnUniquePropertyMap(other.mnUniquePropertyMap)
204+
{
205+
LOCK(other.m_cached_sml_mutex);
206+
m_cached_sml = other.m_cached_sml;
207+
}
208+
209+
// Assignment operator
210+
CDeterministicMNList& operator=(const CDeterministicMNList& other)
211+
{
212+
if (this != &other) {
213+
blockHash = other.blockHash;
214+
nHeight = other.nHeight;
215+
nTotalRegisteredCount = other.nTotalRegisteredCount;
216+
mnMap = other.mnMap;
217+
mnInternalIdMap = other.mnInternalIdMap;
218+
mnUniquePropertyMap = other.mnUniquePropertyMap;
219+
220+
LOCK2(m_cached_sml_mutex, other.m_cached_sml_mutex);
221+
m_cached_sml = other.m_cached_sml;
222+
}
223+
return *this;
224+
}
225+
194226
template <typename Stream, typename Operation>
195227
inline void SerializationOpBase(Stream& s, Operation ser_action)
196228
{
@@ -215,7 +247,10 @@ class CDeterministicMNList
215247
mnMap = MnMap();
216248
mnUniquePropertyMap = MnUniquePropertyMap();
217249
mnInternalIdMap = MnInternalIdMap();
218-
m_cached_sml = nullptr;
250+
{
251+
LOCK(m_cached_sml_mutex);
252+
m_cached_sml = nullptr;
253+
}
219254

220255
SerializationOpBase(s, CSerActionUnserialize());
221256

@@ -344,6 +379,7 @@ class CDeterministicMNList
344379

345380
/**
346381
* Calculates CSimplifiedMNList for current list and cache it
382+
* Thread safety: Uses internal mutex for thread-safe cache access
347383
*/
348384
gsl::not_null<std::shared_ptr<const CSimplifiedMNList>> to_sml() const;
349385

0 commit comments

Comments
 (0)