Skip to content

Commit 2759bc7

Browse files
PastaPastaPastaknst
authored andcommitted
refactor: enhance thread safety for SML caching with mutex protection
1 parent 644d742 commit 2759bc7

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
@@ -269,6 +269,7 @@ std::vector<CDeterministicMNCPtr> CDeterministicMNList::GetProjectedMNPayees(gsl
269269

270270
gsl::not_null<std::shared_ptr<const CSimplifiedMNList>> CDeterministicMNList::to_sml() const
271271
{
272+
LOCK(m_cached_sml_mutex);
272273
if (!m_cached_sml) {
273274
std::vector<std::unique_ptr<CSimplifiedMNListEntry>> sml_entries;
274275
sml_entries.reserve(mnMap.size());
@@ -467,7 +468,10 @@ void CDeterministicMNList::AddMN(const CDeterministicMNCPtr& dmn, bool fBumpTota
467468

468469
mnMap = mnMap.set(dmn->proTxHash, dmn);
469470
mnInternalIdMap = mnInternalIdMap.set(dmn->GetInternalId(), dmn->proTxHash);
470-
m_cached_sml = nullptr;
471+
{
472+
LOCK(m_cached_sml_mutex);
473+
m_cached_sml = nullptr;
474+
}
471475
if (fBumpTotalCount) {
472476
// nTotalRegisteredCount acts more like a checkpoint, not as a limit,
473477
nTotalRegisteredCount = std::max(dmn->GetInternalId() + 1, (uint64_t)nTotalRegisteredCount);
@@ -539,8 +543,11 @@ void CDeterministicMNList::UpdateMN(const CDeterministicMN& oldDmn, const std::s
539543

540544
dmn->pdmnState = pdmnState;
541545
mnMap = mnMap.set(oldDmn.proTxHash, dmn);
542-
if (m_cached_sml && oldDmn.to_sml_entry() != dmn->to_sml_entry()) {
543-
m_cached_sml = nullptr;
546+
{
547+
LOCK(m_cached_sml_mutex);
548+
if (m_cached_sml && oldDmn.to_sml_entry() != dmn->to_sml_entry()) {
549+
m_cached_sml = nullptr;
550+
}
544551
}
545552
}
546553

@@ -613,7 +620,10 @@ void CDeterministicMNList::RemoveMN(const uint256& proTxHash)
613620

614621
mnMap = mnMap.erase(proTxHash);
615622
mnInternalIdMap = mnInternalIdMap.erase(dmn->GetInternalId());
616-
m_cached_sml = nullptr;
623+
{
624+
LOCK(m_cached_sml_mutex);
625+
m_cached_sml = nullptr;
626+
}
617627
}
618628

619629
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
@@ -153,7 +153,9 @@ class CDeterministicMNList
153153
// for multiple CDeterministicMNList until mnMap is actually changed.
154154
// Calls of AddMN, RemoveMN and (in some cases) UpdateMN reset this cache;
155155
// it happens also for indirect calls such as ApplyDiff
156-
mutable std::shared_ptr<const CSimplifiedMNList> m_cached_sml;
156+
// Thread safety: Protected by its own mutex for thread-safe access
157+
mutable Mutex m_cached_sml_mutex;
158+
mutable std::shared_ptr<const CSimplifiedMNList> m_cached_sml GUARDED_BY(m_cached_sml_mutex);
157159

158160
public:
159161
CDeterministicMNList() = default;
@@ -165,6 +167,36 @@ class CDeterministicMNList
165167
assert(nHeight >= 0);
166168
}
167169

170+
// Copy constructor
171+
CDeterministicMNList(const CDeterministicMNList& other) :
172+
blockHash(other.blockHash),
173+
nHeight(other.nHeight),
174+
nTotalRegisteredCount(other.nTotalRegisteredCount),
175+
mnMap(other.mnMap),
176+
mnInternalIdMap(other.mnInternalIdMap),
177+
mnUniquePropertyMap(other.mnUniquePropertyMap)
178+
{
179+
LOCK(other.m_cached_sml_mutex);
180+
m_cached_sml = other.m_cached_sml;
181+
}
182+
183+
// Assignment operator
184+
CDeterministicMNList& operator=(const CDeterministicMNList& other)
185+
{
186+
if (this != &other) {
187+
blockHash = other.blockHash;
188+
nHeight = other.nHeight;
189+
nTotalRegisteredCount = other.nTotalRegisteredCount;
190+
mnMap = other.mnMap;
191+
mnInternalIdMap = other.mnInternalIdMap;
192+
mnUniquePropertyMap = other.mnUniquePropertyMap;
193+
194+
LOCK2(m_cached_sml_mutex, other.m_cached_sml_mutex);
195+
m_cached_sml = other.m_cached_sml;
196+
}
197+
return *this;
198+
}
199+
168200
template <typename Stream, typename Operation>
169201
inline void SerializationOpBase(Stream& s, Operation ser_action)
170202
{
@@ -205,7 +237,10 @@ class CDeterministicMNList
205237
mnMap = MnMap();
206238
mnUniquePropertyMap = MnUniquePropertyMap();
207239
mnInternalIdMap = MnInternalIdMap();
208-
m_cached_sml = nullptr;
240+
{
241+
LOCK(m_cached_sml_mutex);
242+
m_cached_sml = nullptr;
243+
}
209244
}
210245

211246
[[nodiscard]] size_t GetAllMNsCount() const
@@ -327,6 +362,7 @@ class CDeterministicMNList
327362

328363
/**
329364
* Calculates CSimplifiedMNList for current list and cache it
365+
* Thread safety: Uses internal mutex for thread-safe cache access
330366
*/
331367
gsl::not_null<std::shared_ptr<const CSimplifiedMNList>> to_sml() const;
332368

0 commit comments

Comments
 (0)