Skip to content

Commit 8648566

Browse files
codablockUdjinM6
authored andcommitted
Multiple speed optimizations for deterministic MN list handling (#2972)
* Generalize CBLSLazyWrapper so that it can be used of pubkeys and secret keys * Implement == and != operators for CBLSLazyWrapper * Implement cached hash for CBLSLazyWrapper * Use CBLSLazyPublicKey for CDeterministicMNState::pubKeyOperator * Speed up GetProjectedMNPayees by sorting the MN list by last paid Instead of updating a temporary list for each projected height and calling GetMNPayee() on it. * Cache intermediate lists in GetListForBlock This avoids re-loading and applying diffs again and again. * Only update masternode list UI max once every 3 seconds This avoids updating the UI on every block, which turned out to be very expensive. * Fix compilation * Drop time restrictions for mn list update in ClientModel They are fully handled by MasternodeList now.
1 parent d8df05b commit 8648566

28 files changed

+197
-137
lines changed

src/bls/bls.cpp

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -424,33 +424,6 @@ bool CBLSSignature::Recover(const std::vector<CBLSSignature>& sigs, const std::v
424424
}
425425

426426
#ifndef BUILD_BITCOIN_INTERNAL
427-
void CBLSLazySignature::SetSig(const CBLSSignature& _sig)
428-
{
429-
std::unique_lock<std::mutex> l(mutex);
430-
bufValid = false;
431-
sigInitialized = true;
432-
sig = _sig;
433-
}
434-
435-
const CBLSSignature& CBLSLazySignature::GetSig() const
436-
{
437-
std::unique_lock<std::mutex> l(mutex);
438-
static CBLSSignature invalidSig;
439-
if (!bufValid && !sigInitialized) {
440-
return invalidSig;
441-
}
442-
if (!sigInitialized) {
443-
sig.SetBuf(buf, sizeof(buf));
444-
if (!sig.CheckMalleable(buf, sizeof(buf))) {
445-
bufValid = false;
446-
sigInitialized = false;
447-
sig = invalidSig;
448-
} else {
449-
sigInitialized = true;
450-
}
451-
}
452-
return sig;
453-
}
454427

455428
static std::once_flag init_flag;
456429
static mt_pooled_secure_allocator<uint8_t>* secure_allocator_instance;

src/bls/bls.h

Lines changed: 90 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -310,29 +310,34 @@ class CBLSSignature : public CBLSWrapper<bls::InsecureSignature, BLS_CURVE_SIG_S
310310
};
311311

312312
#ifndef BUILD_BITCOIN_INTERNAL
313-
class CBLSLazySignature
313+
template<typename BLSObject>
314+
class CBLSLazyWrapper
314315
{
315316
private:
316317
mutable std::mutex mutex;
317318

318-
mutable char buf[BLS_CURVE_SIG_SIZE];
319+
mutable char buf[BLSObject::SerSize];
319320
mutable bool bufValid{false};
320321

321-
mutable CBLSSignature sig;
322-
mutable bool sigInitialized{false};
322+
mutable BLSObject obj;
323+
mutable bool objInitialized{false};
324+
325+
mutable uint256 hash;
323326

324327
public:
325-
CBLSLazySignature()
328+
CBLSLazyWrapper()
326329
{
327330
memset(buf, 0, sizeof(buf));
331+
// the all-zero buf is considered a valid buf, but the resulting object will return false for IsValid
332+
bufValid = true;
328333
}
329334

330-
CBLSLazySignature(const CBLSLazySignature& r)
335+
CBLSLazyWrapper(const CBLSLazyWrapper& r)
331336
{
332337
*this = r;
333338
}
334339

335-
CBLSLazySignature& operator=(const CBLSLazySignature& r)
340+
CBLSLazyWrapper& operator=(const CBLSLazyWrapper& r)
336341
{
337342
std::unique_lock<std::mutex> l(r.mutex);
338343
bufValid = r.bufValid;
@@ -341,25 +346,27 @@ class CBLSLazySignature
341346
} else {
342347
memset(buf, 0, sizeof(buf));
343348
}
344-
sigInitialized = r.sigInitialized;
345-
if (r.sigInitialized) {
346-
sig = r.sig;
349+
objInitialized = r.objInitialized;
350+
if (r.objInitialized) {
351+
obj = r.obj;
347352
} else {
348-
sig.Reset();
353+
obj.Reset();
349354
}
355+
hash = r.hash;
350356
return *this;
351357
}
352358

353359
template<typename Stream>
354360
inline void Serialize(Stream& s) const
355361
{
356362
std::unique_lock<std::mutex> l(mutex);
357-
if (!sigInitialized && !bufValid) {
358-
throw std::ios_base::failure("sig and buf not initialized");
363+
if (!objInitialized && !bufValid) {
364+
throw std::ios_base::failure("obj and buf not initialized");
359365
}
360366
if (!bufValid) {
361-
sig.GetBuf(buf, sizeof(buf));
367+
obj.GetBuf(buf, sizeof(buf));
362368
bufValid = true;
369+
hash = uint256();
363370
}
364371
s.write(buf, sizeof(buf));
365372
}
@@ -370,12 +377,78 @@ class CBLSLazySignature
370377
std::unique_lock<std::mutex> l(mutex);
371378
s.read(buf, sizeof(buf));
372379
bufValid = true;
373-
sigInitialized = false;
380+
objInitialized = false;
381+
hash = uint256();
382+
}
383+
384+
void Set(const BLSObject& _obj)
385+
{
386+
std::unique_lock<std::mutex> l(mutex);
387+
bufValid = false;
388+
objInitialized = true;
389+
obj = _obj;
390+
hash = uint256();
391+
}
392+
const BLSObject& Get() const
393+
{
394+
std::unique_lock<std::mutex> l(mutex);
395+
static BLSObject invalidObj;
396+
if (!bufValid && !objInitialized) {
397+
return invalidObj;
398+
}
399+
if (!objInitialized) {
400+
obj.SetBuf(buf, sizeof(buf));
401+
if (!obj.CheckMalleable(buf, sizeof(buf))) {
402+
bufValid = false;
403+
objInitialized = false;
404+
obj = invalidObj;
405+
} else {
406+
objInitialized = true;
407+
}
408+
}
409+
return obj;
374410
}
375411

376-
void SetSig(const CBLSSignature& _sig);
377-
const CBLSSignature& GetSig() const;
412+
bool operator==(const CBLSLazyWrapper& r) const
413+
{
414+
if (bufValid && r.bufValid) {
415+
return memcmp(buf, r.buf, sizeof(buf)) == 0;
416+
}
417+
if (objInitialized && r.objInitialized) {
418+
return obj == r.obj;
419+
}
420+
return Get() == r.Get();
421+
}
422+
423+
bool operator!=(const CBLSLazyWrapper& r) const
424+
{
425+
return !(*this == r);
426+
}
427+
428+
uint256 GetHash() const
429+
{
430+
std::unique_lock<std::mutex> l(mutex);
431+
if (!bufValid) {
432+
obj.GetBuf(buf, sizeof(buf));
433+
bufValid = true;
434+
hash = uint256();
435+
}
436+
if (hash.IsNull()) {
437+
UpdateHash();
438+
}
439+
return hash;
440+
}
441+
private:
442+
void UpdateHash() const
443+
{
444+
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
445+
ss.write(buf, sizeof(buf));
446+
hash = ss.GetHash();
447+
}
378448
};
449+
typedef CBLSLazyWrapper<CBLSSignature> CBLSLazySignature;
450+
typedef CBLSLazyWrapper<CBLSPublicKey> CBLSLazyPublicKey;
451+
typedef CBLSLazyWrapper<CBLSSecretKey> CBLSLazySecretKey;
379452
#endif
380453

381454
typedef std::vector<CBLSId> BLSIdVector;

src/evo/deterministicmns.cpp

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ std::string CDeterministicMNState::ToString() const
3838
return strprintf("CDeterministicMNState(nRegisteredHeight=%d, nLastPaidHeight=%d, nPoSePenalty=%d, nPoSeRevivedHeight=%d, nPoSeBanHeight=%d, nRevocationReason=%d, "
3939
"ownerAddress=%s, pubKeyOperator=%s, votingAddress=%s, addr=%s, payoutAddress=%s, operatorPayoutAddress=%s)",
4040
nRegisteredHeight, nLastPaidHeight, nPoSePenalty, nPoSeRevivedHeight, nPoSeBanHeight, nRevocationReason,
41-
CBitcoinAddress(keyIDOwner).ToString(), pubKeyOperator.ToString(), CBitcoinAddress(keyIDVoting).ToString(), addr.ToStringIPPort(false), payoutAddress, operatorPayoutAddress);
41+
CBitcoinAddress(keyIDOwner).ToString(), pubKeyOperator.Get().ToString(), CBitcoinAddress(keyIDVoting).ToString(), addr.ToStringIPPort(false), payoutAddress, operatorPayoutAddress);
4242
}
4343

4444
void CDeterministicMNState::ToJson(UniValue& obj) const
@@ -60,7 +60,7 @@ void CDeterministicMNState::ToJson(UniValue& obj) const
6060
CBitcoinAddress payoutAddress(dest);
6161
obj.push_back(Pair("payoutAddress", payoutAddress.ToString()));
6262
}
63-
obj.push_back(Pair("pubKeyOperator", pubKeyOperator.ToString()));
63+
obj.push_back(Pair("pubKeyOperator", pubKeyOperator.Get().ToString()));
6464
if (ExtractDestination(scriptOperatorPayout, dest)) {
6565
CBitcoinAddress operatorPayoutAddress(dest);
6666
obj.push_back(Pair("operatorPayoutAddress", operatorPayoutAddress.ToString()));
@@ -147,7 +147,7 @@ CDeterministicMNCPtr CDeterministicMNList::GetValidMN(const uint256& proTxHash)
147147
CDeterministicMNCPtr CDeterministicMNList::GetMNByOperatorKey(const CBLSPublicKey& pubKey)
148148
{
149149
for (const auto& p : mnMap) {
150-
if (p.second->pdmnState->pubKeyOperator == pubKey) {
150+
if (p.second->pdmnState->pubKeyOperator.Get() == pubKey) {
151151
return p.second;
152152
}
153153
}
@@ -217,21 +217,21 @@ CDeterministicMNCPtr CDeterministicMNList::GetMNPayee() const
217217

218218
std::vector<CDeterministicMNCPtr> CDeterministicMNList::GetProjectedMNPayees(int nCount) const
219219
{
220+
if (nCount > GetValidMNsCount()) {
221+
nCount = GetValidMNsCount();
222+
}
223+
220224
std::vector<CDeterministicMNCPtr> result;
221225
result.reserve(nCount);
222226

223-
CDeterministicMNList tmpMNList = *this;
224-
for (int h = nHeight; h < nHeight + nCount; h++) {
225-
tmpMNList.SetHeight(h);
226-
227-
CDeterministicMNCPtr payee = tmpMNList.GetMNPayee();
228-
// push the original MN object instead of the one from the temporary list
229-
result.push_back(GetMN(payee->proTxHash));
227+
ForEachMN(true, [&](const CDeterministicMNCPtr& dmn) {
228+
result.emplace_back(dmn);
229+
});
230+
std::sort(result.begin(), result.end(), [&](const CDeterministicMNCPtr& a, const CDeterministicMNCPtr& b) {
231+
return CompareByLastPaid(a, b);
232+
});
230233

231-
CDeterministicMNStatePtr newState = std::make_shared<CDeterministicMNState>(*payee->pdmnState);
232-
newState->nLastPaidHeight = h;
233-
tmpMNList.UpdateMN(payee->proTxHash, newState);
234-
}
234+
result.resize(nCount);
235235

236236
return result;
237237
}
@@ -420,7 +420,7 @@ void CDeterministicMNList::AddMN(const CDeterministicMNCPtr& dmn)
420420
AddUniqueProperty(dmn, dmn->pdmnState->addr);
421421
}
422422
AddUniqueProperty(dmn, dmn->pdmnState->keyIDOwner);
423-
if (dmn->pdmnState->pubKeyOperator.IsValid()) {
423+
if (dmn->pdmnState->pubKeyOperator.Get().IsValid()) {
424424
AddUniqueProperty(dmn, dmn->pdmnState->pubKeyOperator);
425425
}
426426
}
@@ -448,7 +448,7 @@ void CDeterministicMNList::RemoveMN(const uint256& proTxHash)
448448
DeleteUniqueProperty(dmn, dmn->pdmnState->addr);
449449
}
450450
DeleteUniqueProperty(dmn, dmn->pdmnState->keyIDOwner);
451-
if (dmn->pdmnState->pubKeyOperator.IsValid()) {
451+
if (dmn->pdmnState->pubKeyOperator.Get().IsValid()) {
452452
DeleteUniqueProperty(dmn, dmn->pdmnState->pubKeyOperator);
453453
}
454454
mnMap = mnMap.erase(proTxHash);
@@ -692,7 +692,7 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
692692

693693
if (newState->nPoSeBanHeight != -1) {
694694
// only revive when all keys are set
695-
if (newState->pubKeyOperator.IsValid() && !newState->keyIDVoting.IsNull() && !newState->keyIDOwner.IsNull()) {
695+
if (newState->pubKeyOperator.Get().IsValid() && !newState->keyIDVoting.IsNull() && !newState->keyIDOwner.IsNull()) {
696696
newState->nPoSePenalty = 0;
697697
newState->nPoSeBanHeight = -1;
698698
newState->nPoSeRevivedHeight = nHeight;
@@ -720,12 +720,12 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
720720
return _state.DoS(100, false, REJECT_INVALID, "bad-protx-hash");
721721
}
722722
auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
723-
if (newState->pubKeyOperator != proTx.pubKeyOperator) {
723+
if (newState->pubKeyOperator.Get() != proTx.pubKeyOperator) {
724724
// reset all operator related fields and put MN into PoSe-banned state in case the operator key changes
725725
newState->ResetOperatorFields();
726726
newState->BanIfNotBanned(nHeight);
727727
}
728-
newState->pubKeyOperator = proTx.pubKeyOperator;
728+
newState->pubKeyOperator.Set(proTx.pubKeyOperator);
729729
newState->keyIDVoting = proTx.keyIDVoting;
730730
newState->scriptPayout = proTx.scriptPayout;
731731

@@ -857,12 +857,14 @@ CDeterministicMNList CDeterministicMNManager::GetListForBlock(const uint256& blo
857857
}
858858

859859
if (evoDb.Read(std::make_pair(DB_LIST_SNAPSHOT, blockHashTmp), snapshot)) {
860+
mnListsCache.emplace(blockHashTmp, snapshot);
860861
break;
861862
}
862863

863864
CDeterministicMNListDiff diff;
864865
if (!evoDb.Read(std::make_pair(DB_LIST_DIFF, blockHashTmp), diff)) {
865866
snapshot = CDeterministicMNList(blockHashTmp, -1);
867+
mnListsCache.emplace(blockHashTmp, snapshot);
866868
break;
867869
}
868870

@@ -877,9 +879,10 @@ CDeterministicMNList CDeterministicMNManager::GetListForBlock(const uint256& blo
877879
snapshot.SetBlockHash(diff.blockHash);
878880
snapshot.SetHeight(diff.nHeight);
879881
}
882+
883+
mnListsCache.emplace(diff.blockHash, snapshot);
880884
}
881885

882-
mnListsCache.emplace(blockHash, snapshot);
883886
return snapshot;
884887
}
885888

src/evo/deterministicmns.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class CDeterministicMNState
4444
uint256 confirmedHashWithProRegTxHash;
4545

4646
CKeyID keyIDOwner;
47-
CBLSPublicKey pubKeyOperator;
47+
CBLSLazyPublicKey pubKeyOperator;
4848
CKeyID keyIDVoting;
4949
CService addr;
5050
CScript scriptPayout;
@@ -55,7 +55,7 @@ class CDeterministicMNState
5555
CDeterministicMNState(const CProRegTx& proTx)
5656
{
5757
keyIDOwner = proTx.keyIDOwner;
58-
pubKeyOperator = proTx.pubKeyOperator;
58+
pubKeyOperator.Set(proTx.pubKeyOperator);
5959
keyIDVoting = proTx.keyIDVoting;
6060
addr = proTx.addr;
6161
scriptPayout = proTx.scriptPayout;
@@ -89,7 +89,7 @@ class CDeterministicMNState
8989

9090
void ResetOperatorFields()
9191
{
92-
pubKeyOperator = CBLSPublicKey();
92+
pubKeyOperator.Set(CBLSPublicKey());
9393
addr = CService();
9494
scriptOperatorPayout = CScript();
9595
nRevocationReason = CProUpRevTx::REASON_NOT_SPECIFIED;

src/evo/mnauth.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ void CMNAuth::ProcessMessage(CNode* pnode, const std::string& strCommand, CDataS
8989
signHash = ::SerializeHash(std::make_tuple(dmn->pdmnState->pubKeyOperator, pnode->sentMNAuthChallenge, !pnode->fInbound));
9090
}
9191

92-
if (!mnauth.sig.VerifyInsecure(dmn->pdmnState->pubKeyOperator, signHash)) {
92+
if (!mnauth.sig.VerifyInsecure(dmn->pdmnState->pubKeyOperator.Get(), signHash)) {
9393
LOCK(cs_main);
9494
// Same as above, MN seems to not know about his fate yet, so give him a chance to update. If this is a
9595
// malicious actor (DoSing us), we'll ban him soon.

src/evo/providertx.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVa
257257
if (!CheckInputsHash(tx, ptx, state)) {
258258
return false;
259259
}
260-
if (!CheckHashSig(ptx, mn->pdmnState->pubKeyOperator, state)) {
260+
if (!CheckHashSig(ptx, mn->pdmnState->pubKeyOperator.Get(), state)) {
261261
return false;
262262
}
263263
}
@@ -376,7 +376,7 @@ bool CheckProUpRevTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVal
376376

377377
if (!CheckInputsHash(tx, ptx, state))
378378
return false;
379-
if (!CheckHashSig(ptx, dmn->pdmnState->pubKeyOperator, state))
379+
if (!CheckHashSig(ptx, dmn->pdmnState->pubKeyOperator.Get(), state))
380380
return false;
381381
}
382382

src/evo/simplifiedmns.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ uint256 CSimplifiedMNListEntry::CalcHash() const
3737
std::string CSimplifiedMNListEntry::ToString() const
3838
{
3939
return strprintf("CSimplifiedMNListEntry(proRegTxHash=%s, confirmedHash=%s, service=%s, pubKeyOperator=%s, votingAddress=%s, isValid=%d)",
40-
proRegTxHash.ToString(), confirmedHash.ToString(), service.ToString(false), pubKeyOperator.ToString(), CBitcoinAddress(keyIDVoting).ToString(), isValid);
40+
proRegTxHash.ToString(), confirmedHash.ToString(), service.ToString(false), pubKeyOperator.Get().ToString(), CBitcoinAddress(keyIDVoting).ToString(), isValid);
4141
}
4242

4343
void CSimplifiedMNListEntry::ToJson(UniValue& obj) const
@@ -47,7 +47,7 @@ void CSimplifiedMNListEntry::ToJson(UniValue& obj) const
4747
obj.push_back(Pair("proRegTxHash", proRegTxHash.ToString()));
4848
obj.push_back(Pair("confirmedHash", confirmedHash.ToString()));
4949
obj.push_back(Pair("service", service.ToString(false)));
50-
obj.push_back(Pair("pubKeyOperator", pubKeyOperator.ToString()));
50+
obj.push_back(Pair("pubKeyOperator", pubKeyOperator.Get().ToString()));
5151
obj.push_back(Pair("votingAddress", CBitcoinAddress(keyIDVoting).ToString()));
5252
obj.push_back(Pair("isValid", isValid));
5353
}

0 commit comments

Comments
 (0)