Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Resolve mainnet v19 fork issues #5392

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
201 changes: 134 additions & 67 deletions src/evo/deterministicmns.cpp

Large diffs are not rendered by default.

67 changes: 44 additions & 23 deletions src/evo/deterministicmns.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,10 @@ class CDeterministicMN
uint64_t internalId{std::numeric_limits<uint64_t>::max()};

public:
static constexpr uint16_t CURRENT_MN_FORMAT = 0;
static constexpr uint16_t MN_OLD_FORMAT = 0;
static constexpr uint16_t MN_TYPE_FORMAT = 1;
static constexpr uint16_t MN_VERSION_FORMAT = 2;
static constexpr uint16_t MN_CURRENT_FORMAT = MN_VERSION_FORMAT;

uint256 proTxHash;
COutPoint collateralOutpoint;
Expand Down Expand Up @@ -73,12 +75,16 @@ class CDeterministicMN
READWRITE(VARINT(internalId));
READWRITE(collateralOutpoint);
READWRITE(nOperatorReward);
// We need to read CDeterministicMNState using the old format only when called with CURRENT_MN_FORMAT on Unserialize()
// We need to read CDeterministicMNState using the old format only when called with MN_OLD_FORMAT or MN_TYPE_FORMAT on Unserialize()
// Serialisation (writing) will be done always using new format
if (ser_action.ForRead() && format_version == CURRENT_MN_FORMAT) {
if (ser_action.ForRead() && format_version == MN_OLD_FORMAT) {
CDeterministicMNState_Oldformat old_state;
READWRITE(old_state);
pdmnState = std::make_shared<const CDeterministicMNState>(old_state);
} else if (ser_action.ForRead() && format_version == MN_TYPE_FORMAT) {
CDeterministicMNState_mntype_format old_state;
READWRITE(old_state);
pdmnState = std::make_shared<const CDeterministicMNState>(old_state);
} else {
READWRITE(pdmnState);
}
Expand All @@ -97,11 +103,11 @@ class CDeterministicMN
template<typename Stream>
void Serialize(Stream& s) const
{
const_cast<CDeterministicMN*>(this)->SerializationOp(s, CSerActionSerialize(), MN_TYPE_FORMAT);
const_cast<CDeterministicMN*>(this)->SerializationOp(s, CSerActionSerialize(), MN_CURRENT_FORMAT);
}

template <typename Stream>
void Unserialize(Stream& s, const uint8_t format_version = MN_TYPE_FORMAT)
void Unserialize(Stream& s, const uint8_t format_version = MN_CURRENT_FORMAT)
{
SerializationOp(s, CSerActionUnserialize(), format_version);
}
Expand Down Expand Up @@ -203,14 +209,14 @@ class CDeterministicMNList
}

template<typename Stream>
void Unserialize(Stream& s, const uint8_t format_version = CDeterministicMN::MN_TYPE_FORMAT) {
void Unserialize(Stream& s, const uint8_t format_version = CDeterministicMN::MN_CURRENT_FORMAT) {
mnMap = MnMap();
mnUniquePropertyMap = MnUniquePropertyMap();
mnInternalIdMap = MnInternalIdMap();

SerializationOpBase(s, CSerActionUnserialize());

bool evodb_migration = (format_version == CDeterministicMN::CURRENT_MN_FORMAT);
bool evodb_migration = (format_version == CDeterministicMN::MN_OLD_FORMAT || format_version == CDeterministicMN::MN_TYPE_FORMAT);
size_t cnt = ReadCompactSize(s);
for (size_t i = 0; i < cnt; i++) {
if (evodb_migration) {
Expand Down Expand Up @@ -383,23 +389,21 @@ class CDeterministicMNList
[[nodiscard]] CDeterministicMNListDiff BuildDiff(const CDeterministicMNList& to) const;
[[nodiscard]] CDeterministicMNList ApplyDiff(const CBlockIndex* pindex, const CDeterministicMNListDiff& diff) const;

void RepopulateUniquePropertyMap();

void AddMN(const CDeterministicMNCPtr& dmn, bool fBumpTotalCount = true);
void UpdateMN(const CDeterministicMN& oldDmn, const std::shared_ptr<const CDeterministicMNState>& pdmnState);
void UpdateMN(const uint256& proTxHash, const std::shared_ptr<const CDeterministicMNState>& pdmnState);
void UpdateMN(const CDeterministicMN& oldDmn, const CDeterministicMNStateDiff& stateDiff);
void RemoveMN(const uint256& proTxHash);

template <typename T>
[[nodiscard]] bool HasUniqueProperty(const T& v) const
[[nodiscard]] bool HasUniqueProperty(const T& v, std::optional<bool> specific_legacy_bls_scheme = std::nullopt) const
{
return mnUniquePropertyMap.count(::SerializeHash(v)) != 0;
return mnUniquePropertyMap.count(GetUniquePropertyHash(v, specific_legacy_bls_scheme)) != 0;
}
template <typename T>
[[nodiscard]] CDeterministicMNCPtr GetUniquePropertyMN(const T& v) const
[[nodiscard]] CDeterministicMNCPtr GetUniquePropertyMN(const T& v, std::optional<bool> specific_legacy_bls_scheme = std::nullopt) const
{
auto p = mnUniquePropertyMap.find(::SerializeHash(v));
auto p = mnUniquePropertyMap.find(GetUniquePropertyHash(v, specific_legacy_bls_scheme));
if (!p) {
return nullptr;
}
Expand All @@ -408,14 +412,31 @@ class CDeterministicMNList

private:
template <typename T>
[[nodiscard]] bool AddUniqueProperty(const CDeterministicMN& dmn, const T& v)
[[nodiscard]] uint256 GetUniquePropertyHash(const T& v, std::optional<bool> specific_legacy_bls_scheme = std::nullopt) const
{
if constexpr (std::is_same<T, CBLSPublicKey>()) {
assert(specific_legacy_bls_scheme.has_value());
ConstCBLSPublicKeyVersionWrapper wrapped_pub_key(v, specific_legacy_bls_scheme.value());
return ::SerializeHash(wrapped_pub_key);
}
if constexpr (std::is_same<T, CBLSLazyPublicKey>()) {
assert(specific_legacy_bls_scheme.has_value());
ConstCBLSPublicKeyVersionWrapper wrapped_pub_key(v.Get(), specific_legacy_bls_scheme.value());
return ::SerializeHash(wrapped_pub_key);
}
assert(!specific_legacy_bls_scheme.has_value());
return ::SerializeHash(v);
}
template <typename T>
[[nodiscard]] bool AddUniqueProperty(const CDeterministicMN& dmn, const T& v, std::optional<bool> specific_legacy_bls_scheme = std::nullopt)
{
static const T nullValue;
if (v == nullValue) {
return false;
}

auto hash = ::SerializeHash(v);
uint256 hash = GetUniquePropertyHash(v, specific_legacy_bls_scheme);

auto oldEntry = mnUniquePropertyMap.find(hash);
if (oldEntry != nullptr && oldEntry->first != dmn.proTxHash) {
return false;
Expand All @@ -428,14 +449,15 @@ class CDeterministicMNList
return true;
}
template <typename T>
[[nodiscard]] bool DeleteUniqueProperty(const CDeterministicMN& dmn, const T& oldValue)
[[nodiscard]] bool DeleteUniqueProperty(const CDeterministicMN& dmn, const T& oldValue, std::optional<bool> specific_legacy_bls_scheme = std::nullopt)
{
static const T nullValue;
if (oldValue == nullValue) {
return false;
}

auto oldHash = ::SerializeHash(oldValue);
uint256 oldHash = GetUniquePropertyHash(oldValue, specific_legacy_bls_scheme);

auto p = mnUniquePropertyMap.find(oldHash);
if (p == nullptr || p->first != dmn.proTxHash) {
return false;
Expand All @@ -448,18 +470,18 @@ class CDeterministicMNList
return true;
}
template <typename T>
[[nodiscard]] bool UpdateUniqueProperty(const CDeterministicMN& dmn, const T& oldValue, const T& newValue)
[[nodiscard]] bool UpdateUniqueProperty(const CDeterministicMN& dmn, const T& oldValue, const T& newValue, std::optional<bool> specific_legacy_bls_scheme = std::nullopt)
{
if (oldValue == newValue) {
return true;
}
static const T nullValue;

if (oldValue != nullValue && !DeleteUniqueProperty(dmn, oldValue)) {
if (oldValue != nullValue && !DeleteUniqueProperty(dmn, oldValue, specific_legacy_bls_scheme)) {
return false;
}

if (newValue != nullValue && !AddUniqueProperty(dmn, newValue)) {
if (newValue != nullValue && !AddUniqueProperty(dmn, newValue, specific_legacy_bls_scheme)) {
return false;
}
return true;
Expand Down Expand Up @@ -492,7 +514,7 @@ class CDeterministicMNListDiff
}

template <typename Stream>
void Unserialize(Stream& s, const uint8_t format_version = CDeterministicMN::MN_TYPE_FORMAT)
void Unserialize(Stream& s, const uint8_t format_version = CDeterministicMN::MN_CURRENT_FORMAT)
{
updatedMNs.clear();
removedMns.clear();
Expand All @@ -502,8 +524,6 @@ class CDeterministicMNListDiff
tmp = ReadCompactSize(s);
for (size_t i = 0; i < tmp; i++) {
CDeterministicMN mn(0);
// Unserialise CDeterministicMN using CURRENT_MN_FORMAT and set it's type to the default value TYPE_REGULAR_MASTERNODE
// It will be later written with format MN_TYPE_FORMAT which includes the type field.
mn.Unserialize(s, format_version);
auto dmn = std::make_shared<CDeterministicMN>(mn);
addedMNs.push_back(dmn);
Expand Down Expand Up @@ -585,6 +605,7 @@ class CDeterministicMNManager
bool IsDIP3Enforced(int nHeight = -1) LOCKS_EXCLUDED(cs);

bool MigrateDBIfNeeded();
bool MigrateDBIfNeeded2();

void DoMaintenance() LOCKS_EXCLUDED(cs);

Expand Down
6 changes: 3 additions & 3 deletions src/evo/dmnstate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ std::string CDeterministicMNState::ToString() const
return strprintf("CDeterministicMNState(nRegisteredHeight=%d, nLastPaidHeight=%d, nPoSePenalty=%d, nPoSeRevivedHeight=%d, nPoSeBanHeight=%d, nRevocationReason=%d, "
"ownerAddress=%s, pubKeyOperator=%s, votingAddress=%s, addr=%s, payoutAddress=%s, operatorPayoutAddress=%s)",
nRegisteredHeight, nLastPaidHeight, nPoSePenalty, nPoSeRevivedHeight, nPoSeBanHeight, nRevocationReason,
EncodeDestination(PKHash(keyIDOwner)), pubKeyOperator.Get().ToString(), EncodeDestination(PKHash(keyIDVoting)), addr.ToStringIPPort(false), payoutAddress, operatorPayoutAddress);
EncodeDestination(PKHash(keyIDOwner)), pubKeyOperator.Get().ToString(nVersion == CProRegTx::LEGACY_BLS_VERSION), EncodeDestination(PKHash(keyIDVoting)), addr.ToStringIPPort(false), payoutAddress, operatorPayoutAddress);
}

void CDeterministicMNState::ToJson(UniValue& obj, MnType nType) const
Expand All @@ -55,7 +55,7 @@ void CDeterministicMNState::ToJson(UniValue& obj, MnType nType) const
if (ExtractDestination(scriptPayout, dest)) {
obj.pushKV("payoutAddress", EncodeDestination(dest));
}
obj.pushKV("pubKeyOperator", pubKeyOperator.Get().ToString());
obj.pushKV("pubKeyOperator", pubKeyOperator.Get().ToString(nVersion == CProRegTx::LEGACY_BLS_VERSION));
if (ExtractDestination(scriptOperatorPayout, dest)) {
obj.pushKV("operatorPayoutAddress", EncodeDestination(dest));
}
Expand Down Expand Up @@ -108,7 +108,7 @@ void CDeterministicMNStateDiff::ToJson(UniValue& obj, MnType nType) const
}
}
if (fields & Field_pubKeyOperator) {
obj.pushKV("pubKeyOperator", state.pubKeyOperator.Get().ToString());
obj.pushKV("pubKeyOperator", state.pubKeyOperator.Get().ToString(state.nVersion == CProRegTx::LEGACY_BLS_VERSION));
}
if (nType == MnType::HighPerformance) {
if (fields & Field_platformNodeID) {
Expand Down
101 changes: 95 additions & 6 deletions src/evo/dmnstate.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,76 @@ class CDeterministicMNState_Oldformat
obj.nRevocationReason,
obj.confirmedHash,
obj.confirmedHashWithProRegTxHash,
obj.keyIDOwner,
obj.pubKeyOperator,
obj.keyIDOwner);
// NOTE: make sure we can read it if we are migrating after v19 hf
READWRITE(CBLSLazyPublicKeyVersionWrapper(const_cast<CBLSLazyPublicKey&>(obj.pubKeyOperator), true));
READWRITE(
obj.keyIDVoting,
obj.addr,
obj.scriptPayout,
obj.scriptOperatorPayout);
}
};

// TODO: To remove this in the future
class CDeterministicMNState_mntype_format
{
private:
int nPoSeBanHeight{-1};

friend class CDeterministicMNStateDiff;
friend class CDeterministicMNState;

public:
int nRegisteredHeight{-1};
int nLastPaidHeight{0};
int nConsecutivePayments{0};
int nPoSePenalty{0};
int nPoSeRevivedHeight{-1};
uint16_t nRevocationReason{CProUpRevTx::REASON_NOT_SPECIFIED};
uint256 confirmedHash;
uint256 confirmedHashWithProRegTxHash;
CKeyID keyIDOwner;
CBLSLazyPublicKey pubKeyOperator;
CKeyID keyIDVoting;
CService addr;
CScript scriptPayout;
CScript scriptOperatorPayout;

uint160 platformNodeID{};
uint16_t platformP2PPort{0};
uint16_t platformHTTPPort{0};

public:
CDeterministicMNState_mntype_format() = default;

SERIALIZE_METHODS(CDeterministicMNState_mntype_format, obj)
{
READWRITE(
obj.nRegisteredHeight,
obj.nLastPaidHeight,
obj.nConsecutivePayments,
obj.nPoSePenalty,
obj.nPoSeRevivedHeight,
obj.nPoSeBanHeight,
obj.nRevocationReason,
obj.confirmedHash,
obj.confirmedHashWithProRegTxHash,
obj.keyIDOwner);
// NOTE: we can't read it if we are migrating after v19 hf
// prior to v19 hf all pubkeys were using legacy mode, so try our best here
READWRITE(CBLSLazyPublicKeyVersionWrapper(const_cast<CBLSLazyPublicKey&>(obj.pubKeyOperator), true));
READWRITE(
obj.keyIDVoting,
obj.addr,
obj.scriptPayout,
obj.scriptOperatorPayout,
obj.platformNodeID,
obj.platformP2PPort,
obj.platformHTTPPort);
}
};

class CDeterministicMNState
{
private:
Expand All @@ -80,6 +141,8 @@ class CDeterministicMNState
friend class CDeterministicMNStateDiff;

public:
int nVersion{CProRegTx::LEGACY_BLS_VERSION};

int nRegisteredHeight{-1};
int nLastPaidHeight{0};
int nConsecutivePayments{0};
Expand Down Expand Up @@ -107,6 +170,7 @@ class CDeterministicMNState
public:
CDeterministicMNState() = default;
explicit CDeterministicMNState(const CProRegTx& proTx) :
nVersion(proTx.nVersion),
keyIDOwner(proTx.keyIDOwner),
keyIDVoting(proTx.keyIDVoting),
addr(proTx.addr),
Expand All @@ -132,6 +196,27 @@ class CDeterministicMNState
addr(s.addr),
scriptPayout(s.scriptPayout),
scriptOperatorPayout(s.scriptOperatorPayout) {}

explicit CDeterministicMNState(const CDeterministicMNState_mntype_format& s) :
nPoSeBanHeight(s.nPoSeBanHeight),
nRegisteredHeight(s.nRegisteredHeight),
nLastPaidHeight(s.nLastPaidHeight),
nConsecutivePayments(s.nConsecutivePayments),
nPoSePenalty(s.nPoSePenalty),
nPoSeRevivedHeight(s.nPoSeRevivedHeight),
nRevocationReason(s.nRevocationReason),
confirmedHash(s.confirmedHash),
confirmedHashWithProRegTxHash(s.confirmedHashWithProRegTxHash),
keyIDOwner(s.keyIDOwner),
pubKeyOperator(s.pubKeyOperator),
keyIDVoting(s.keyIDVoting),
addr(s.addr),
scriptPayout(s.scriptPayout),
scriptOperatorPayout(s.scriptOperatorPayout),
platformNodeID(s.platformNodeID),
platformP2PPort(s.platformP2PPort),
platformHTTPPort(s.platformHTTPPort) {}

template <typename Stream>
CDeterministicMNState(deserialize_type, Stream& s)
{
Expand All @@ -141,6 +226,7 @@ class CDeterministicMNState
SERIALIZE_METHODS(CDeterministicMNState, obj)
{
READWRITE(
obj.nVersion,
obj.nRegisteredHeight,
obj.nLastPaidHeight,
obj.nConsecutivePayments,
Expand All @@ -151,7 +237,9 @@ class CDeterministicMNState
obj.confirmedHash,
obj.confirmedHashWithProRegTxHash,
obj.keyIDOwner,
obj.pubKeyOperator,
obj.keyIDOwner);
READWRITE(CBLSLazyPublicKeyVersionWrapper(const_cast<CBLSLazyPublicKey&>(obj.pubKeyOperator), obj.nVersion == CProRegTx::LEGACY_BLS_VERSION));
READWRITE(
obj.keyIDVoting,
obj.addr,
obj.scriptPayout,
Expand Down Expand Up @@ -225,6 +313,7 @@ class CDeterministicMNStateDiff
Field_platformNodeID = 0x8000,
Field_platformP2PPort = 0x10000,
Field_platformHTTPPort = 0x20000,
Field_nVersion = 0x40000,
};

#define DMN_STATE_DIFF_ALL_FIELDS \
Expand All @@ -245,7 +334,8 @@ class CDeterministicMNStateDiff
DMN_STATE_DIFF_LINE(nConsecutivePayments) \
DMN_STATE_DIFF_LINE(platformNodeID) \
DMN_STATE_DIFF_LINE(platformP2PPort) \
DMN_STATE_DIFF_LINE(platformHTTPPort)
DMN_STATE_DIFF_LINE(platformHTTPPort) \
DMN_STATE_DIFF_LINE(nVersion)

public:
uint32_t fields{0};
Expand All @@ -268,8 +358,7 @@ class CDeterministicMNStateDiff
READWRITE(VARINT(obj.fields));
#define DMN_STATE_DIFF_LINE(f) \
if (strcmp(#f, "pubKeyOperator") == 0 && (obj.fields & Field_pubKeyOperator)) {\
/* TODO: implement migration to Basic BLS after the fork */ \
READWRITE(CBLSLazyPublicKeyVersionWrapper(const_cast<CBLSLazyPublicKey&>(obj.state.pubKeyOperator), true)); \
READWRITE(CBLSLazyPublicKeyVersionWrapper(const_cast<CBLSLazyPublicKey&>(obj.state.pubKeyOperator), obj.state.nVersion == CProRegTx::LEGACY_BLS_VERSION)); \
} else if (obj.fields & Field_##f) READWRITE(obj.state.f);

DMN_STATE_DIFF_ALL_FIELDS
Expand Down
3 changes: 2 additions & 1 deletion src/evo/evodb.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
// "b_b" was used in the initial version of deterministic MN storage
// "b_b2" was used after compact diffs were introduced
// "b_b3" was used after masternode type introduction in evoDB
static const std::string EVODB_BEST_BLOCK = "b_b3";
// "b_b4" was used after storing protx version for each masternode in evoDB
static const std::string EVODB_BEST_BLOCK = "b_b4";

class CEvoDB;

Expand Down
Loading