2020-01-17 15:42:55 +01:00
|
|
|
// Copyright (c) 2018-2020 The Dash Core developers
|
2018-02-14 14:43:03 +01:00
|
|
|
// Distributed under the MIT software license, see the accompanying
|
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
|
2018-04-02 00:30:17 +02:00
|
|
|
#ifndef BITCOIN_EVO_DETERMINISTICMNS_H
|
|
|
|
#define BITCOIN_EVO_DETERMINISTICMNS_H
|
2018-02-14 14:43:03 +01:00
|
|
|
|
2020-03-19 23:46:56 +01:00
|
|
|
#include <arith_uint256.h>
|
|
|
|
#include <bls/bls.h>
|
|
|
|
#include <dbwrapper.h>
|
|
|
|
#include <evo/evodb.h>
|
|
|
|
#include <evo/providertx.h>
|
|
|
|
#include <evo/simplifiedmns.h>
|
2020-06-09 06:43:34 +02:00
|
|
|
#include <saltedhasher.h>
|
2020-03-19 23:46:56 +01:00
|
|
|
#include <sync.h>
|
2018-02-14 14:43:03 +01:00
|
|
|
|
2020-03-19 23:46:56 +01:00
|
|
|
#include <immer/map.hpp>
|
|
|
|
#include <immer/map_transient.hpp>
|
2018-02-14 14:43:03 +01:00
|
|
|
|
2020-06-09 06:43:34 +02:00
|
|
|
#include <unordered_map>
|
2018-02-14 14:43:03 +01:00
|
|
|
|
|
|
|
class CBlock;
|
|
|
|
class CBlockIndex;
|
|
|
|
class CValidationState;
|
|
|
|
|
2018-11-25 14:27:18 +01:00
|
|
|
namespace llmq
|
|
|
|
{
|
|
|
|
class CFinalCommitment;
|
2019-07-15 20:55:01 +02:00
|
|
|
} // namespace llmq
|
2018-11-25 14:27:18 +01:00
|
|
|
|
2018-02-14 14:43:03 +01:00
|
|
|
class CDeterministicMNState
|
|
|
|
{
|
2020-08-04 13:36:02 +02:00
|
|
|
private:
|
|
|
|
int nPoSeBanHeight{-1};
|
|
|
|
|
|
|
|
friend class CDeterministicMNStateDiff;
|
|
|
|
|
2018-02-14 14:43:03 +01:00
|
|
|
public:
|
|
|
|
int nRegisteredHeight{-1};
|
|
|
|
int nLastPaidHeight{0};
|
2018-08-31 11:33:37 +02:00
|
|
|
int nPoSePenalty{0};
|
2018-02-14 14:43:03 +01:00
|
|
|
int nPoSeRevivedHeight{-1};
|
2018-03-19 12:29:59 +01:00
|
|
|
uint16_t nRevocationReason{CProUpRevTx::REASON_NOT_SPECIFIED};
|
2018-02-14 14:43:03 +01:00
|
|
|
|
2018-11-13 13:24:14 +01:00
|
|
|
// the block hash X blocks after registration, used in quorum calculations
|
|
|
|
uint256 confirmedHash;
|
|
|
|
// sha256(proTxHash, confirmedHash) to speed up quorum calculations
|
|
|
|
// please note that this is NOT a double-sha256 hash
|
|
|
|
uint256 confirmedHashWithProRegTxHash;
|
|
|
|
|
2018-02-14 14:43:03 +01:00
|
|
|
CKeyID keyIDOwner;
|
2019-06-13 11:01:26 +02:00
|
|
|
CBLSLazyPublicKey pubKeyOperator;
|
2018-02-14 14:43:03 +01:00
|
|
|
CKeyID keyIDVoting;
|
|
|
|
CService addr;
|
|
|
|
CScript scriptPayout;
|
|
|
|
CScript scriptOperatorPayout;
|
|
|
|
|
|
|
|
public:
|
2020-08-09 23:34:26 +02:00
|
|
|
CDeterministicMNState() = default;
|
2020-01-05 01:55:41 +01:00
|
|
|
explicit CDeterministicMNState(const CProRegTx& proTx)
|
2018-02-14 14:43:03 +01:00
|
|
|
{
|
|
|
|
keyIDOwner = proTx.keyIDOwner;
|
2019-06-13 11:01:26 +02:00
|
|
|
pubKeyOperator.Set(proTx.pubKeyOperator);
|
2018-02-14 14:43:03 +01:00
|
|
|
keyIDVoting = proTx.keyIDVoting;
|
|
|
|
addr = proTx.addr;
|
|
|
|
scriptPayout = proTx.scriptPayout;
|
|
|
|
}
|
2018-11-06 09:54:23 +01:00
|
|
|
template <typename Stream>
|
|
|
|
CDeterministicMNState(deserialize_type, Stream& s)
|
|
|
|
{
|
|
|
|
s >> *this;
|
|
|
|
}
|
2018-02-14 14:43:03 +01:00
|
|
|
|
|
|
|
ADD_SERIALIZE_METHODS;
|
|
|
|
|
|
|
|
template <typename Stream, typename Operation>
|
|
|
|
inline void SerializationOp(Stream& s, Operation ser_action)
|
|
|
|
{
|
|
|
|
READWRITE(nRegisteredHeight);
|
|
|
|
READWRITE(nLastPaidHeight);
|
2018-08-31 11:33:37 +02:00
|
|
|
READWRITE(nPoSePenalty);
|
2018-02-14 14:43:03 +01:00
|
|
|
READWRITE(nPoSeRevivedHeight);
|
|
|
|
READWRITE(nPoSeBanHeight);
|
2018-03-19 12:29:59 +01:00
|
|
|
READWRITE(nRevocationReason);
|
2018-11-13 13:24:14 +01:00
|
|
|
READWRITE(confirmedHash);
|
|
|
|
READWRITE(confirmedHashWithProRegTxHash);
|
2018-02-14 14:43:03 +01:00
|
|
|
READWRITE(keyIDOwner);
|
2018-10-21 21:45:16 +02:00
|
|
|
READWRITE(pubKeyOperator);
|
2018-02-14 14:43:03 +01:00
|
|
|
READWRITE(keyIDVoting);
|
|
|
|
READWRITE(addr);
|
2019-07-09 07:59:57 +02:00
|
|
|
READWRITE(scriptPayout);
|
|
|
|
READWRITE(scriptOperatorPayout);
|
2018-02-14 14:43:03 +01:00
|
|
|
}
|
|
|
|
|
2018-03-19 08:44:00 +01:00
|
|
|
void ResetOperatorFields()
|
|
|
|
{
|
2019-06-13 11:01:26 +02:00
|
|
|
pubKeyOperator.Set(CBLSPublicKey());
|
2018-03-19 08:44:00 +01:00
|
|
|
addr = CService();
|
|
|
|
scriptOperatorPayout = CScript();
|
2018-03-19 12:29:59 +01:00
|
|
|
nRevocationReason = CProUpRevTx::REASON_NOT_SPECIFIED;
|
2018-03-19 08:44:00 +01:00
|
|
|
}
|
|
|
|
void BanIfNotBanned(int height)
|
|
|
|
{
|
2020-08-04 13:36:02 +02:00
|
|
|
if (!IsBanned()) {
|
2018-03-19 08:44:00 +01:00
|
|
|
nPoSeBanHeight = height;
|
|
|
|
}
|
|
|
|
}
|
2020-08-04 13:36:02 +02:00
|
|
|
int GetBannedHeight() const
|
|
|
|
{
|
|
|
|
return nPoSeBanHeight;
|
|
|
|
}
|
|
|
|
bool IsBanned() const
|
|
|
|
{
|
|
|
|
return nPoSeBanHeight != -1;
|
|
|
|
}
|
|
|
|
void Revive(int nRevivedHeight)
|
|
|
|
{
|
|
|
|
nPoSePenalty = 0;
|
|
|
|
nPoSeBanHeight = -1;
|
|
|
|
nPoSeRevivedHeight = nRevivedHeight;
|
|
|
|
}
|
2018-11-13 13:24:14 +01:00
|
|
|
void UpdateConfirmedHash(const uint256& _proTxHash, const uint256& _confirmedHash)
|
|
|
|
{
|
|
|
|
confirmedHash = _confirmedHash;
|
|
|
|
CSHA256 h;
|
|
|
|
h.Write(_proTxHash.begin(), _proTxHash.size());
|
|
|
|
h.Write(_confirmedHash.begin(), _confirmedHash.size());
|
|
|
|
h.Finalize(confirmedHashWithProRegTxHash.begin());
|
|
|
|
}
|
2018-03-19 08:44:00 +01:00
|
|
|
|
2019-07-09 07:59:57 +02:00
|
|
|
public:
|
|
|
|
std::string ToString() const;
|
|
|
|
void ToJson(UniValue& obj) const;
|
|
|
|
};
|
|
|
|
typedef std::shared_ptr<CDeterministicMNState> CDeterministicMNStatePtr;
|
|
|
|
typedef std::shared_ptr<const CDeterministicMNState> CDeterministicMNStateCPtr;
|
|
|
|
|
|
|
|
class CDeterministicMNStateDiff
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
enum Field : uint32_t {
|
|
|
|
Field_nRegisteredHeight = 0x0001,
|
|
|
|
Field_nLastPaidHeight = 0x0002,
|
|
|
|
Field_nPoSePenalty = 0x0004,
|
|
|
|
Field_nPoSeRevivedHeight = 0x0008,
|
|
|
|
Field_nPoSeBanHeight = 0x0010,
|
|
|
|
Field_nRevocationReason = 0x0020,
|
|
|
|
Field_confirmedHash = 0x0040,
|
|
|
|
Field_confirmedHashWithProRegTxHash = 0x0080,
|
|
|
|
Field_keyIDOwner = 0x0100,
|
|
|
|
Field_pubKeyOperator = 0x0200,
|
|
|
|
Field_keyIDVoting = 0x0400,
|
|
|
|
Field_addr = 0x0800,
|
|
|
|
Field_scriptPayout = 0x1000,
|
|
|
|
Field_scriptOperatorPayout = 0x2000,
|
|
|
|
};
|
|
|
|
|
|
|
|
#define DMN_STATE_DIFF_ALL_FIELDS \
|
|
|
|
DMN_STATE_DIFF_LINE(nRegisteredHeight) \
|
|
|
|
DMN_STATE_DIFF_LINE(nLastPaidHeight) \
|
|
|
|
DMN_STATE_DIFF_LINE(nPoSePenalty) \
|
|
|
|
DMN_STATE_DIFF_LINE(nPoSeRevivedHeight) \
|
|
|
|
DMN_STATE_DIFF_LINE(nPoSeBanHeight) \
|
|
|
|
DMN_STATE_DIFF_LINE(nRevocationReason) \
|
|
|
|
DMN_STATE_DIFF_LINE(confirmedHash) \
|
|
|
|
DMN_STATE_DIFF_LINE(confirmedHashWithProRegTxHash) \
|
|
|
|
DMN_STATE_DIFF_LINE(keyIDOwner) \
|
|
|
|
DMN_STATE_DIFF_LINE(pubKeyOperator) \
|
|
|
|
DMN_STATE_DIFF_LINE(keyIDVoting) \
|
|
|
|
DMN_STATE_DIFF_LINE(addr) \
|
|
|
|
DMN_STATE_DIFF_LINE(scriptPayout) \
|
|
|
|
DMN_STATE_DIFF_LINE(scriptOperatorPayout)
|
|
|
|
|
|
|
|
public:
|
|
|
|
uint32_t fields{0};
|
|
|
|
// we reuse the state class, but only the members as noted by fields are valid
|
|
|
|
CDeterministicMNState state;
|
|
|
|
|
|
|
|
public:
|
2020-08-09 23:34:26 +02:00
|
|
|
CDeterministicMNStateDiff() = default;
|
2019-07-09 07:59:57 +02:00
|
|
|
CDeterministicMNStateDiff(const CDeterministicMNState& a, const CDeterministicMNState& b)
|
2018-02-14 14:43:03 +01:00
|
|
|
{
|
2019-07-09 07:59:57 +02:00
|
|
|
#define DMN_STATE_DIFF_LINE(f) if (a.f != b.f) { state.f = b.f; fields |= Field_##f; }
|
|
|
|
DMN_STATE_DIFF_ALL_FIELDS
|
|
|
|
#undef DMN_STATE_DIFF_LINE
|
2018-02-14 14:43:03 +01:00
|
|
|
}
|
|
|
|
|
2019-07-09 07:59:57 +02:00
|
|
|
ADD_SERIALIZE_METHODS;
|
|
|
|
|
|
|
|
template <typename Stream, typename Operation>
|
|
|
|
inline void SerializationOp(Stream& s, Operation ser_action)
|
2018-02-14 14:43:03 +01:00
|
|
|
{
|
2019-07-09 07:59:57 +02:00
|
|
|
READWRITE(VARINT(fields));
|
|
|
|
#define DMN_STATE_DIFF_LINE(f) if (fields & Field_##f) READWRITE(state.f);
|
|
|
|
DMN_STATE_DIFF_ALL_FIELDS
|
|
|
|
#undef DMN_STATE_DIFF_LINE
|
2018-02-14 14:43:03 +01:00
|
|
|
}
|
|
|
|
|
2019-07-09 07:59:57 +02:00
|
|
|
void ApplyToState(CDeterministicMNState& target) const
|
|
|
|
{
|
|
|
|
#define DMN_STATE_DIFF_LINE(f) if (fields & Field_##f) target.f = state.f;
|
|
|
|
DMN_STATE_DIFF_ALL_FIELDS
|
|
|
|
#undef DMN_STATE_DIFF_LINE
|
|
|
|
}
|
2018-02-14 14:43:03 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
class CDeterministicMN
|
|
|
|
{
|
2020-06-09 05:53:42 +02:00
|
|
|
private:
|
|
|
|
uint64_t internalId{std::numeric_limits<uint64_t>::max()};
|
|
|
|
|
2018-02-14 14:43:03 +01:00
|
|
|
public:
|
2020-06-09 05:53:42 +02:00
|
|
|
CDeterministicMN() = delete; // no default constructor, must specify internalId
|
2020-08-09 23:34:26 +02:00
|
|
|
explicit CDeterministicMN(uint64_t _internalId) : internalId(_internalId)
|
2020-06-09 05:53:42 +02:00
|
|
|
{
|
|
|
|
// only non-initial values
|
|
|
|
assert(_internalId != std::numeric_limits<uint64_t>::max());
|
|
|
|
}
|
|
|
|
// TODO: can be removed in a future version
|
|
|
|
CDeterministicMN(const CDeterministicMN& mn, uint64_t _internalId) : CDeterministicMN(mn) {
|
|
|
|
// only non-initial values
|
|
|
|
assert(_internalId != std::numeric_limits<uint64_t>::max());
|
|
|
|
internalId = _internalId;
|
|
|
|
}
|
|
|
|
|
2018-11-06 09:54:23 +01:00
|
|
|
template <typename Stream>
|
|
|
|
CDeterministicMN(deserialize_type, Stream& s)
|
|
|
|
{
|
|
|
|
s >> *this;
|
|
|
|
}
|
2018-02-14 14:43:03 +01:00
|
|
|
|
|
|
|
uint256 proTxHash;
|
2018-10-25 16:29:50 +02:00
|
|
|
COutPoint collateralOutpoint;
|
2018-02-14 14:43:03 +01:00
|
|
|
uint16_t nOperatorReward;
|
|
|
|
CDeterministicMNStateCPtr pdmnState;
|
|
|
|
|
|
|
|
public:
|
|
|
|
template <typename Stream, typename Operation>
|
2019-07-09 07:59:57 +02:00
|
|
|
inline void SerializationOp(Stream& s, Operation ser_action, bool oldFormat)
|
2018-02-14 14:43:03 +01:00
|
|
|
{
|
|
|
|
READWRITE(proTxHash);
|
2019-07-09 07:59:57 +02:00
|
|
|
if (!oldFormat) {
|
|
|
|
READWRITE(VARINT(internalId));
|
|
|
|
}
|
2018-10-25 16:29:50 +02:00
|
|
|
READWRITE(collateralOutpoint);
|
2018-02-14 14:43:03 +01:00
|
|
|
READWRITE(nOperatorReward);
|
|
|
|
READWRITE(pdmnState);
|
|
|
|
}
|
|
|
|
|
2019-07-09 07:59:57 +02:00
|
|
|
template<typename Stream>
|
|
|
|
void Serialize(Stream& s) const
|
|
|
|
{
|
|
|
|
NCONST_PTR(this)->SerializationOp(s, CSerActionSerialize(), false);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename Stream>
|
|
|
|
void Unserialize(Stream& s, bool oldFormat = false)
|
|
|
|
{
|
|
|
|
SerializationOp(s, CSerActionUnserialize(), oldFormat);
|
|
|
|
}
|
|
|
|
|
2020-06-09 05:53:42 +02:00
|
|
|
uint64_t GetInternalId() const;
|
|
|
|
|
2018-02-14 14:43:03 +01:00
|
|
|
std::string ToString() const;
|
|
|
|
void ToJson(UniValue& obj) const;
|
|
|
|
};
|
|
|
|
typedef std::shared_ptr<const CDeterministicMN> CDeterministicMNCPtr;
|
|
|
|
|
|
|
|
class CDeterministicMNListDiff;
|
|
|
|
|
2018-11-06 09:54:23 +01:00
|
|
|
template <typename Stream, typename K, typename T, typename Hash, typename Equal>
|
2018-02-14 14:43:03 +01:00
|
|
|
void SerializeImmerMap(Stream& os, const immer::map<K, T, Hash, Equal>& m)
|
|
|
|
{
|
|
|
|
WriteCompactSize(os, m.size());
|
|
|
|
for (typename immer::map<K, T, Hash, Equal>::const_iterator mi = m.begin(); mi != m.end(); ++mi)
|
|
|
|
Serialize(os, (*mi));
|
|
|
|
}
|
|
|
|
|
2018-11-06 09:54:23 +01:00
|
|
|
template <typename Stream, typename K, typename T, typename Hash, typename Equal>
|
2018-02-14 14:43:03 +01:00
|
|
|
void UnserializeImmerMap(Stream& is, immer::map<K, T, Hash, Equal>& m)
|
|
|
|
{
|
|
|
|
m = immer::map<K, T, Hash, Equal>();
|
|
|
|
unsigned int nSize = ReadCompactSize(is);
|
2018-11-06 09:54:23 +01:00
|
|
|
for (unsigned int i = 0; i < nSize; i++) {
|
2018-02-14 14:43:03 +01:00
|
|
|
std::pair<K, T> item;
|
|
|
|
Unserialize(is, item);
|
|
|
|
m = m.set(item.first, item.second);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-02 06:16:27 +02:00
|
|
|
// For some reason the compiler is not able to choose the correct Serialize/Deserialize methods without a specialized
|
|
|
|
// version of SerReadWrite. It otherwise always chooses the version that calls a.Serialize()
|
|
|
|
template<typename Stream, typename K, typename T, typename Hash, typename Equal>
|
|
|
|
inline void SerReadWrite(Stream& s, const immer::map<K, T, Hash, Equal>& m, CSerActionSerialize ser_action)
|
|
|
|
{
|
|
|
|
::SerializeImmerMap(s, m);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename Stream, typename K, typename T, typename Hash, typename Equal>
|
|
|
|
inline void SerReadWrite(Stream& s, immer::map<K, T, Hash, Equal>& obj, CSerActionUnserialize ser_action)
|
|
|
|
{
|
|
|
|
::UnserializeImmerMap(s, obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-14 14:43:03 +01:00
|
|
|
class CDeterministicMNList
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
typedef immer::map<uint256, CDeterministicMNCPtr> MnMap;
|
2019-07-09 07:59:57 +02:00
|
|
|
typedef immer::map<uint64_t, uint256> MnInternalIdMap;
|
2018-11-06 09:54:23 +01:00
|
|
|
typedef immer::map<uint256, std::pair<uint256, uint32_t> > MnUniquePropertyMap;
|
2018-02-14 14:43:03 +01:00
|
|
|
|
|
|
|
private:
|
|
|
|
uint256 blockHash;
|
|
|
|
int nHeight{-1};
|
2019-07-09 07:59:57 +02:00
|
|
|
uint32_t nTotalRegisteredCount{0};
|
2018-02-14 14:43:03 +01:00
|
|
|
MnMap mnMap;
|
2019-07-09 07:59:57 +02:00
|
|
|
MnInternalIdMap mnInternalIdMap;
|
2018-02-14 14:43:03 +01:00
|
|
|
|
|
|
|
// map of unique properties like address and keys
|
|
|
|
// we keep track of this as checking for duplicates would otherwise be painfully slow
|
|
|
|
MnUniquePropertyMap mnUniquePropertyMap;
|
|
|
|
|
|
|
|
public:
|
2020-08-09 23:34:26 +02:00
|
|
|
CDeterministicMNList() = default;
|
2019-07-09 07:59:57 +02:00
|
|
|
explicit CDeterministicMNList(const uint256& _blockHash, int _height, uint32_t _totalRegisteredCount) :
|
2018-11-06 09:54:23 +01:00
|
|
|
blockHash(_blockHash),
|
2019-07-09 07:59:57 +02:00
|
|
|
nHeight(_height),
|
|
|
|
nTotalRegisteredCount(_totalRegisteredCount)
|
2018-11-06 09:54:23 +01:00
|
|
|
{
|
|
|
|
}
|
2018-02-14 14:43:03 +01:00
|
|
|
|
|
|
|
template <typename Stream, typename Operation>
|
2019-07-09 07:59:57 +02:00
|
|
|
inline void SerializationOpBase(Stream& s, Operation ser_action)
|
2018-02-14 14:43:03 +01:00
|
|
|
{
|
|
|
|
READWRITE(blockHash);
|
|
|
|
READWRITE(nHeight);
|
2019-07-09 07:59:57 +02:00
|
|
|
READWRITE(nTotalRegisteredCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename Stream>
|
|
|
|
void Serialize(Stream& s) const
|
|
|
|
{
|
|
|
|
NCONST_PTR(this)->SerializationOpBase(s, CSerActionSerialize());
|
|
|
|
// Serialize the map as a vector
|
|
|
|
WriteCompactSize(s, mnMap.size());
|
|
|
|
for (const auto& p : mnMap) {
|
|
|
|
s << *p.second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename Stream>
|
|
|
|
void Unserialize(Stream& s) {
|
|
|
|
mnMap = MnMap();
|
|
|
|
mnUniquePropertyMap = MnUniquePropertyMap();
|
|
|
|
mnInternalIdMap = MnInternalIdMap();
|
|
|
|
|
|
|
|
SerializationOpBase(s, CSerActionUnserialize());
|
|
|
|
|
|
|
|
size_t cnt = ReadCompactSize(s);
|
|
|
|
for (size_t i = 0; i < cnt; i++) {
|
2020-06-08 04:57:57 +02:00
|
|
|
AddMN(std::make_shared<CDeterministicMN>(deserialize, s), false);
|
2019-07-09 07:59:57 +02:00
|
|
|
}
|
2018-02-14 14:43:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
2018-10-02 11:03:05 +02:00
|
|
|
size_t GetAllMNsCount() const
|
2018-02-14 14:43:03 +01:00
|
|
|
{
|
|
|
|
return mnMap.size();
|
|
|
|
}
|
|
|
|
|
2018-10-23 13:15:38 +02:00
|
|
|
size_t GetValidMNsCount() const
|
|
|
|
{
|
|
|
|
size_t count = 0;
|
|
|
|
for (const auto& p : mnMap) {
|
|
|
|
if (IsMNValid(p.second)) {
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2018-11-06 09:54:23 +01:00
|
|
|
template <typename Callback>
|
|
|
|
void ForEachMN(bool onlyValid, Callback&& cb) const
|
|
|
|
{
|
2018-02-14 14:43:03 +01:00
|
|
|
for (const auto& p : mnMap) {
|
2018-10-02 11:03:05 +02:00
|
|
|
if (!onlyValid || IsMNValid(p.second)) {
|
|
|
|
cb(p.second);
|
2018-02-14 14:43:03 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
const uint256& GetBlockHash() const
|
|
|
|
{
|
|
|
|
return blockHash;
|
|
|
|
}
|
|
|
|
void SetBlockHash(const uint256& _blockHash)
|
|
|
|
{
|
|
|
|
blockHash = _blockHash;
|
|
|
|
}
|
|
|
|
int GetHeight() const
|
|
|
|
{
|
|
|
|
return nHeight;
|
|
|
|
}
|
|
|
|
void SetHeight(int _height)
|
|
|
|
{
|
|
|
|
nHeight = _height;
|
|
|
|
}
|
2019-07-09 07:59:57 +02:00
|
|
|
uint32_t GetTotalRegisteredCount() const
|
|
|
|
{
|
|
|
|
return nTotalRegisteredCount;
|
|
|
|
}
|
2018-02-14 14:43:03 +01:00
|
|
|
|
|
|
|
bool IsMNValid(const uint256& proTxHash) const;
|
|
|
|
bool IsMNPoSeBanned(const uint256& proTxHash) const;
|
2020-08-09 23:34:26 +02:00
|
|
|
static bool IsMNValid(const CDeterministicMNCPtr& dmn);
|
|
|
|
static bool IsMNPoSeBanned(const CDeterministicMNCPtr& dmn);
|
2018-02-14 14:43:03 +01:00
|
|
|
|
2018-11-06 09:54:23 +01:00
|
|
|
bool HasMN(const uint256& proTxHash) const
|
|
|
|
{
|
2018-02-14 14:43:03 +01:00
|
|
|
return GetMN(proTxHash) != nullptr;
|
|
|
|
}
|
2018-12-17 14:24:48 +01:00
|
|
|
bool HasMNByCollateral(const COutPoint& collateralOutpoint) const
|
|
|
|
{
|
|
|
|
return GetMNByCollateral(collateralOutpoint) != nullptr;
|
|
|
|
}
|
|
|
|
bool HasValidMNByCollateral(const COutPoint& collateralOutpoint) const
|
|
|
|
{
|
|
|
|
return GetValidMNByCollateral(collateralOutpoint) != nullptr;
|
|
|
|
}
|
2018-02-14 14:43:03 +01:00
|
|
|
CDeterministicMNCPtr GetMN(const uint256& proTxHash) const;
|
|
|
|
CDeterministicMNCPtr GetValidMN(const uint256& proTxHash) const;
|
2018-10-21 21:45:16 +02:00
|
|
|
CDeterministicMNCPtr GetMNByOperatorKey(const CBLSPublicKey& pubKey);
|
2018-10-25 16:29:50 +02:00
|
|
|
CDeterministicMNCPtr GetMNByCollateral(const COutPoint& collateralOutpoint) const;
|
2018-12-17 14:24:48 +01:00
|
|
|
CDeterministicMNCPtr GetValidMNByCollateral(const COutPoint& collateralOutpoint) const;
|
2019-06-13 11:03:20 +02:00
|
|
|
CDeterministicMNCPtr GetMNByService(const CService& service) const;
|
2019-07-09 07:59:57 +02:00
|
|
|
CDeterministicMNCPtr GetMNByInternalId(uint64_t internalId) const;
|
2018-02-14 14:43:03 +01:00
|
|
|
CDeterministicMNCPtr GetMNPayee() const;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Calculates the projected MN payees for the next *count* blocks. The result is not guaranteed to be correct
|
|
|
|
* as PoSe banning might occur later
|
|
|
|
* @param count
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
std::vector<CDeterministicMNCPtr> GetProjectedMNPayees(int nCount) const;
|
|
|
|
|
2018-11-13 13:24:14 +01:00
|
|
|
/**
|
|
|
|
* Calculate a quorum based on the modifier. The resulting list is deterministically sorted by score
|
|
|
|
* @param maxSize
|
|
|
|
* @param modifier
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
std::vector<CDeterministicMNCPtr> CalculateQuorum(size_t maxSize, const uint256& modifier) const;
|
|
|
|
std::vector<std::pair<arith_uint256, CDeterministicMNCPtr>> CalculateScores(const uint256& modifier) const;
|
|
|
|
|
2018-11-25 14:27:18 +01:00
|
|
|
/**
|
|
|
|
* Calculates the maximum penalty which is allowed at the height of this MN list. It is dynamic and might change
|
|
|
|
* for every block.
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
int CalcMaxPoSePenalty() const;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a the given percentage from the max penalty for this MN list. Always use this method to calculate the
|
|
|
|
* value later passed to PoSePunish. The percentage should be high enough to take per-block penalty decreasing for MNs
|
|
|
|
* into account. This means, if you want to accept 2 failures per payment cycle, you should choose a percentage that
|
|
|
|
* is higher then 50%, e.g. 66%.
|
|
|
|
* @param percent
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
int CalcPenalty(int percent) const;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Punishes a MN for misbehavior. If the resulting penalty score of the MN reaches the max penalty, it is banned.
|
|
|
|
* Penalty scores are only increased when the MN is not already banned, which means that after banning the penalty
|
|
|
|
* might appear lower then the current max penalty, while the MN is still banned.
|
|
|
|
* @param proTxHash
|
|
|
|
* @param penalty
|
|
|
|
*/
|
2018-12-06 08:06:37 +01:00
|
|
|
void PoSePunish(const uint256& proTxHash, int penalty, bool debugLogs);
|
2018-11-25 14:27:18 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Decrease penalty score of MN by 1.
|
|
|
|
* Only allowed on non-banned MNs.
|
|
|
|
* @param proTxHash
|
|
|
|
*/
|
|
|
|
void PoSeDecrease(const uint256& proTxHash);
|
|
|
|
|
2018-02-14 14:43:03 +01:00
|
|
|
CDeterministicMNListDiff BuildDiff(const CDeterministicMNList& to) const;
|
2018-11-15 10:42:39 +01:00
|
|
|
CSimplifiedMNListDiff BuildSimplifiedDiff(const CDeterministicMNList& to) const;
|
2019-07-09 07:59:57 +02:00
|
|
|
CDeterministicMNList ApplyDiff(const CBlockIndex* pindex, const CDeterministicMNListDiff& diff) const;
|
2018-02-14 14:43:03 +01:00
|
|
|
|
2020-06-08 04:57:57 +02:00
|
|
|
void AddMN(const CDeterministicMNCPtr& dmn, bool fBumpTotalCount = true);
|
2019-07-09 07:59:57 +02:00
|
|
|
void UpdateMN(const CDeterministicMNCPtr& oldDmn, const CDeterministicMNStateCPtr& pdmnState);
|
2018-11-06 09:54:23 +01:00
|
|
|
void UpdateMN(const uint256& proTxHash, const CDeterministicMNStateCPtr& pdmnState);
|
2019-07-09 07:59:57 +02:00
|
|
|
void UpdateMN(const CDeterministicMNCPtr& oldDmn, const CDeterministicMNStateDiff& stateDiff);
|
2018-02-14 14:43:03 +01:00
|
|
|
void RemoveMN(const uint256& proTxHash);
|
|
|
|
|
2018-11-06 09:54:23 +01:00
|
|
|
template <typename T>
|
2018-02-14 14:43:03 +01:00
|
|
|
bool HasUniqueProperty(const T& v) const
|
|
|
|
{
|
|
|
|
return mnUniquePropertyMap.count(::SerializeHash(v)) != 0;
|
|
|
|
}
|
2018-11-06 09:54:23 +01:00
|
|
|
template <typename T>
|
2018-02-14 14:43:03 +01:00
|
|
|
CDeterministicMNCPtr GetUniquePropertyMN(const T& v) const
|
|
|
|
{
|
|
|
|
auto p = mnUniquePropertyMap.find(::SerializeHash(v));
|
|
|
|
if (!p) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return GetMN(p->first);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2018-11-06 09:54:23 +01:00
|
|
|
template <typename T>
|
2018-02-14 14:43:03 +01:00
|
|
|
void AddUniqueProperty(const CDeterministicMNCPtr& dmn, const T& v)
|
|
|
|
{
|
2018-12-10 08:31:09 +01:00
|
|
|
static const T nullValue;
|
|
|
|
assert(v != nullValue);
|
|
|
|
|
2018-02-14 14:43:03 +01:00
|
|
|
auto hash = ::SerializeHash(v);
|
|
|
|
auto oldEntry = mnUniquePropertyMap.find(hash);
|
|
|
|
assert(!oldEntry || oldEntry->first == dmn->proTxHash);
|
|
|
|
std::pair<uint256, uint32_t> newEntry(dmn->proTxHash, 1);
|
|
|
|
if (oldEntry) {
|
|
|
|
newEntry.second = oldEntry->second + 1;
|
|
|
|
}
|
|
|
|
mnUniquePropertyMap = mnUniquePropertyMap.set(hash, newEntry);
|
|
|
|
}
|
2018-11-06 09:54:23 +01:00
|
|
|
template <typename T>
|
2018-02-14 14:43:03 +01:00
|
|
|
void DeleteUniqueProperty(const CDeterministicMNCPtr& dmn, const T& oldValue)
|
|
|
|
{
|
2018-12-10 08:31:09 +01:00
|
|
|
static const T nullValue;
|
|
|
|
assert(oldValue != nullValue);
|
|
|
|
|
2018-02-14 14:43:03 +01:00
|
|
|
auto oldHash = ::SerializeHash(oldValue);
|
|
|
|
auto p = mnUniquePropertyMap.find(oldHash);
|
|
|
|
assert(p && p->first == dmn->proTxHash);
|
|
|
|
if (p->second == 1) {
|
|
|
|
mnUniquePropertyMap = mnUniquePropertyMap.erase(oldHash);
|
|
|
|
} else {
|
|
|
|
mnUniquePropertyMap = mnUniquePropertyMap.set(oldHash, std::make_pair(dmn->proTxHash, p->second - 1));
|
|
|
|
}
|
|
|
|
}
|
2018-11-06 09:54:23 +01:00
|
|
|
template <typename T>
|
2018-02-14 14:43:03 +01:00
|
|
|
void UpdateUniqueProperty(const CDeterministicMNCPtr& dmn, const T& oldValue, const T& newValue)
|
|
|
|
{
|
|
|
|
if (oldValue == newValue) {
|
|
|
|
return;
|
|
|
|
}
|
2018-12-10 08:31:09 +01:00
|
|
|
static const T nullValue;
|
|
|
|
|
|
|
|
if (oldValue != nullValue) {
|
|
|
|
DeleteUniqueProperty(dmn, oldValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (newValue != nullValue) {
|
|
|
|
AddUniqueProperty(dmn, newValue);
|
|
|
|
}
|
2018-02-14 14:43:03 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class CDeterministicMNListDiff
|
|
|
|
{
|
|
|
|
public:
|
2020-06-09 06:43:34 +02:00
|
|
|
int nHeight{-1}; //memory only
|
|
|
|
|
2019-07-09 07:59:57 +02:00
|
|
|
std::vector<CDeterministicMNCPtr> addedMNs;
|
|
|
|
// keys are all relating to the internalId of MNs
|
|
|
|
std::map<uint64_t, CDeterministicMNStateDiff> updatedMNs;
|
|
|
|
std::set<uint64_t> removedMns;
|
2018-02-14 14:43:03 +01:00
|
|
|
|
|
|
|
public:
|
2019-07-09 07:59:57 +02:00
|
|
|
template<typename Stream>
|
|
|
|
void Serialize(Stream& s) const
|
|
|
|
{
|
|
|
|
s << addedMNs;
|
|
|
|
WriteCompactSize(s, updatedMNs.size());
|
|
|
|
for (const auto& p : updatedMNs) {
|
2020-12-17 13:20:31 +01:00
|
|
|
WriteVarInt<Stream, VarIntMode::DEFAULT, uint64_t>(s, p.first);
|
2019-07-09 07:59:57 +02:00
|
|
|
s << p.second;
|
|
|
|
}
|
|
|
|
WriteCompactSize(s, removedMns.size());
|
|
|
|
for (const auto& p : removedMns) {
|
2020-12-17 13:20:31 +01:00
|
|
|
WriteVarInt<Stream, VarIntMode::DEFAULT, uint64_t>(s, p);
|
2019-07-09 07:59:57 +02:00
|
|
|
}
|
|
|
|
}
|
2018-02-14 14:43:03 +01:00
|
|
|
|
2019-07-09 07:59:57 +02:00
|
|
|
template<typename Stream>
|
|
|
|
void Unserialize(Stream& s)
|
2018-02-14 14:43:03 +01:00
|
|
|
{
|
2019-07-09 07:59:57 +02:00
|
|
|
updatedMNs.clear();
|
|
|
|
removedMns.clear();
|
|
|
|
|
|
|
|
size_t tmp;
|
|
|
|
uint64_t tmp2;
|
|
|
|
s >> addedMNs;
|
|
|
|
tmp = ReadCompactSize(s);
|
|
|
|
for (size_t i = 0; i < tmp; i++) {
|
|
|
|
CDeterministicMNStateDiff diff;
|
2020-12-17 13:20:31 +01:00
|
|
|
tmp2 = ReadVarInt<Stream, VarIntMode::DEFAULT, uint64_t>(s);
|
2019-07-09 07:59:57 +02:00
|
|
|
s >> diff;
|
|
|
|
updatedMNs.emplace(tmp2, std::move(diff));
|
|
|
|
}
|
|
|
|
tmp = ReadCompactSize(s);
|
|
|
|
for (size_t i = 0; i < tmp; i++) {
|
2020-12-17 13:20:31 +01:00
|
|
|
tmp2 = ReadVarInt<Stream, VarIntMode::DEFAULT, uint64_t>(s);
|
2019-07-09 07:59:57 +02:00
|
|
|
removedMns.emplace(tmp2);
|
|
|
|
}
|
2018-02-14 14:43:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
bool HasChanges() const
|
|
|
|
{
|
|
|
|
return !addedMNs.empty() || !updatedMNs.empty() || !removedMns.empty();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-07-09 07:59:57 +02:00
|
|
|
// TODO can be removed in a future version
|
|
|
|
class CDeterministicMNListDiff_OldFormat
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
uint256 prevBlockHash;
|
|
|
|
uint256 blockHash;
|
|
|
|
int nHeight{-1};
|
|
|
|
std::map<uint256, CDeterministicMNCPtr> addedMNs;
|
|
|
|
std::map<uint256, CDeterministicMNStateCPtr> updatedMNs;
|
|
|
|
std::set<uint256> removedMns;
|
|
|
|
|
|
|
|
public:
|
|
|
|
template<typename Stream>
|
|
|
|
void Unserialize(Stream& s) {
|
|
|
|
addedMNs.clear();
|
|
|
|
s >> prevBlockHash;
|
|
|
|
s >> blockHash;
|
|
|
|
s >> nHeight;
|
|
|
|
size_t cnt = ReadCompactSize(s);
|
|
|
|
for (size_t i = 0; i < cnt; i++) {
|
|
|
|
uint256 proTxHash;
|
2020-06-09 05:53:42 +02:00
|
|
|
// NOTE: This is a hack and "0" is just a dummy id. The actual internalId is assigned to a copy
|
|
|
|
// of this dmn via corresponding ctor when we convert the diff format to a new one in UpgradeDiff
|
|
|
|
// thus the logic that we must set internalId before dmn is used in any meaningful way is preserved.
|
|
|
|
auto dmn = std::make_shared<CDeterministicMN>(0);
|
2019-07-09 07:59:57 +02:00
|
|
|
s >> proTxHash;
|
|
|
|
dmn->Unserialize(s, true);
|
|
|
|
addedMNs.emplace(proTxHash, dmn);
|
|
|
|
}
|
|
|
|
s >> updatedMNs;
|
|
|
|
s >> removedMns;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-02-14 14:43:03 +01:00
|
|
|
class CDeterministicMNManager
|
|
|
|
{
|
2020-06-09 06:43:34 +02:00
|
|
|
static const int DISK_SNAPSHOT_PERIOD = 576; // once per day
|
|
|
|
static const int DISK_SNAPSHOTS = 3; // keep cache for 3 disk snapshots to have 2 full days covered
|
|
|
|
static const int LIST_DIFFS_CACHE_SIZE = DISK_SNAPSHOT_PERIOD * DISK_SNAPSHOTS;
|
2018-02-14 14:43:03 +01:00
|
|
|
|
|
|
|
public:
|
|
|
|
CCriticalSection cs;
|
|
|
|
|
|
|
|
private:
|
|
|
|
CEvoDB& evoDb;
|
|
|
|
|
2020-06-09 06:43:34 +02:00
|
|
|
std::unordered_map<uint256, CDeterministicMNList, StaticSaltedHasher> mnListsCache;
|
|
|
|
std::unordered_map<uint256, CDeterministicMNListDiff, StaticSaltedHasher> mnListDiffsCache;
|
2019-07-09 07:59:57 +02:00
|
|
|
const CBlockIndex* tipIndex{nullptr};
|
2018-02-14 14:43:03 +01:00
|
|
|
|
|
|
|
public:
|
2020-01-05 01:55:41 +01:00
|
|
|
explicit CDeterministicMNManager(CEvoDB& _evoDb);
|
2018-02-14 14:43:03 +01:00
|
|
|
|
2021-04-03 19:18:50 +02:00
|
|
|
bool ProcessBlock(const CBlock& block, const CBlockIndex* pindex, CValidationState& state, const CCoinsViewCache& view, bool fJustCheck);
|
2018-02-14 14:43:03 +01:00
|
|
|
bool UndoBlock(const CBlock& block, const CBlockIndex* pindex);
|
|
|
|
|
2018-11-06 09:54:23 +01:00
|
|
|
void UpdatedBlockTip(const CBlockIndex* pindex);
|
2018-02-14 14:43:03 +01:00
|
|
|
|
|
|
|
// the returned list will not contain the correct block hash (we can't know it yet as the coinbase TX is not updated yet)
|
2021-04-03 19:18:50 +02:00
|
|
|
bool BuildNewListFromBlock(const CBlock& block, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view, CDeterministicMNList& mnListRet, bool debugLogs);
|
2020-08-09 23:34:26 +02:00
|
|
|
static void HandleQuorumCommitment(llmq::CFinalCommitment& qc, const CBlockIndex* pindexQuorum, CDeterministicMNList& mnList, bool debugLogs);
|
|
|
|
static void DecreasePoSePenalties(CDeterministicMNList& mnList);
|
2018-02-14 14:43:03 +01:00
|
|
|
|
2019-07-09 07:59:57 +02:00
|
|
|
CDeterministicMNList GetListForBlock(const CBlockIndex* pindex);
|
2018-02-14 14:43:03 +01:00
|
|
|
CDeterministicMNList GetListAtChainTip();
|
|
|
|
|
2018-10-25 16:29:50 +02:00
|
|
|
// Test if given TX is a ProRegTx which also contains the collateral at index n
|
2020-08-09 23:34:26 +02:00
|
|
|
static bool IsProTxWithCollateral(const CTransactionRef& tx, uint32_t n);
|
2018-02-14 14:43:03 +01:00
|
|
|
|
2019-01-29 15:54:38 +01:00
|
|
|
bool IsDIP3Enforced(int nHeight = -1);
|
2018-02-15 13:57:18 +01:00
|
|
|
|
2019-07-09 07:59:57 +02:00
|
|
|
public:
|
|
|
|
// TODO these can all be removed in a future version
|
2020-06-11 19:52:58 +02:00
|
|
|
void UpgradeDiff(CDBBatch& batch, const CBlockIndex* pindexNext, const CDeterministicMNList& curMNList, CDeterministicMNList& newMNList);
|
|
|
|
bool UpgradeDBIfNeeded();
|
2019-07-09 07:59:57 +02:00
|
|
|
|
2018-02-14 14:43:03 +01:00
|
|
|
private:
|
|
|
|
void CleanupCache(int nHeight);
|
|
|
|
};
|
|
|
|
|
2017-11-09 21:22:08 +01:00
|
|
|
extern std::unique_ptr<CDeterministicMNManager> deterministicMNManager;
|
2018-02-14 14:43:03 +01:00
|
|
|
|
2018-04-02 00:30:17 +02:00
|
|
|
#endif // BITCOIN_EVO_DETERMINISTICMNS_H
|