mirror of
https://github.com/dashpay/dash.git
synced 2024-12-24 19:42:46 +01:00
fix: Resolve mainnet v19 fork issues (#5403)
same as #5392, alternative solution ~based on #5402 atm, will rebase later~ pls see individual commits reorg mainnet around forkpoint with a patched client (to allow low difficulty), run tests Another evodb migration is required. Going back to an older version or migrating after the fork requires reindexing. - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas - [ ] I have added or updated relevant unit/integration/functional/e2e tests - [ ] I have made corresponding changes to the documentation - [x] I have assigned this pull request to a milestone _(for repository code-owners and collaborators only)_
This commit is contained in:
parent
35ccc8500c
commit
e0175b28d7
@ -418,10 +418,7 @@ public:
|
||||
CBLSLazyWrapper() :
|
||||
vecBytes(BLSObject::SerSize, 0),
|
||||
bufLegacyScheme(bls::bls_legacy_scheme.load())
|
||||
{
|
||||
// the all-zero buf is considered a valid buf, but the resulting object will return false for IsValid
|
||||
bufValid = true;
|
||||
}
|
||||
{}
|
||||
|
||||
explicit CBLSLazyWrapper(const CBLSLazyWrapper& r)
|
||||
{
|
||||
@ -459,12 +456,8 @@ public:
|
||||
{
|
||||
std::unique_lock<std::mutex> l(mutex);
|
||||
if (!objInitialized && !bufValid) {
|
||||
// the all-zero buf is considered a valid buf
|
||||
std::fill(vecBytes.begin(), vecBytes.end(), 0);
|
||||
bufLegacyScheme = specificLegacyScheme;
|
||||
bufValid = true;
|
||||
}
|
||||
if (!bufValid || (bufLegacyScheme != specificLegacyScheme)) {
|
||||
} else if (!bufValid || (bufLegacyScheme != specificLegacyScheme)) {
|
||||
vecBytes = obj.ToByteVector(specificLegacyScheme);
|
||||
bufValid = true;
|
||||
bufLegacyScheme = specificLegacyScheme;
|
||||
@ -476,7 +469,7 @@ public:
|
||||
template<typename Stream>
|
||||
inline void Serialize(Stream& s) const
|
||||
{
|
||||
Serialize(s, bls::bls_legacy_scheme.load());
|
||||
Serialize(s, bufLegacyScheme);
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
@ -493,13 +486,14 @@ public:
|
||||
template<typename Stream>
|
||||
inline void Unserialize(Stream& s) const
|
||||
{
|
||||
Unserialize(s, bls::bls_legacy_scheme.load());
|
||||
Unserialize(s, bufLegacyScheme);
|
||||
}
|
||||
|
||||
void Set(const BLSObject& _obj)
|
||||
void Set(const BLSObject& _obj, const bool specificLegacyScheme)
|
||||
{
|
||||
std::unique_lock<std::mutex> l(mutex);
|
||||
bufValid = false;
|
||||
bufLegacyScheme = specificLegacyScheme;
|
||||
objInitialized = true;
|
||||
obj = _obj;
|
||||
hash.SetNull();
|
||||
@ -549,13 +543,15 @@ public:
|
||||
return !(*this == r);
|
||||
}
|
||||
|
||||
uint256 GetHash(const bool specificLegacyScheme = bls::bls_legacy_scheme.load()) const
|
||||
uint256 GetHash() const
|
||||
{
|
||||
std::unique_lock<std::mutex> l(mutex);
|
||||
if (!bufValid || bufLegacyScheme != specificLegacyScheme) {
|
||||
vecBytes = obj.ToByteVector(specificLegacyScheme);
|
||||
if (!objInitialized && !bufValid) {
|
||||
std::fill(vecBytes.begin(), vecBytes.end(), 0);
|
||||
hash.SetNull();
|
||||
} else if (!bufValid) {
|
||||
vecBytes = obj.ToByteVector(bufLegacyScheme);
|
||||
bufValid = true;
|
||||
bufLegacyScheme = specificLegacyScheme;
|
||||
hash.SetNull();
|
||||
}
|
||||
if (hash.IsNull()) {
|
||||
@ -565,6 +561,11 @@ public:
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
std::string ToString() const
|
||||
{
|
||||
return Get().ToString(bufLegacyScheme);
|
||||
}
|
||||
};
|
||||
using CBLSLazySignature = CBLSLazyWrapper<CBLSSignature>;
|
||||
using CBLSLazyPublicKey = CBLSLazyWrapper<CBLSPublicKey>;
|
||||
|
@ -25,8 +25,8 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
static const std::string DB_LIST_SNAPSHOT = "dmn_S2";
|
||||
static const std::string DB_LIST_DIFF = "dmn_D2";
|
||||
static const std::string DB_LIST_SNAPSHOT = "dmn_S3";
|
||||
static const std::string DB_LIST_DIFF = "dmn_D3";
|
||||
|
||||
std::unique_ptr<CDeterministicMNManager> deterministicMNManager;
|
||||
|
||||
@ -463,48 +463,6 @@ CDeterministicMNList CDeterministicMNList::ApplyDiff(const CBlockIndex* pindex,
|
||||
return result;
|
||||
}
|
||||
|
||||
// RepopulateUniquePropertyMap clears internal mnUniquePropertyMap, and repopulate it with currently MNs unique properties.
|
||||
// This is needed when the v19 fork activates, we need to store again pubKeyOperator in the mnUniquePropertyMap.
|
||||
// pubKeyOperator don't differ between the two schemes (legacy and basic(v19)) but their serialisation do: hence their hash.
|
||||
// And because mnUniquePropertyMap store only hashes, then we need to re-calculate hashes and repopulate.
|
||||
void CDeterministicMNList::RepopulateUniquePropertyMap() {
|
||||
decltype(mnUniquePropertyMap) mnUniquePropertyMapEmpty;
|
||||
mnUniquePropertyMap = mnUniquePropertyMapEmpty;
|
||||
|
||||
for (const auto &p: mnMap) {
|
||||
auto dmn = p.second;
|
||||
if (!AddUniqueProperty(*dmn, dmn->collateralOutpoint)) {
|
||||
throw (std::runtime_error(
|
||||
strprintf("%s: Can't add a masternode %s with a duplicate collateralOutpoint=%s", __func__,
|
||||
dmn->proTxHash.ToString(), dmn->collateralOutpoint.ToStringShort())));
|
||||
}
|
||||
if (dmn->pdmnState->addr != CService() && !AddUniqueProperty(*dmn, dmn->pdmnState->addr)) {
|
||||
throw (std::runtime_error(strprintf("%s: Can't add a masternode %s with a duplicate address=%s", __func__,
|
||||
dmn->proTxHash.ToString(),
|
||||
dmn->pdmnState->addr.ToStringIPPort(false))));
|
||||
}
|
||||
if (!AddUniqueProperty(*dmn, dmn->pdmnState->keyIDOwner)) {
|
||||
throw (std::runtime_error(
|
||||
strprintf("%s: Can't add a masternode %s with a duplicate keyIDOwner=%s", __func__,
|
||||
dmn->proTxHash.ToString(), EncodeDestination(PKHash(dmn->pdmnState->keyIDOwner)))));
|
||||
}
|
||||
if (dmn->pdmnState->pubKeyOperator.Get().IsValid() &&
|
||||
!AddUniqueProperty(*dmn, dmn->pdmnState->pubKeyOperator)) {
|
||||
throw (std::runtime_error(
|
||||
strprintf("%s: Can't add a masternode %s with a duplicate pubKeyOperator=%s", __func__,
|
||||
dmn->proTxHash.ToString(), dmn->pdmnState->pubKeyOperator.Get().ToString())));
|
||||
}
|
||||
|
||||
if (dmn->nType == MnType::HighPerformance) {
|
||||
if (!AddUniqueProperty(*dmn, dmn->pdmnState->platformNodeID)) {
|
||||
throw (std::runtime_error(
|
||||
strprintf("%s: Can't add a masternode %s with a duplicate platformNodeID=%s", __func__,
|
||||
dmn->proTxHash.ToString(), dmn->pdmnState->platformNodeID.ToString())));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CDeterministicMNList::AddMN(const CDeterministicMNCPtr& dmn, bool fBumpTotalCount)
|
||||
{
|
||||
assert(dmn != nullptr);
|
||||
@ -538,7 +496,7 @@ void CDeterministicMNList::AddMN(const CDeterministicMNCPtr& dmn, bool fBumpTota
|
||||
if (dmn->pdmnState->pubKeyOperator.Get().IsValid() && !AddUniqueProperty(*dmn, dmn->pdmnState->pubKeyOperator)) {
|
||||
mnUniquePropertyMap = mnUniquePropertyMapSaved;
|
||||
throw(std::runtime_error(strprintf("%s: Can't add a masternode %s with a duplicate pubKeyOperator=%s", __func__,
|
||||
dmn->proTxHash.ToString(), dmn->pdmnState->pubKeyOperator.Get().ToString())));
|
||||
dmn->proTxHash.ToString(), dmn->pdmnState->pubKeyOperator.ToString())));
|
||||
}
|
||||
|
||||
if (dmn->nType == MnType::HighPerformance) {
|
||||
@ -580,7 +538,7 @@ void CDeterministicMNList::UpdateMN(const CDeterministicMN& oldDmn, const std::s
|
||||
if (!UpdateUniqueProperty(*dmn, oldState->pubKeyOperator, pdmnState->pubKeyOperator)) {
|
||||
mnUniquePropertyMap = mnUniquePropertyMapSaved;
|
||||
throw(std::runtime_error(strprintf("%s: Can't update a masternode %s with a duplicate pubKeyOperator=%s", __func__,
|
||||
oldDmn.proTxHash.ToString(), pdmnState->pubKeyOperator.Get().ToString())));
|
||||
oldDmn.proTxHash.ToString(), pdmnState->pubKeyOperator.ToString())));
|
||||
}
|
||||
if (dmn->nType == MnType::HighPerformance) {
|
||||
if (!UpdateUniqueProperty(*dmn, oldState->platformNodeID, dmn->pdmnState->platformNodeID)) {
|
||||
@ -639,7 +597,7 @@ void CDeterministicMNList::RemoveMN(const uint256& proTxHash)
|
||||
if (dmn->pdmnState->pubKeyOperator.Get().IsValid() && !DeleteUniqueProperty(*dmn, dmn->pdmnState->pubKeyOperator)) {
|
||||
mnUniquePropertyMap = mnUniquePropertyMapSaved;
|
||||
throw(std::runtime_error(strprintf("%s: Can't delete a masternode %s with a pubKeyOperator=%s", __func__,
|
||||
proTxHash.ToString(), dmn->pdmnState->pubKeyOperator.Get().ToString())));
|
||||
proTxHash.ToString(), dmn->pdmnState->pubKeyOperator.ToString())));
|
||||
}
|
||||
|
||||
if (dmn->nType == MnType::HighPerformance) {
|
||||
@ -687,17 +645,14 @@ bool CDeterministicMNManager::ProcessBlock(const CBlock& block, const CBlockInde
|
||||
|
||||
newList.SetBlockHash(block.GetHash());
|
||||
|
||||
// If the fork is active for pindex block, then we need to repopulate property map
|
||||
// (Check documentation of CDeterministicMNList::RepopulateUniquePropertyMap()).
|
||||
// This is needed only when base list is pre-v19 fork and pindex is post-v19 fork.
|
||||
bool v19_just_activated = pindex == llmq::utils::V19ActivationIndex(pindex);
|
||||
if (v19_just_activated) {
|
||||
newList.RepopulateUniquePropertyMap();
|
||||
}
|
||||
|
||||
oldList = GetListForBlock(pindex->pprev);
|
||||
diff = oldList.BuildDiff(newList);
|
||||
|
||||
// NOTE: The block next to the activation is the one that is using new rules.
|
||||
// If the fork was activated at pindex->prev block then current one is the first one
|
||||
// using new rules. Save mn list snapsot for this block.
|
||||
bool v19_just_activated = pindex->pprev == llmq::utils::V19ActivationIndex(pindex);
|
||||
|
||||
m_evoDb.Write(std::make_pair(DB_LIST_DIFF, newList.GetBlockHash()), diff);
|
||||
if ((nHeight % DISK_SNAPSHOT_PERIOD) == 0 || oldList.GetHeight() == -1 || v19_just_activated) {
|
||||
m_evoDb.Write(std::make_pair(DB_LIST_SNAPSHOT, newList.GetBlockHash()), newList);
|
||||
@ -940,12 +895,12 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
|
||||
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-protx-hash");
|
||||
}
|
||||
auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
|
||||
if (newState->pubKeyOperator.Get() != proTx.pubKeyOperator) {
|
||||
if (newState->pubKeyOperator != proTx.pubKeyOperator) {
|
||||
// reset all operator related fields and put MN into PoSe-banned state in case the operator key changes
|
||||
newState->ResetOperatorFields();
|
||||
newState->BanIfNotBanned(nHeight);
|
||||
}
|
||||
newState->pubKeyOperator.Set(proTx.pubKeyOperator);
|
||||
newState->pubKeyOperator = proTx.pubKeyOperator;
|
||||
newState->keyIDVoting = proTx.keyIDVoting;
|
||||
newState->scriptPayout = proTx.scriptPayout;
|
||||
|
||||
@ -1266,6 +1221,7 @@ bool CDeterministicMNManager::MigrateDBIfNeeded()
|
||||
static const std::string DB_OLD_LIST_SNAPSHOT = "dmn_S";
|
||||
static const std::string DB_OLD_LIST_DIFF = "dmn_D";
|
||||
static const std::string DB_OLD_BEST_BLOCK = "b_b2";
|
||||
static const std::string DB_OLD_BEST_BLOCK2 = "b_b3";
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
@ -1277,11 +1233,17 @@ bool CDeterministicMNManager::MigrateDBIfNeeded()
|
||||
return m_evoDb.IsEmpty();
|
||||
}
|
||||
|
||||
if (m_evoDb.GetRawDB().Exists(EVODB_BEST_BLOCK)) {
|
||||
if (m_evoDb.GetRawDB().Exists(EVODB_BEST_BLOCK) || m_evoDb.GetRawDB().Exists(DB_OLD_BEST_BLOCK2)) {
|
||||
LogPrintf("CDeterministicMNManager::%s -- migration already done. skipping.\n", __func__);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (::ChainActive().Tip()->pprev != nullptr && llmq::utils::IsV19Active(::ChainActive().Tip()->pprev)) {
|
||||
// too late
|
||||
LogPrintf("CDeterministicMNManager::%s -- migration is not possible\n", __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Removing the old EVODB_BEST_BLOCK value early results in older version to crash immediately, even if the upgrade
|
||||
// process is cancelled in-between. But if the new version sees that the old EVODB_BEST_BLOCK is already removed,
|
||||
// then we must assume that the upgrade process was already running before but was interrupted.
|
||||
@ -1304,15 +1266,15 @@ bool CDeterministicMNManager::MigrateDBIfNeeded()
|
||||
|
||||
for (const auto nHeight : irange::range(Params().GetConsensus().DIP0003Height, ::ChainActive().Height() + 1)) {
|
||||
auto pindex = ::ChainActive()[nHeight];
|
||||
// Unserialise CDeterministicMNListDiff 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.
|
||||
// Unserialise CDeterministicMNListDiff using MN_OLD_FORMAT and set it's type to the default value TYPE_REGULAR_MASTERNODE
|
||||
// It will be later written with format MN_CURRENT_FORMAT which includes the type field and MN state bls version.
|
||||
CDataStream diff_data(SER_DISK, CLIENT_VERSION);
|
||||
if (!m_evoDb.GetRawDB().ReadDataStream(std::make_pair(DB_OLD_LIST_DIFF, pindex->GetBlockHash()), diff_data)) {
|
||||
LogPrintf("CDeterministicMNManager::%s -- missing CDeterministicMNListDiff at height %d\n", __func__, nHeight);
|
||||
return false;
|
||||
}
|
||||
CDeterministicMNListDiff mndiff;
|
||||
mndiff.Unserialize(diff_data, CDeterministicMN::CURRENT_MN_FORMAT);
|
||||
mndiff.Unserialize(diff_data, CDeterministicMN::MN_OLD_FORMAT);
|
||||
batch.Write(std::make_pair(DB_LIST_DIFF, pindex->GetBlockHash()), mndiff);
|
||||
CDataStream snapshot_data(SER_DISK, CLIENT_VERSION);
|
||||
if (!m_evoDb.GetRawDB().ReadDataStream(std::make_pair(DB_OLD_LIST_SNAPSHOT, pindex->GetBlockHash()), snapshot_data)) {
|
||||
@ -1320,7 +1282,7 @@ bool CDeterministicMNManager::MigrateDBIfNeeded()
|
||||
continue;
|
||||
}
|
||||
CDeterministicMNList mnList;
|
||||
mnList.Unserialize(snapshot_data, CDeterministicMN::CURRENT_MN_FORMAT);
|
||||
mnList.Unserialize(snapshot_data, CDeterministicMN::MN_OLD_FORMAT);
|
||||
batch.Write(std::make_pair(DB_LIST_SNAPSHOT, pindex->GetBlockHash()), mnList);
|
||||
m_evoDb.GetRawDB().WriteBatch(batch);
|
||||
batch.Clear();
|
||||
@ -1329,7 +1291,7 @@ bool CDeterministicMNManager::MigrateDBIfNeeded()
|
||||
|
||||
m_evoDb.GetRawDB().WriteBatch(batch);
|
||||
|
||||
// Writing EVODB_BEST_BLOCK (which is b_b3 now) marks the DB as upgraded
|
||||
// Writing EVODB_BEST_BLOCK (which is b_b4 now) marks the DB as upgraded
|
||||
auto dbTx = m_evoDb.BeginTransaction();
|
||||
m_evoDb.WriteBestBlock(::ChainActive().Tip()->GetBlockHash());
|
||||
dbTx->Commit();
|
||||
@ -1345,6 +1307,111 @@ bool CDeterministicMNManager::MigrateDBIfNeeded()
|
||||
|
||||
LogPrintf("CDeterministicMNManager::%s -- done compacting database\n", __func__);
|
||||
|
||||
// flush it to disk
|
||||
if (!m_evoDb.CommitRootTransaction()) {
|
||||
LogPrintf("CDeterministicMNManager::%s -- failed to commit to evoDB\n", __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDeterministicMNManager::MigrateDBIfNeeded2()
|
||||
{
|
||||
static const std::string DB_OLD_LIST_SNAPSHOT = "dmn_S2";
|
||||
static const std::string DB_OLD_LIST_DIFF = "dmn_D2";
|
||||
static const std::string DB_OLD_BEST_BLOCK = "b_b3";
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
LogPrintf("CDeterministicMNManager::%s -- upgrading DB to migrate MN state bls version\n", __func__);
|
||||
|
||||
if (::ChainActive().Tip() == nullptr) {
|
||||
// should have no records
|
||||
LogPrintf("CDeterministicMNManager::%s -- Chain empty. evoDB:%d.\n", __func__, m_evoDb.IsEmpty());
|
||||
return m_evoDb.IsEmpty();
|
||||
}
|
||||
|
||||
if (m_evoDb.GetRawDB().Exists(EVODB_BEST_BLOCK)) {
|
||||
LogPrintf("CDeterministicMNManager::%s -- migration already done. skipping.\n", __func__);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (::ChainActive().Tip()->pprev != nullptr && llmq::utils::IsV19Active(::ChainActive().Tip()->pprev)) {
|
||||
// too late
|
||||
LogPrintf("CDeterministicMNManager::%s -- migration is not possible\n", __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Removing the old EVODB_BEST_BLOCK value early results in older version to crash immediately, even if the upgrade
|
||||
// process is cancelled in-between. But if the new version sees that the old EVODB_BEST_BLOCK is already removed,
|
||||
// then we must assume that the upgrade process was already running before but was interrupted.
|
||||
if (::ChainActive().Height() > 1 && !m_evoDb.GetRawDB().Exists(DB_OLD_BEST_BLOCK)) {
|
||||
LogPrintf("CDeterministicMNManager::%s -- previous migration attempt failed.\n", __func__);
|
||||
return false;
|
||||
}
|
||||
m_evoDb.GetRawDB().Erase(DB_OLD_BEST_BLOCK);
|
||||
|
||||
if (::ChainActive().Height() < Params().GetConsensus().DIP0003Height) {
|
||||
// not reached DIP3 height yet, so no upgrade needed
|
||||
LogPrintf("CDeterministicMNManager::%s -- migration not needed. dip3 not reached\n", __func__);
|
||||
auto dbTx = m_evoDb.BeginTransaction();
|
||||
m_evoDb.WriteBestBlock(::ChainActive().Tip()->GetBlockHash());
|
||||
dbTx->Commit();
|
||||
return true;
|
||||
}
|
||||
|
||||
CDBBatch batch(m_evoDb.GetRawDB());
|
||||
|
||||
for (const auto nHeight : irange::range(Params().GetConsensus().DIP0003Height, ::ChainActive().Height() + 1)) {
|
||||
auto pindex = ::ChainActive()[nHeight];
|
||||
// Unserialise CDeterministicMNListDiff using MN_TYPE_FORMAT and set MN state bls version to LEGACY_BLS_VERSION.
|
||||
// It will be later written with format MN_CURRENT_FORMAT which includes the type field.
|
||||
CDataStream diff_data(SER_DISK, CLIENT_VERSION);
|
||||
if (!m_evoDb.GetRawDB().ReadDataStream(std::make_pair(DB_OLD_LIST_DIFF, pindex->GetBlockHash()), diff_data)) {
|
||||
LogPrintf("CDeterministicMNManager::%s -- missing CDeterministicMNListDiff at height %d\n", __func__, nHeight);
|
||||
return false;
|
||||
}
|
||||
CDeterministicMNListDiff mndiff;
|
||||
mndiff.Unserialize(diff_data, CDeterministicMN::MN_TYPE_FORMAT);
|
||||
batch.Write(std::make_pair(DB_LIST_DIFF, pindex->GetBlockHash()), mndiff);
|
||||
CDataStream snapshot_data(SER_DISK, CLIENT_VERSION);
|
||||
if (!m_evoDb.GetRawDB().ReadDataStream(std::make_pair(DB_OLD_LIST_SNAPSHOT, pindex->GetBlockHash()), snapshot_data)) {
|
||||
// it's ok, we write snapshots every DISK_SNAPSHOT_PERIOD blocks only
|
||||
continue;
|
||||
}
|
||||
CDeterministicMNList mnList;
|
||||
mnList.Unserialize(snapshot_data, CDeterministicMN::MN_TYPE_FORMAT);
|
||||
batch.Write(std::make_pair(DB_LIST_SNAPSHOT, pindex->GetBlockHash()), mnList);
|
||||
m_evoDb.GetRawDB().WriteBatch(batch);
|
||||
batch.Clear();
|
||||
LogPrintf("CDeterministicMNManager::%s -- wrote snapshot at height %d\n", __func__, nHeight);
|
||||
}
|
||||
|
||||
m_evoDb.GetRawDB().WriteBatch(batch);
|
||||
|
||||
// Writing EVODB_BEST_BLOCK (which is b_b4 now) marks the DB as upgraded
|
||||
auto dbTx = m_evoDb.BeginTransaction();
|
||||
m_evoDb.WriteBestBlock(::ChainActive().Tip()->GetBlockHash());
|
||||
dbTx->Commit();
|
||||
|
||||
LogPrintf("CDeterministicMNManager::%s -- done migrating\n", __func__);
|
||||
|
||||
m_evoDb.GetRawDB().Erase(DB_OLD_LIST_DIFF);
|
||||
m_evoDb.GetRawDB().Erase(DB_OLD_LIST_SNAPSHOT);
|
||||
|
||||
LogPrintf("CDeterministicMNManager::%s -- done cleaning old data\n", __func__);
|
||||
|
||||
m_evoDb.GetRawDB().CompactFull();
|
||||
|
||||
LogPrintf("CDeterministicMNManager::%s -- done compacting database\n", __func__);
|
||||
|
||||
// flush it to disk
|
||||
if (!m_evoDb.CommitRootTransaction()) {
|
||||
LogPrintf("CDeterministicMNManager::%s -- failed to commit to evoDB\n", __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -43,8 +43,10 @@ private:
|
||||
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;
|
||||
|
||||
CDeterministicMN() = delete; // no default constructor, must specify internalId
|
||||
explicit CDeterministicMN(uint64_t _internalId, MnType mnType = MnType::Regular) :
|
||||
@ -74,12 +76,16 @@ public:
|
||||
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);
|
||||
}
|
||||
@ -98,11 +104,11 @@ public:
|
||||
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);
|
||||
}
|
||||
@ -204,14 +210,14 @@ public:
|
||||
}
|
||||
|
||||
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) {
|
||||
@ -385,8 +391,6 @@ public:
|
||||
[[nodiscard]] CSimplifiedMNListDiff BuildSimplifiedDiff(const CDeterministicMNList& to, bool extended) 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);
|
||||
@ -396,12 +400,12 @@ public:
|
||||
template <typename T>
|
||||
[[nodiscard]] bool HasUniqueProperty(const T& v) const
|
||||
{
|
||||
return mnUniquePropertyMap.count(::SerializeHash(v)) != 0;
|
||||
return mnUniquePropertyMap.count(GetUniquePropertyHash(v)) != 0;
|
||||
}
|
||||
template <typename T>
|
||||
[[nodiscard]] CDeterministicMNCPtr GetUniquePropertyMN(const T& v) const
|
||||
{
|
||||
auto p = mnUniquePropertyMap.find(::SerializeHash(v));
|
||||
auto p = mnUniquePropertyMap.find(GetUniquePropertyHash(v));
|
||||
if (!p) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -409,6 +413,14 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
[[nodiscard]] uint256 GetUniquePropertyHash(const T& v) const
|
||||
{
|
||||
if constexpr (std::is_same<T, CBLSPublicKey>()) {
|
||||
assert(false);
|
||||
}
|
||||
return ::SerializeHash(v);
|
||||
}
|
||||
template <typename T>
|
||||
[[nodiscard]] bool AddUniqueProperty(const CDeterministicMN& dmn, const T& v)
|
||||
{
|
||||
@ -417,7 +429,7 @@ private:
|
||||
return false;
|
||||
}
|
||||
|
||||
auto hash = ::SerializeHash(v);
|
||||
auto hash = GetUniquePropertyHash(v);
|
||||
auto oldEntry = mnUniquePropertyMap.find(hash);
|
||||
if (oldEntry != nullptr && oldEntry->first != dmn.proTxHash) {
|
||||
return false;
|
||||
@ -437,7 +449,7 @@ private:
|
||||
return false;
|
||||
}
|
||||
|
||||
auto oldHash = ::SerializeHash(oldValue);
|
||||
auto oldHash = GetUniquePropertyHash(oldValue);
|
||||
auto p = mnUniquePropertyMap.find(oldHash);
|
||||
if (p == nullptr || p->first != dmn.proTxHash) {
|
||||
return false;
|
||||
@ -466,6 +478,16 @@ private:
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
friend bool operator==(const CDeterministicMNList& a, const CDeterministicMNList& b)
|
||||
{
|
||||
return a.blockHash == b.blockHash &&
|
||||
a.nHeight == b.nHeight &&
|
||||
a.nTotalRegisteredCount == b.nTotalRegisteredCount &&
|
||||
a.mnMap == b.mnMap &&
|
||||
a.mnInternalIdMap == b.mnInternalIdMap &&
|
||||
a.mnUniquePropertyMap == b.mnUniquePropertyMap;
|
||||
}
|
||||
};
|
||||
|
||||
class CDeterministicMNListDiff
|
||||
@ -494,7 +516,7 @@ public:
|
||||
}
|
||||
|
||||
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();
|
||||
@ -504,8 +526,6 @@ public:
|
||||
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);
|
||||
@ -594,6 +614,7 @@ public:
|
||||
bool IsDIP3Enforced(int nHeight = -1);
|
||||
|
||||
bool MigrateDBIfNeeded();
|
||||
bool MigrateDBIfNeeded2();
|
||||
|
||||
void DoMaintenance();
|
||||
|
||||
|
@ -29,7 +29,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.ToString(), EncodeDestination(PKHash(keyIDVoting)), addr.ToStringIPPort(false), payoutAddress, operatorPayoutAddress);
|
||||
}
|
||||
|
||||
void CDeterministicMNState::ToJson(UniValue& obj, MnType nType) const
|
||||
@ -56,7 +56,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.ToString());
|
||||
if (ExtractDestination(scriptOperatorPayout, dest)) {
|
||||
obj.pushKV("operatorPayoutAddress", EncodeDestination(dest));
|
||||
}
|
||||
|
@ -72,6 +72,62 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// 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,
|
||||
obj.pubKeyOperator,
|
||||
obj.keyIDVoting,
|
||||
obj.addr,
|
||||
obj.scriptPayout,
|
||||
obj.scriptOperatorPayout,
|
||||
obj.platformNodeID,
|
||||
obj.platformP2PPort,
|
||||
obj.platformHTTPPort);
|
||||
}
|
||||
};
|
||||
|
||||
class CDeterministicMNState
|
||||
{
|
||||
private:
|
||||
@ -80,6 +136,8 @@ private:
|
||||
friend class CDeterministicMNStateDiff;
|
||||
|
||||
public:
|
||||
int nVersion{CProRegTx::LEGACY_BLS_VERSION};
|
||||
|
||||
int nRegisteredHeight{-1};
|
||||
int nLastPaidHeight{0};
|
||||
int nConsecutivePayments{0};
|
||||
@ -107,7 +165,9 @@ public:
|
||||
public:
|
||||
CDeterministicMNState() = default;
|
||||
explicit CDeterministicMNState(const CProRegTx& proTx) :
|
||||
nVersion(proTx.nVersion),
|
||||
keyIDOwner(proTx.keyIDOwner),
|
||||
pubKeyOperator(proTx.pubKeyOperator),
|
||||
keyIDVoting(proTx.keyIDVoting),
|
||||
addr(proTx.addr),
|
||||
scriptPayout(proTx.scriptPayout),
|
||||
@ -115,7 +175,6 @@ public:
|
||||
platformP2PPort(proTx.platformP2PPort),
|
||||
platformHTTPPort(proTx.platformHTTPPort)
|
||||
{
|
||||
pubKeyOperator.Set(proTx.pubKeyOperator);
|
||||
}
|
||||
explicit CDeterministicMNState(const CDeterministicMNState_Oldformat& s) :
|
||||
nPoSeBanHeight(s.nPoSeBanHeight),
|
||||
@ -132,6 +191,27 @@ public:
|
||||
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)
|
||||
{
|
||||
@ -141,6 +221,7 @@ public:
|
||||
SERIALIZE_METHODS(CDeterministicMNState, obj)
|
||||
{
|
||||
READWRITE(
|
||||
obj.nVersion,
|
||||
obj.nRegisteredHeight,
|
||||
obj.nLastPaidHeight,
|
||||
obj.nConsecutivePayments,
|
||||
@ -151,7 +232,9 @@ public:
|
||||
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,
|
||||
@ -163,7 +246,7 @@ public:
|
||||
|
||||
void ResetOperatorFields()
|
||||
{
|
||||
pubKeyOperator.Set(CBLSPublicKey());
|
||||
pubKeyOperator.Set(CBLSPublicKey(), bls::bls_legacy_scheme.load());
|
||||
addr = CService();
|
||||
scriptOperatorPayout = CScript();
|
||||
nRevocationReason = CProUpRevTx::REASON_NOT_SPECIFIED;
|
||||
@ -225,6 +308,7 @@ public:
|
||||
Field_platformNodeID = 0x8000,
|
||||
Field_platformP2PPort = 0x10000,
|
||||
Field_platformHTTPPort = 0x20000,
|
||||
Field_nVersion = 0x40000,
|
||||
};
|
||||
|
||||
#define DMN_STATE_DIFF_ALL_FIELDS \
|
||||
@ -245,7 +329,8 @@ public:
|
||||
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};
|
||||
@ -266,8 +351,7 @@ public:
|
||||
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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -23,7 +23,7 @@ maybe_error CProRegTx::IsTriviallyValid(bool is_bls_legacy_scheme) const
|
||||
return {ValidationInvalidReason::CONSENSUS, "bad-protx-mode"};
|
||||
}
|
||||
|
||||
if (keyIDOwner.IsNull() || !pubKeyOperator.IsValid() || keyIDVoting.IsNull()) {
|
||||
if (keyIDOwner.IsNull() || !pubKeyOperator.Get().IsValid() || keyIDVoting.IsNull()) {
|
||||
return {ValidationInvalidReason::TX_BAD_SPECIAL, "bad-protx-key-null"};
|
||||
}
|
||||
if (!scriptPayout.IsPayToPublicKeyHash() && !scriptPayout.IsPayToScriptHash()) {
|
||||
@ -81,7 +81,7 @@ std::string CProRegTx::ToString() const
|
||||
}
|
||||
|
||||
return strprintf("CProRegTx(nVersion=%d, nType=%d, collateralOutpoint=%s, addr=%s, nOperatorReward=%f, ownerAddress=%s, pubKeyOperator=%s, votingAddress=%s, scriptPayout=%s, platformNodeID=%s, platformP2PPort=%d, platformHTTPPort=%d)",
|
||||
nVersion, ToUnderlying(nType), collateralOutpoint.ToStringShort(), addr.ToString(), (double)nOperatorReward / 100, EncodeDestination(PKHash(keyIDOwner)), pubKeyOperator.ToString(nVersion == LEGACY_BLS_VERSION), EncodeDestination(PKHash(keyIDVoting)), payee, platformNodeID.ToString(), platformP2PPort, platformHTTPPort);
|
||||
nVersion, ToUnderlying(nType), collateralOutpoint.ToStringShort(), addr.ToString(), (double)nOperatorReward / 100, EncodeDestination(PKHash(keyIDOwner)), pubKeyOperator.ToString(), EncodeDestination(PKHash(keyIDVoting)), payee, platformNodeID.ToString(), platformP2PPort, platformHTTPPort);
|
||||
}
|
||||
|
||||
maybe_error CProUpServTx::IsTriviallyValid(bool is_bls_legacy_scheme) const
|
||||
@ -114,7 +114,7 @@ maybe_error CProUpRegTx::IsTriviallyValid(bool is_bls_legacy_scheme) const
|
||||
return {ValidationInvalidReason::CONSENSUS, "bad-protx-mode"};
|
||||
}
|
||||
|
||||
if (!pubKeyOperator.IsValid() || keyIDVoting.IsNull()) {
|
||||
if (!pubKeyOperator.Get().IsValid() || keyIDVoting.IsNull()) {
|
||||
return {ValidationInvalidReason::TX_BAD_SPECIAL, "bad-protx-key-null"};
|
||||
}
|
||||
if (!scriptPayout.IsPayToPublicKeyHash() && !scriptPayout.IsPayToScriptHash()) {
|
||||
@ -132,7 +132,7 @@ std::string CProUpRegTx::ToString() const
|
||||
}
|
||||
|
||||
return strprintf("CProUpRegTx(nVersion=%d, proTxHash=%s, pubKeyOperator=%s, votingAddress=%s, payoutAddress=%s)",
|
||||
nVersion, proTxHash.ToString(), pubKeyOperator.ToString(nVersion == LEGACY_BLS_VERSION), EncodeDestination(PKHash(keyIDVoting)), payee);
|
||||
nVersion, proTxHash.ToString(), pubKeyOperator.ToString(), EncodeDestination(PKHash(keyIDVoting)), payee);
|
||||
}
|
||||
|
||||
maybe_error CProUpRevTx::IsTriviallyValid(bool is_bls_legacy_scheme) const
|
||||
|
@ -43,7 +43,7 @@ public:
|
||||
uint16_t platformP2PPort{0};
|
||||
uint16_t platformHTTPPort{0};
|
||||
CKeyID keyIDOwner;
|
||||
CBLSPublicKey pubKeyOperator;
|
||||
CBLSLazyPublicKey pubKeyOperator;
|
||||
CKeyID keyIDVoting;
|
||||
uint16_t nOperatorReward{0};
|
||||
CScript scriptPayout;
|
||||
@ -65,7 +65,7 @@ public:
|
||||
obj.collateralOutpoint,
|
||||
obj.addr,
|
||||
obj.keyIDOwner,
|
||||
CBLSPublicKeyVersionWrapper(const_cast<CBLSPublicKey&>(obj.pubKeyOperator), (obj.nVersion == LEGACY_BLS_VERSION)),
|
||||
CBLSLazyPublicKeyVersionWrapper(const_cast<CBLSLazyPublicKey&>(obj.pubKeyOperator), (obj.nVersion == LEGACY_BLS_VERSION)),
|
||||
obj.keyIDVoting,
|
||||
obj.nOperatorReward,
|
||||
obj.scriptPayout,
|
||||
@ -104,7 +104,7 @@ public:
|
||||
if (ExtractDestination(scriptPayout, dest)) {
|
||||
obj.pushKV("payoutAddress", EncodeDestination(dest));
|
||||
}
|
||||
obj.pushKV("pubKeyOperator", pubKeyOperator.ToString(nVersion == LEGACY_BLS_VERSION));
|
||||
obj.pushKV("pubKeyOperator", pubKeyOperator.ToString());
|
||||
obj.pushKV("operatorReward", (double)nOperatorReward / 100);
|
||||
if (nType == MnType::HighPerformance) {
|
||||
obj.pushKV("platformNodeID", platformNodeID.ToString());
|
||||
@ -212,7 +212,7 @@ public:
|
||||
uint16_t nVersion{LEGACY_BLS_VERSION}; // message version
|
||||
uint256 proTxHash;
|
||||
uint16_t nMode{0}; // only 0 supported for now
|
||||
CBLSPublicKey pubKeyOperator;
|
||||
CBLSLazyPublicKey pubKeyOperator;
|
||||
CKeyID keyIDVoting;
|
||||
CScript scriptPayout;
|
||||
uint256 inputsHash; // replay protection
|
||||
@ -230,7 +230,7 @@ public:
|
||||
READWRITE(
|
||||
obj.proTxHash,
|
||||
obj.nMode,
|
||||
CBLSPublicKeyVersionWrapper(const_cast<CBLSPublicKey&>(obj.pubKeyOperator), (obj.nVersion == LEGACY_BLS_VERSION)),
|
||||
CBLSLazyPublicKeyVersionWrapper(const_cast<CBLSLazyPublicKey&>(obj.pubKeyOperator), (obj.nVersion == LEGACY_BLS_VERSION)),
|
||||
obj.keyIDVoting,
|
||||
obj.scriptPayout,
|
||||
obj.inputsHash
|
||||
@ -255,7 +255,7 @@ public:
|
||||
if (ExtractDestination(scriptPayout, dest)) {
|
||||
obj.pushKV("payoutAddress", EncodeDestination(dest));
|
||||
}
|
||||
obj.pushKV("pubKeyOperator", pubKeyOperator.ToString(nVersion == LEGACY_BLS_VERSION));
|
||||
obj.pushKV("pubKeyOperator", pubKeyOperator.ToString());
|
||||
obj.pushKV("inputsHash", inputsHash.ToString());
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <hash.h>
|
||||
#include <llmq/blockprocessor.h>
|
||||
#include <llmq/commitment.h>
|
||||
#include <llmq/utils.h>
|
||||
#include <primitives/block.h>
|
||||
#include <validation.h>
|
||||
|
||||
@ -152,6 +153,13 @@ bool ProcessSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, ll
|
||||
int64_t nTime5 = GetTimeMicros();
|
||||
nTimeMerkle += nTime5 - nTime4;
|
||||
LogPrint(BCLog::BENCHMARK, " - CheckCbTxMerkleRoots: %.2fms [%.2fs]\n", 0.001 * (nTime5 - nTime4), nTimeMerkle * 0.000001);
|
||||
|
||||
if (llmq::utils::V19ActivationIndex(pindex) == pindex) {
|
||||
// NOTE: The block next to the activation is the one that is using new rules.
|
||||
// V19 activated just activated, so we must switch to the new rules here.
|
||||
bls::bls_legacy_scheme.store(false);
|
||||
LogPrintf("%s: bls_legacy_scheme=%d\n", __func__, bls::bls_legacy_scheme.load());
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
LogPrintf("%s -- failed: %s\n", __func__, e.what());
|
||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "failed-procspectxsinblock");
|
||||
@ -164,7 +172,16 @@ bool UndoSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, llmq:
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
|
||||
auto bls_legacy_scheme = bls::bls_legacy_scheme.load();
|
||||
|
||||
try {
|
||||
if (llmq::utils::V19ActivationIndex(pindex) == pindex) {
|
||||
// NOTE: The block next to the activation is the one that is using new rules.
|
||||
// Removing the activation block here, so we must switch back to the old rules.
|
||||
bls::bls_legacy_scheme.store(true);
|
||||
LogPrintf("%s: bls_legacy_scheme=%d\n", __func__, bls::bls_legacy_scheme.load());
|
||||
}
|
||||
|
||||
for (int i = (int)block.vtx.size() - 1; i >= 0; --i) {
|
||||
const CTransaction& tx = *block.vtx[i];
|
||||
if (!UndoSpecialTx(tx, pindex)) {
|
||||
@ -180,6 +197,8 @@ bool UndoSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, llmq:
|
||||
return false;
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
bls::bls_legacy_scheme.store(bls_legacy_scheme);
|
||||
LogPrintf("%s: bls_legacy_scheme=%d\n", __func__, bls::bls_legacy_scheme.load());
|
||||
return error(strprintf("%s -- failed: %s\n", __func__, e.what()).c_str());
|
||||
}
|
||||
|
||||
|
@ -501,7 +501,7 @@ bool CGovernanceObject::IsValidLocally(std::string& strError, bool& fMissingConf
|
||||
|
||||
// Check that we have a valid MN signature
|
||||
if (!CheckSignature(dmn->pdmnState->pubKeyOperator.Get())) {
|
||||
strError = "Invalid masternode signature for: " + strOutpoint + ", pubkey = " + dmn->pdmnState->pubKeyOperator.Get().ToString();
|
||||
strError = "Invalid masternode signature for: " + strOutpoint + ", pubkey = " + dmn->pdmnState->pubKeyOperator.ToString();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
22
src/init.cpp
22
src/init.cpp
@ -1702,7 +1702,10 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc
|
||||
activeMasternodeInfo.blsKeyOperator = std::make_unique<CBLSSecretKey>(keyOperator);
|
||||
activeMasternodeInfo.blsPubKeyOperator = std::make_unique<CBLSPublicKey>(keyOperator.GetPublicKey());
|
||||
}
|
||||
LogPrintf("MASTERNODE:\n blsPubKeyOperator: %s\n", activeMasternodeInfo.blsPubKeyOperator->ToString());
|
||||
// We don't know the actual scheme at this point, print both
|
||||
LogPrintf("MASTERNODE:\n blsPubKeyOperator legacy: %s\n blsPubKeyOperator basic: %s\n",
|
||||
activeMasternodeInfo.blsPubKeyOperator->ToString(true),
|
||||
activeMasternodeInfo.blsPubKeyOperator->ToString(false));
|
||||
} else {
|
||||
LOCK(activeMasternodeInfoCs);
|
||||
activeMasternodeInfo.blsKeyOperator = std::make_unique<CBLSSecretKey>();
|
||||
@ -2168,6 +2171,10 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc
|
||||
strLoadError = _("Error upgrading evo database");
|
||||
break;
|
||||
}
|
||||
if (!deterministicMNManager->MigrateDBIfNeeded2()) {
|
||||
strLoadError = _("Error upgrading evo database");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!llmq::quorumBlockProcessor->UpgradeDB()) {
|
||||
strLoadError = _("Error upgrading evo database");
|
||||
@ -2192,8 +2199,11 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc
|
||||
break;
|
||||
}
|
||||
|
||||
if (llmq::utils::IsV19Active(tip))
|
||||
bool v19active = llmq::utils::IsV19Active(tip);
|
||||
if (llmq::utils::IsV19Active(tip)) {
|
||||
bls::bls_legacy_scheme.store(false);
|
||||
LogPrintf("%s: bls_legacy_scheme=%d\n", __func__, bls::bls_legacy_scheme.load());
|
||||
}
|
||||
|
||||
// Only verify the DB of the active chainstate. This is fixed in later
|
||||
// work when we allow VerifyDB to be parameterized by chainstate.
|
||||
@ -2207,6 +2217,14 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc
|
||||
failed_verification = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// VerifyDB() disconnects blocks which might result in us switching back to legacy.
|
||||
// Make sure we use the right scheme.
|
||||
if (v19active && bls::bls_legacy_scheme.load()) {
|
||||
bls::bls_legacy_scheme.store(false);
|
||||
LogPrintf("%s: bls_legacy_scheme=%d\n", __func__, bls::bls_legacy_scheme.load());
|
||||
}
|
||||
|
||||
} else {
|
||||
// TODO: CEvoDB instance should probably be a part of CChainState
|
||||
// (for multiple chainstates to actually work in parallel)
|
||||
|
@ -146,9 +146,6 @@ bool CQuorumBlockProcessor::ProcessBlock(const CBlock& block, const CBlockIndex*
|
||||
return true;
|
||||
}
|
||||
|
||||
if (utils::IsV19Active(pindex->pprev))
|
||||
bls::bls_legacy_scheme.store(false);
|
||||
|
||||
llmq::utils::PreComputeQuorumMembers(pindex);
|
||||
|
||||
std::multimap<Consensus::LLMQType, CFinalCommitment> qcs;
|
||||
@ -307,9 +304,6 @@ bool CQuorumBlockProcessor::UndoBlock(const CBlock& block, const CBlockIndex* pi
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
|
||||
if (!utils::IsV19Active(pindex->pprev))
|
||||
bls::bls_legacy_scheme.store(true);
|
||||
|
||||
llmq::utils::PreComputeQuorumMembers(pindex, true);
|
||||
|
||||
std::multimap<Consensus::LLMQType, CFinalCommitment> qcs;
|
||||
|
@ -74,7 +74,7 @@ public:
|
||||
CRecoveredSig(Consensus::LLMQType _llmqType, const uint256& _quorumHash, const uint256& _id, const uint256& _msgHash, const CBLSLazySignature& _sig) :
|
||||
CSigBase(_llmqType, _quorumHash, _id, _msgHash), sig(_sig) {UpdateHash();};
|
||||
CRecoveredSig(Consensus::LLMQType _llmqType, const uint256& _quorumHash, const uint256& _id, const uint256& _msgHash, const CBLSSignature& _sig) :
|
||||
CSigBase(_llmqType, _quorumHash, _id, _msgHash) {const_cast<CBLSLazySignature&>(sig).Set(_sig); UpdateHash();};
|
||||
CSigBase(_llmqType, _quorumHash, _id, _msgHash) {const_cast<CBLSLazySignature&>(sig).Set(_sig, bls::bls_legacy_scheme.load()); UpdateHash();};
|
||||
|
||||
private:
|
||||
// only in-memory
|
||||
|
@ -1514,7 +1514,7 @@ std::optional<CSigShare> CSigSharesManager::CreateSigShare(const CQuorumCPtr& qu
|
||||
CSigShare sigShare(quorum->params.type, quorum->qc->quorumHash, id, msgHash, uint16_t(memberIdx), {});
|
||||
uint256 signHash = sigShare.buildSignHash();
|
||||
|
||||
sigShare.sigShare.Set(skShare.Sign(signHash));
|
||||
sigShare.sigShare.Set(skShare.Sign(signHash), bls::bls_legacy_scheme.load());
|
||||
if (!sigShare.sigShare.Get().IsValid()) {
|
||||
LogPrintf("CSigSharesManager::%s -- failed to sign sigShare. signHash=%s, id=%s, msgHash=%s, time=%s\n", __func__,
|
||||
signHash.ToString(), sigShare.getId().ToString(), sigShare.getMsgHash().ToString(), t.count());
|
||||
|
@ -131,6 +131,7 @@ void CActiveMasternodeManager::Init(const CBlockIndex* pindex)
|
||||
|
||||
activeMasternodeInfo.proTxHash = dmn->proTxHash;
|
||||
activeMasternodeInfo.outpoint = dmn->collateralOutpoint;
|
||||
activeMasternodeInfo.legacy = dmn->pdmnState->nVersion == CProRegTx::LEGACY_BLS_VERSION;
|
||||
state = MASTERNODE_READY;
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@ struct CActiveMasternodeInfo {
|
||||
uint256 proTxHash;
|
||||
COutPoint outpoint;
|
||||
CService service;
|
||||
bool legacy{true};
|
||||
};
|
||||
|
||||
|
||||
|
@ -661,7 +661,7 @@ static UniValue protx_register_common_wrapper(const JSONRPCRequest& request,
|
||||
}
|
||||
|
||||
ptx.keyIDOwner = ParsePubKeyIDFromAddress(request.params[paramIdx + 1].get_str(), "owner address");
|
||||
CBLSPublicKey pubKeyOperator = ParseBLSPubKey(request.params[paramIdx + 2].get_str(), "operator BLS address", specific_legacy_bls_scheme && !isHPMNrequested);
|
||||
ptx.pubKeyOperator.Set(ParseBLSPubKey(request.params[paramIdx + 2].get_str(), "operator BLS address", ptx.nVersion == CProRegTx::LEGACY_BLS_VERSION), ptx.nVersion == CProRegTx::LEGACY_BLS_VERSION);
|
||||
CKeyID keyIDVoting = ptx.keyIDOwner;
|
||||
|
||||
if (request.params[paramIdx + 3].get_str() != "") {
|
||||
@ -703,7 +703,6 @@ static UniValue protx_register_common_wrapper(const JSONRPCRequest& request,
|
||||
paramIdx += 3;
|
||||
}
|
||||
|
||||
ptx.pubKeyOperator = pubKeyOperator;
|
||||
ptx.keyIDVoting = keyIDVoting;
|
||||
ptx.scriptPayout = GetScriptForDestination(payoutDest);
|
||||
|
||||
@ -1041,12 +1040,12 @@ static UniValue protx_update_registrar_wrapper(const JSONRPCRequest& request, co
|
||||
if (!dmn) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("masternode %s not found", ptx.proTxHash.ToString()));
|
||||
}
|
||||
ptx.pubKeyOperator = dmn->pdmnState->pubKeyOperator.Get();
|
||||
ptx.pubKeyOperator = dmn->pdmnState->pubKeyOperator;
|
||||
ptx.keyIDVoting = dmn->pdmnState->keyIDVoting;
|
||||
ptx.scriptPayout = dmn->pdmnState->scriptPayout;
|
||||
|
||||
if (request.params[1].get_str() != "") {
|
||||
ptx.pubKeyOperator = ParseBLSPubKey(request.params[1].get_str(), "operator BLS address", specific_legacy_bls_scheme);
|
||||
ptx.pubKeyOperator.Set(ParseBLSPubKey(request.params[1].get_str(), "operator BLS address", ptx.nVersion == CProUpRegTx::LEGACY_BLS_VERSION), ptx.nVersion == CProRegTx::LEGACY_BLS_VERSION);
|
||||
}
|
||||
if (request.params[2].get_str() != "") {
|
||||
ptx.keyIDVoting = ParsePubKeyIDFromAddress(request.params[2].get_str(), "voting address");
|
||||
|
@ -323,7 +323,7 @@ static UniValue gobject_submit(const JSONRPCRequest& request)
|
||||
bool fMnFound = WITH_LOCK(activeMasternodeInfoCs, return mnList.HasValidMNByCollateral(activeMasternodeInfo.outpoint));
|
||||
|
||||
LogPrint(BCLog::GOBJECT, "gobject_submit -- pubKeyOperator = %s, outpoint = %s, params.size() = %lld, fMnFound = %d\n",
|
||||
(WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.blsPubKeyOperator ? activeMasternodeInfo.blsPubKeyOperator->ToString() : "N/A")),
|
||||
(WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.blsPubKeyOperator ? activeMasternodeInfo.blsPubKeyOperator->ToString(activeMasternodeInfo.legacy) : "N/A")),
|
||||
WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.outpoint.ToStringShort()), request.params.size(), fMnFound);
|
||||
|
||||
// ASSEMBLE NEW GOVERNANCE OBJECT FROM USER PARAMETERS
|
||||
|
@ -675,7 +675,7 @@ static UniValue masternodelist(const JSONRPCRequest& request)
|
||||
EncodeDestination(PKHash(dmn.pdmnState->keyIDOwner)) << " " <<
|
||||
EncodeDestination(PKHash(dmn.pdmnState->keyIDVoting)) << " " <<
|
||||
collateralAddressStr << " " <<
|
||||
dmn.pdmnState->pubKeyOperator.Get().ToString();
|
||||
dmn.pdmnState->pubKeyOperator.ToString();
|
||||
std::string strInfo = streamInfo.str();
|
||||
if (strFilter !="" && strInfo.find(strFilter) == std::string::npos &&
|
||||
strOutpoint.find(strFilter) == std::string::npos) return;
|
||||
@ -697,7 +697,7 @@ static UniValue masternodelist(const JSONRPCRequest& request)
|
||||
objMN.pushKV("owneraddress", EncodeDestination(PKHash(dmn.pdmnState->keyIDOwner)));
|
||||
objMN.pushKV("votingaddress", EncodeDestination(PKHash(dmn.pdmnState->keyIDVoting)));
|
||||
objMN.pushKV("collateraladdress", collateralAddressStr);
|
||||
objMN.pushKV("pubkeyoperator", dmn.pdmnState->pubKeyOperator.Get().ToString());
|
||||
objMN.pushKV("pubkeyoperator", dmn.pdmnState->pubKeyOperator.ToString());
|
||||
obj.pushKV(strOutpoint, objMN);
|
||||
} else if (strMode == "lastpaidblock") {
|
||||
if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) return;
|
||||
@ -714,7 +714,7 @@ static UniValue masternodelist(const JSONRPCRequest& request)
|
||||
obj.pushKV(strOutpoint, EncodeDestination(PKHash(dmn.pdmnState->keyIDOwner)));
|
||||
} else if (strMode == "pubkeyoperator") {
|
||||
if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) return;
|
||||
obj.pushKV(strOutpoint, dmn.pdmnState->pubKeyOperator.Get().ToString());
|
||||
obj.pushKV(strOutpoint, dmn.pdmnState->pubKeyOperator.ToString());
|
||||
} else if (strMode == "status") {
|
||||
std::string strStatus = dmnToStatus(dmn);
|
||||
if (strFilter !="" && strStatus.find(strFilter) == std::string::npos &&
|
||||
|
@ -210,7 +210,7 @@ static UniValue BuildQuorumInfo(const llmq::CQuorumCPtr& quorum, bool includeMem
|
||||
UniValue mo(UniValue::VOBJ);
|
||||
mo.pushKV("proTxHash", dmn->proTxHash.ToString());
|
||||
mo.pushKV("service", dmn->pdmnState->addr.ToString());
|
||||
mo.pushKV("pubKeyOperator", dmn->pdmnState->pubKeyOperator.Get().ToString());
|
||||
mo.pushKV("pubKeyOperator", dmn->pdmnState->pubKeyOperator.ToString());
|
||||
mo.pushKV("valid", quorum->qc->validMembers[i]);
|
||||
if (quorum->qc->validMembers[i]) {
|
||||
CBLSPublicKey pubKey = quorum->GetPubKeyShare(i);
|
||||
|
@ -125,7 +125,7 @@ static CMutableTransaction CreateProRegTx(const CTxMemPool& mempool, SimpleUTXOM
|
||||
proTx.collateralOutpoint.n = 0;
|
||||
proTx.addr = LookupNumeric("1.1.1.1", port);
|
||||
proTx.keyIDOwner = ownerKeyRet.GetPubKey().GetID();
|
||||
proTx.pubKeyOperator = operatorKeyRet.GetPublicKey();
|
||||
proTx.pubKeyOperator.Set(operatorKeyRet.GetPublicKey(), bls::bls_legacy_scheme.load());
|
||||
proTx.keyIDVoting = ownerKeyRet.GetPubKey().GetID();
|
||||
proTx.scriptPayout = scriptPayout;
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <evo/specialtx.h>
|
||||
#include <evo/providertx.h>
|
||||
#include <evo/deterministicmns.h>
|
||||
#include <llmq/utils.h>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
@ -103,7 +104,7 @@ static CMutableTransaction CreateProRegTx(const CTxMemPool& mempool, SimpleUTXOM
|
||||
proTx.collateralOutpoint.n = 0;
|
||||
proTx.addr = LookupNumeric("1.1.1.1", port);
|
||||
proTx.keyIDOwner = ownerKeyRet.GetPubKey().GetID();
|
||||
proTx.pubKeyOperator = operatorKeyRet.GetPublicKey();
|
||||
proTx.pubKeyOperator.Set(operatorKeyRet.GetPublicKey(), bls::bls_legacy_scheme.load());
|
||||
proTx.keyIDVoting = ownerKeyRet.GetPubKey().GetID();
|
||||
proTx.scriptPayout = scriptPayout;
|
||||
|
||||
@ -143,7 +144,7 @@ static CMutableTransaction CreateProUpRegTx(const CTxMemPool& mempool, SimpleUTX
|
||||
CProUpRegTx proTx;
|
||||
proTx.nVersion = CProUpRegTx::GetVersion(!bls::bls_legacy_scheme);
|
||||
proTx.proTxHash = proTxHash;
|
||||
proTx.pubKeyOperator = pubKeyOperator;
|
||||
proTx.pubKeyOperator.Set(pubKeyOperator, bls::bls_legacy_scheme.load());
|
||||
proTx.keyIDVoting = keyIDVoting;
|
||||
proTx.scriptPayout = scriptPayout;
|
||||
|
||||
@ -264,6 +265,136 @@ void FuncDIP3Activation(TestChainSetup& setup)
|
||||
BOOST_ASSERT(deterministicMNManager->GetListAtChainTip().HasMN(tx.GetHash()));
|
||||
};
|
||||
|
||||
void FuncV19Activation(TestChainSetup& setup)
|
||||
{
|
||||
BOOST_ASSERT(!llmq::utils::IsV19Active(::ChainActive().Tip()));
|
||||
|
||||
// create
|
||||
auto utxos = BuildSimpleUtxoMap(setup.m_coinbase_txns);
|
||||
CKey owner_key;
|
||||
CBLSSecretKey operator_key;
|
||||
CKey collateral_key;
|
||||
collateral_key.MakeNewKey(false);
|
||||
auto collateralScript = GetScriptForDestination(PKHash(collateral_key.GetPubKey()));
|
||||
auto tx_reg = CreateProRegTx(*(setup.m_node.mempool), utxos, 1, collateralScript, setup.coinbaseKey, owner_key, operator_key);
|
||||
auto tx_reg_hash = tx_reg.GetHash();
|
||||
|
||||
int nHeight = ::ChainActive().Height();
|
||||
|
||||
auto block = std::make_shared<CBlock>(setup.CreateBlock({tx_reg}, setup.coinbaseKey));
|
||||
BOOST_ASSERT(Assert(setup.m_node.chainman)->ProcessNewBlock(Params(), block, true, nullptr));
|
||||
BOOST_ASSERT(!llmq::utils::IsV19Active(::ChainActive().Tip()));
|
||||
++nHeight;
|
||||
BOOST_CHECK_EQUAL(::ChainActive().Height(), nHeight);
|
||||
deterministicMNManager->UpdatedBlockTip(::ChainActive().Tip());
|
||||
deterministicMNManager->DoMaintenance();
|
||||
auto tip_list = deterministicMNManager->GetListAtChainTip();
|
||||
BOOST_ASSERT(tip_list.HasMN(tx_reg_hash));
|
||||
auto pindex_create = ::ChainActive().Tip();
|
||||
auto base_list = deterministicMNManager->GetListForBlock(pindex_create);
|
||||
std::vector<CDeterministicMNListDiff> diffs;
|
||||
|
||||
// update
|
||||
CBLSSecretKey operator_key_new;
|
||||
operator_key_new.MakeNewKey();
|
||||
auto tx_upreg = CreateProUpRegTx(*(setup.m_node.mempool), utxos, tx_reg_hash, owner_key, operator_key_new.GetPublicKey(), owner_key.GetPubKey().GetID(), collateralScript, setup.coinbaseKey);
|
||||
|
||||
block = std::make_shared<CBlock>(setup.CreateBlock({tx_upreg}, setup.coinbaseKey));
|
||||
BOOST_ASSERT(Assert(setup.m_node.chainman)->ProcessNewBlock(Params(), block, true, nullptr));
|
||||
BOOST_ASSERT(!llmq::utils::IsV19Active(::ChainActive().Tip()));
|
||||
++nHeight;
|
||||
BOOST_CHECK_EQUAL(::ChainActive().Height(), nHeight);
|
||||
deterministicMNManager->UpdatedBlockTip(::ChainActive().Tip());
|
||||
deterministicMNManager->DoMaintenance();
|
||||
tip_list = deterministicMNManager->GetListAtChainTip();
|
||||
BOOST_ASSERT(tip_list.HasMN(tx_reg_hash));
|
||||
diffs.push_back(base_list.BuildDiff(tip_list));
|
||||
|
||||
// spend
|
||||
CMutableTransaction tx_spend;
|
||||
COutPoint collateralOutpoint(tx_reg_hash, 0);
|
||||
tx_spend.vin.emplace_back(collateralOutpoint);
|
||||
tx_spend.vout.emplace_back(999.99 * COIN, collateralScript);
|
||||
|
||||
FillableSigningProvider signing_provider;
|
||||
signing_provider.AddKeyPubKey(collateral_key, collateral_key.GetPubKey());
|
||||
BOOST_ASSERT(SignSignature(signing_provider, CTransaction(tx_reg), tx_spend, 0, SIGHASH_ALL));
|
||||
block = std::make_shared<CBlock>(setup.CreateBlock({tx_spend}, setup.coinbaseKey));
|
||||
BOOST_ASSERT(Assert(setup.m_node.chainman)->ProcessNewBlock(Params(), block, true, nullptr));
|
||||
BOOST_ASSERT(!llmq::utils::IsV19Active(::ChainActive().Tip()));
|
||||
++nHeight;
|
||||
BOOST_CHECK_EQUAL(::ChainActive().Height(), nHeight);
|
||||
deterministicMNManager->UpdatedBlockTip(::ChainActive().Tip());
|
||||
deterministicMNManager->DoMaintenance();
|
||||
diffs.push_back(tip_list.BuildDiff(deterministicMNManager->GetListAtChainTip()));
|
||||
tip_list = deterministicMNManager->GetListAtChainTip();
|
||||
BOOST_ASSERT(!tip_list.HasMN(tx_reg_hash));
|
||||
BOOST_ASSERT(deterministicMNManager->GetListForBlock(pindex_create).HasMN(tx_reg_hash));
|
||||
|
||||
// mine another block so that it's not the last one before V19
|
||||
setup.CreateAndProcessBlock({}, setup.coinbaseKey);
|
||||
BOOST_ASSERT(!llmq::utils::IsV19Active(::ChainActive().Tip()));
|
||||
++nHeight;
|
||||
BOOST_CHECK_EQUAL(::ChainActive().Height(), nHeight);
|
||||
deterministicMNManager->UpdatedBlockTip(::ChainActive().Tip());
|
||||
deterministicMNManager->DoMaintenance();
|
||||
diffs.push_back(tip_list.BuildDiff(deterministicMNManager->GetListAtChainTip()));
|
||||
tip_list = deterministicMNManager->GetListAtChainTip();
|
||||
BOOST_ASSERT(!tip_list.HasMN(tx_reg_hash));
|
||||
BOOST_ASSERT(deterministicMNManager->GetListForBlock(pindex_create).HasMN(tx_reg_hash));
|
||||
|
||||
// this block should activate V19
|
||||
setup.CreateAndProcessBlock({}, setup.coinbaseKey);
|
||||
BOOST_ASSERT(llmq::utils::IsV19Active(::ChainActive().Tip()));
|
||||
++nHeight;
|
||||
BOOST_CHECK_EQUAL(::ChainActive().Height(), nHeight);
|
||||
deterministicMNManager->UpdatedBlockTip(::ChainActive().Tip());
|
||||
deterministicMNManager->DoMaintenance();
|
||||
diffs.push_back(tip_list.BuildDiff(deterministicMNManager->GetListAtChainTip()));
|
||||
tip_list = deterministicMNManager->GetListAtChainTip();
|
||||
BOOST_ASSERT(!tip_list.HasMN(tx_reg_hash));
|
||||
BOOST_ASSERT(deterministicMNManager->GetListForBlock(pindex_create).HasMN(tx_reg_hash));
|
||||
|
||||
// check mn list/diff
|
||||
CDeterministicMNListDiff dummy_diff = base_list.BuildDiff(tip_list);
|
||||
CDeterministicMNList dummmy_list = base_list.ApplyDiff(::ChainActive().Tip(), dummy_diff);
|
||||
// Lists should match
|
||||
BOOST_ASSERT(dummmy_list == tip_list);
|
||||
|
||||
// mine 10 more blocks
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{
|
||||
setup.CreateAndProcessBlock({}, setup.coinbaseKey);
|
||||
BOOST_ASSERT(llmq::utils::IsV19Active(::ChainActive().Tip()));
|
||||
BOOST_CHECK_EQUAL(::ChainActive().Height(), nHeight + 1 + i);
|
||||
deterministicMNManager->UpdatedBlockTip(::ChainActive().Tip());
|
||||
deterministicMNManager->DoMaintenance();
|
||||
diffs.push_back(tip_list.BuildDiff(deterministicMNManager->GetListAtChainTip()));
|
||||
tip_list = deterministicMNManager->GetListAtChainTip();
|
||||
BOOST_ASSERT(!tip_list.HasMN(tx_reg_hash));
|
||||
BOOST_ASSERT(deterministicMNManager->GetListForBlock(pindex_create).HasMN(tx_reg_hash));
|
||||
}
|
||||
|
||||
// check mn list/diff
|
||||
const CBlockIndex* v19_index = llmq::utils::V19ActivationIndex(::ChainActive().Tip());
|
||||
auto v19_list = deterministicMNManager->GetListForBlock(v19_index);
|
||||
dummy_diff = v19_list.BuildDiff(tip_list);
|
||||
dummmy_list = v19_list.ApplyDiff(::ChainActive().Tip(), dummy_diff);
|
||||
BOOST_ASSERT(dummmy_list == tip_list);
|
||||
|
||||
// NOTE: this fails on v19/v19.1 with errors like:
|
||||
// "RemoveMN: Can't delete a masternode ... with a pubKeyOperator=..."
|
||||
dummy_diff = base_list.BuildDiff(tip_list);
|
||||
dummmy_list = base_list.ApplyDiff(::ChainActive().Tip(), dummy_diff);
|
||||
BOOST_ASSERT(dummmy_list == tip_list);
|
||||
|
||||
dummmy_list = base_list;
|
||||
for (const auto& diff : diffs) {
|
||||
dummmy_list = dummmy_list.ApplyDiff(::ChainActive().Tip(), diff);
|
||||
}
|
||||
BOOST_ASSERT(dummmy_list == tip_list);
|
||||
};
|
||||
|
||||
void FuncDIP3Protx(TestChainSetup& setup)
|
||||
{
|
||||
CKey sporkKey;
|
||||
@ -481,7 +612,7 @@ void FuncTestMempoolReorg(TestChainSetup& setup)
|
||||
payload.nVersion = CProRegTx::GetVersion(!bls::bls_legacy_scheme);
|
||||
payload.addr = LookupNumeric("1.1.1.1", 1);
|
||||
payload.keyIDOwner = ownerKey.GetPubKey().GetID();
|
||||
payload.pubKeyOperator = operatorKey.GetPublicKey();
|
||||
payload.pubKeyOperator.Set(operatorKey.GetPublicKey(), bls::bls_legacy_scheme.load());
|
||||
payload.keyIDVoting = ownerKey.GetPubKey().GetID();
|
||||
payload.scriptPayout = scriptPayout;
|
||||
|
||||
@ -550,7 +681,7 @@ void FuncTestMempoolDualProregtx(TestChainSetup& setup)
|
||||
CProRegTx payload;
|
||||
payload.addr = LookupNumeric("1.1.1.1", 2);
|
||||
payload.keyIDOwner = ownerKey.GetPubKey().GetID();
|
||||
payload.pubKeyOperator = operatorKey.GetPublicKey();
|
||||
payload.pubKeyOperator.Set(operatorKey.GetPublicKey(), bls::bls_legacy_scheme.load());
|
||||
payload.keyIDVoting = ownerKey.GetPubKey().GetID();
|
||||
payload.scriptPayout = scriptPayout;
|
||||
|
||||
@ -612,7 +743,7 @@ void FuncVerifyDB(TestChainSetup& setup)
|
||||
payload.nVersion = CProRegTx::GetVersion(!bls::bls_legacy_scheme);
|
||||
payload.addr = LookupNumeric("1.1.1.1", 1);
|
||||
payload.keyIDOwner = ownerKey.GetPubKey().GetID();
|
||||
payload.pubKeyOperator = operatorKey.GetPublicKey();
|
||||
payload.pubKeyOperator.Set(operatorKey.GetPublicKey(), bls::bls_legacy_scheme.load());
|
||||
payload.keyIDVoting = ownerKey.GetPubKey().GetID();
|
||||
payload.scriptPayout = scriptPayout;
|
||||
|
||||
@ -667,6 +798,13 @@ BOOST_AUTO_TEST_CASE(dip3_activation_legacy)
|
||||
FuncDIP3Activation(setup);
|
||||
}
|
||||
|
||||
// V19 can only be activated with legacy scheme
|
||||
BOOST_AUTO_TEST_CASE(v19_activation_legacy)
|
||||
{
|
||||
TestChainV19BeforeActivationSetup setup;
|
||||
FuncV19Activation(setup);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(dip3_protx_legacy)
|
||||
{
|
||||
TestChainDIP3Setup setup;
|
||||
|
@ -28,7 +28,7 @@ BOOST_AUTO_TEST_CASE(simplifiedmns_merkleroots)
|
||||
std::vector<unsigned char> vecBytes{static_cast<unsigned char>(i)};
|
||||
vecBytes.resize(CBLSSecretKey::SerSize);
|
||||
|
||||
smle.pubKeyOperator.Set(CBLSSecretKey(vecBytes).GetPublicKey());
|
||||
smle.pubKeyOperator.Set(CBLSSecretKey(vecBytes).GetPublicKey(), bls::bls_legacy_scheme.load());
|
||||
smle.keyIDVoting.SetHex(strprintf("%040x", i));
|
||||
smle.isValid = true;
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <llmq/signing_shares.h>
|
||||
#include <llmq/signing.h>
|
||||
#include <llmq/snapshot.h>
|
||||
#include <llmq/utils.h>
|
||||
#include <miner.h>
|
||||
#include <net.h>
|
||||
#include <net_processing.h>
|
||||
@ -391,3 +392,9 @@ CBlock getBlock13b8a()
|
||||
stream >> block;
|
||||
return block;
|
||||
}
|
||||
|
||||
TestChainV19BeforeActivationSetup::TestChainV19BeforeActivationSetup() : TestChainSetup(894)
|
||||
{
|
||||
bool v19_active = llmq::utils::IsV19Active(::ChainActive().Tip());
|
||||
assert(!v19_active);
|
||||
}
|
||||
|
@ -152,6 +152,11 @@ struct TestChainDIP3BeforeActivationSetup : public TestChainSetup
|
||||
TestChainDIP3BeforeActivationSetup() : TestChainSetup(430) {}
|
||||
};
|
||||
|
||||
struct TestChainV19BeforeActivationSetup : public TestChainSetup
|
||||
{
|
||||
TestChainV19BeforeActivationSetup();
|
||||
};
|
||||
|
||||
class CTxMemPoolEntry;
|
||||
|
||||
struct TestMemPoolEntryHelper
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include <hash.h>
|
||||
#include <validationinterface.h>
|
||||
|
||||
#include <bls/bls.h>
|
||||
#include <evo/specialtx.h>
|
||||
#include <evo/providertx.h>
|
||||
#include <evo/deterministicmns.h>
|
||||
@ -443,7 +442,7 @@ void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, setEntries &setAnces
|
||||
auto dmn = deterministicMNManager->GetListAtChainTip().GetMN(proTx.proTxHash);
|
||||
assert(dmn);
|
||||
newit->validForProTxKey = ::SerializeHash(dmn->pdmnState->pubKeyOperator);
|
||||
if (dmn->pdmnState->pubKeyOperator.Get() != proTx.pubKeyOperator) {
|
||||
if (dmn->pdmnState->pubKeyOperator != proTx.pubKeyOperator) {
|
||||
newit->isKeyChangeProTx = true;
|
||||
}
|
||||
} else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_REVOKE) {
|
||||
@ -838,7 +837,7 @@ void CTxMemPool::removeProTxPubKeyConflicts(const CTransaction &tx, const CKeyID
|
||||
}
|
||||
}
|
||||
|
||||
void CTxMemPool::removeProTxPubKeyConflicts(const CTransaction &tx, const CBLSPublicKey &pubKey)
|
||||
void CTxMemPool::removeProTxPubKeyConflicts(const CTransaction &tx, const CBLSLazyPublicKey &pubKey)
|
||||
{
|
||||
if (mapProTxBlsPubKeyHashes.count(pubKey.GetHash())) {
|
||||
uint256 conflictHash = mapProTxBlsPubKeyHashes[pubKey.GetHash()];
|
||||
@ -1301,7 +1300,7 @@ bool CTxMemPool::existsProviderTxConflict(const CTransaction &tx) const {
|
||||
return true; // i.e. failed to find validated ProTx == conflict
|
||||
}
|
||||
// only allow one operator key change in the mempool
|
||||
if (dmn->pdmnState->pubKeyOperator.Get() != proTx.pubKeyOperator) {
|
||||
if (dmn->pdmnState->pubKeyOperator != proTx.pubKeyOperator) {
|
||||
if (hasKeyChangeInMempool(proTx.proTxHash)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <addressindex.h>
|
||||
#include <spentindex.h>
|
||||
#include <amount.h>
|
||||
#include <bls/bls.h>
|
||||
#include <coins.h>
|
||||
#include <crypto/siphash.h>
|
||||
#include <indirectmap.h>
|
||||
@ -33,8 +34,6 @@
|
||||
#include <boost/multi_index/ordered_index.hpp>
|
||||
#include <boost/multi_index/sequenced_index.hpp>
|
||||
|
||||
class CBLSPublicKey;
|
||||
|
||||
class CBlockIndex;
|
||||
extern CCriticalSection cs_main;
|
||||
|
||||
@ -616,7 +615,7 @@ public:
|
||||
void removeForReorg(const CCoinsViewCache* pcoins, unsigned int nMemPoolHeight, int flags) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
|
||||
void removeConflicts(const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
void removeProTxPubKeyConflicts(const CTransaction &tx, const CKeyID &keyId) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
void removeProTxPubKeyConflicts(const CTransaction &tx, const CBLSPublicKey &pubKey) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
void removeProTxPubKeyConflicts(const CTransaction &tx, const CBLSLazyPublicKey &pubKey) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
void removeProTxCollateralConflicts(const CTransaction &tx, const COutPoint &collateralOutpoint) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
void removeProTxSpentCollateralConflicts(const CTransaction &tx) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
void removeProTxKeyChangedConflicts(const CTransaction &tx, const uint256& proTxHash, const uint256& newKeyHash) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
|
@ -4214,6 +4214,8 @@ bool TestBlockValidity(CValidationState& state, llmq::CChainLocksHandler& clhand
|
||||
AssertLockHeld(cs_main);
|
||||
assert(pindexPrev && pindexPrev == ::ChainActive().Tip());
|
||||
|
||||
auto bls_legacy_scheme = bls::bls_legacy_scheme.load();
|
||||
|
||||
uint256 hash = block.GetHash();
|
||||
if (clhandler.HasConflictingChainLock(pindexPrev->nHeight + 1, hash)) {
|
||||
return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_PREV, error("%s: conflicting with chainlock", __func__), REJECT_INVALID, "bad-chainlock");
|
||||
@ -4240,6 +4242,12 @@ bool TestBlockValidity(CValidationState& state, llmq::CChainLocksHandler& clhand
|
||||
return false;
|
||||
assert(state.IsValid());
|
||||
|
||||
// we could switch to another scheme while testing, switch back to the original one
|
||||
if (bls_legacy_scheme != bls::bls_legacy_scheme.load()) {
|
||||
bls::bls_legacy_scheme.store(bls_legacy_scheme);
|
||||
LogPrintf("%s: bls_legacy_scheme=%d\n", __func__, bls::bls_legacy_scheme.load());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -66,9 +66,18 @@ class DIP3V19Test(DashTestFramework):
|
||||
b_0 = self.nodes[0].getbestblockhash()
|
||||
self.test_getmnlistdiff(null_hash, b_0, {}, [], expected_updated)
|
||||
|
||||
mn_list_before = self.nodes[0].masternodelist()
|
||||
pubkeyoperator_list_before = set([mn_list_before[e]["pubkeyoperator"] for e in mn_list_before])
|
||||
|
||||
self.activate_v19(expected_activation_height=900)
|
||||
self.log.info("Activated v19 at height:" + str(self.nodes[0].getblockcount()))
|
||||
|
||||
mn_list_after = self.nodes[0].masternodelist()
|
||||
pubkeyoperator_list_after = set([mn_list_after[e]["pubkeyoperator"] for e in mn_list_after])
|
||||
|
||||
self.log.info("pubkeyoperator should still be shown using legacy scheme")
|
||||
assert_equal(pubkeyoperator_list_before, pubkeyoperator_list_after)
|
||||
|
||||
self.move_to_next_cycle()
|
||||
self.log.info("Cycle H height:" + str(self.nodes[0].getblockcount()))
|
||||
self.move_to_next_cycle()
|
||||
|
Loading…
Reference in New Issue
Block a user