Skip to content
Draft
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
4 changes: 2 additions & 2 deletions src/common/bloom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ bool CBloomFilter::CheckSpecialTransactionMatchesAndUpdate(const CTransaction &t
switch(tx.nType) {
case(TRANSACTION_PROVIDER_REGISTER): {
if (const auto opt_proTx = GetTxPayload<CProRegTx>(tx)) {
const auto owner_payouts = GetOwnerPayouts(opt_proTx->nVersion, opt_proTx->scriptPayout, opt_proTx->payouts);
const auto owner_payouts = GetOwnerPayouts(*opt_proTx);
const bool found_payout = std::any_of(owner_payouts.begin(), owner_payouts.end(),
[&](const auto& payout) { return CheckScript(payout.scriptPayout); });
if(contains(opt_proTx->collateralOutpoint) ||
Expand Down Expand Up @@ -163,7 +163,7 @@ bool CBloomFilter::CheckSpecialTransactionMatchesAndUpdate(const CTransaction &t
if (const auto opt_proTx = GetTxPayload<CProUpRegTx>(tx)) {
if(contains(opt_proTx->proTxHash))
return true;
const auto owner_payouts = GetOwnerPayouts(opt_proTx->nVersion, opt_proTx->scriptPayout, opt_proTx->payouts);
const auto owner_payouts = GetOwnerPayouts(*opt_proTx);
const bool found_payout = std::any_of(owner_payouts.begin(), owner_payouts.end(),
[&](const auto& payout) { return CheckScript(payout.scriptPayout); });
if(contains(opt_proTx->keyIDVoting) ||
Expand Down
8 changes: 4 additions & 4 deletions src/evo/core_write.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ UniValue CDeterministicMNState::ToJson(MnType nType) const
}

CTxDestination dest;
if (nVersion >= ProTxVersion::MultiPayout) {
if (nVersion >= ProTxVersion::ExtAddr) {
obj.pushKV("payouts", PayoutListToJson(payouts));
} else if (ExtractDestination(scriptPayout, dest)) {
obj.pushKV("payoutAddress", EncodeDestination(dest));
Expand Down Expand Up @@ -335,7 +335,7 @@ UniValue CProRegTx::ToJson() const
ret.pushKV("addresses", GetNetInfoWithLegacyFields(*this, nType));
ret.pushKV("ownerAddress", EncodeDestination(PKHash(keyIDOwner)));
ret.pushKV("votingAddress", EncodeDestination(PKHash(keyIDVoting)));
if (nVersion >= ProTxVersion::MultiPayout) {
if (nVersion >= ProTxVersion::ExtAddr) {
ret.pushKV("payouts", PayoutListToJson(payouts));
} else if (CTxDestination dest; ExtractDestination(scriptPayout, dest)) {
ret.pushKV("payoutAddress", EncodeDestination(dest));
Expand Down Expand Up @@ -373,7 +373,7 @@ UniValue CProUpRegTx::ToJson() const
ret.pushKV("version", nVersion);
ret.pushKV("proTxHash", proTxHash.ToString());
ret.pushKV("votingAddress", EncodeDestination(PKHash(keyIDVoting)));
if (nVersion >= ProTxVersion::MultiPayout) {
if (nVersion >= ProTxVersion::ExtAddr) {
ret.pushKV("payouts", PayoutListToJson(payouts));
} else if (CTxDestination dest; ExtractDestination(scriptPayout, dest)) {
ret.pushKV("payoutAddress", EncodeDestination(dest));
Expand Down Expand Up @@ -582,7 +582,7 @@ UniValue CSimplifiedMNListEntry::ToJson(bool extended) const

if (extended) {
CTxDestination dest;
if (nVersion >= ProTxVersion::MultiPayout) {
if (nVersion >= ProTxVersion::ExtAddr) {
obj.pushKV("payouts", PayoutListToJson(payouts));
} else if (ExtractDestination(scriptPayout, dest)) {
obj.pushKV("payoutAddress", EncodeDestination(dest));
Expand Down
2 changes: 1 addition & 1 deletion src/evo/deterministicmns.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ CSimplifiedMNListEntry CDeterministicMN::to_sml_entry() const
const CDeterministicMNState& state{*pdmnState};
return CSimplifiedMNListEntry(proTxHash, state.confirmedHash, state.netInfo, state.pubKeyOperator,
state.keyIDVoting, !state.IsBanned(), state.platformHTTPPort, state.platformNodeID,
state.scriptPayout, GetOwnerPayouts(state.nVersion, state.scriptPayout, state.payouts),
state.scriptPayout, GetOwnerPayouts(state),
state.scriptOperatorPayout, state.nVersion, nType);
}

Expand Down
2 changes: 1 addition & 1 deletion src/evo/dmnstate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ std::string CDeterministicMNState::ToString() const
if (ExtractDestination(scriptPayout, dest)) {
payoutAddress = EncodeDestination(dest);
}
const auto owner_payouts = GetOwnerPayouts(nVersion, scriptPayout, payouts);
const auto owner_payouts = GetOwnerPayouts(*this);
const std::string payoutList = PayoutListToString(owner_payouts);
if (ExtractDestination(scriptOperatorPayout, dest)) {
operatorPayoutAddress = EncodeDestination(dest);
Expand Down
2 changes: 1 addition & 1 deletion src/evo/dmnstate.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ class CDeterministicMNState
obj.keyIDVoting,
NetInfoSerWrapper(const_cast<std::shared_ptr<NetInfoInterface>&>(obj.netInfo),
obj.nVersion >= ProTxVersion::ExtAddr));
if (obj.nVersion >= ProTxVersion::MultiPayout) {
if (obj.nVersion >= ProTxVersion::ExtAddr) {
READWRITE(obj.payouts);
Comment on lines +104 to 105

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Backfill payouts when service updates promote v2 states

Because v3 states now take the payouts branch, a basic v2 masternode upgraded by a post-v24 ProUpServTx loses its owner payee: the service-update path in CSpecialTxProcessor::RebuildListFromBlock can raise nVersion from 2 to 3 while only converting netInfo, and v2 states have an empty payouts vector because they serialized scriptPayout. After that, GetOwnerPayouts(state) returns an empty list, so masternode payment construction omits the owner payout (and callers that use .front() can fail) until a registrar update backfills it. Please migrate scriptPayout to LegacyPayoutAsList when any non-registrar version bump crosses ExtAddr.

Useful? React with 👍 / 👎.

Comment on lines +104 to 105

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve decoding of existing v3 state snapshots

For nodes that have already written deterministic MN snapshots containing v3 states with the previous encoding, this switch makes CDeterministicMNState read those same dmn_S3 snapshot records as payouts instead of the formerly serialized scriptPayout; DB_LIST_SNAPSHOT is still dmn_S3 in src/evo/deterministicmns.cpp, and GetListForBlockInternal reads it directly before applying diffs. In that upgrade scenario the old script bytes are interpreted as a vector of payout shares, which can fail deserialization or corrupt the reconstructed list, so this needs a snapshot key bump or legacy decoder/migration alongside the format change.

Useful? React with 👍 / 👎.

} else {
READWRITE(obj.scriptPayout);
Expand Down
2 changes: 1 addition & 1 deletion src/evo/netinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include <evo/netinfo.h>

#include <chainparams.h>
#include <evo/providertx.h>
#include <evo/types.h>
#include <netbase.h>
#include <span.h>
#include <util/check.h>
Expand Down
63 changes: 15 additions & 48 deletions src/evo/providertx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,38 +13,9 @@
#include <hash.h>
#include <script/standard.h>
#include <tinyformat.h>
#include <validation.h>

#include <set>

namespace ProTxVersion {
template <typename T>
[[nodiscard]] uint16_t GetMaxFromDeployment(gsl::not_null<const CBlockIndex*> pindexPrev,
const ChainstateManager& chainman, std::optional<bool> is_basic_override)
{
constexpr bool is_extaddr_eligible{std::is_same_v<std::decay_t<T>, CProRegTx> || std::is_same_v<std::decay_t<T>, CProUpServTx>};
constexpr bool is_multipayout_eligible{std::is_same_v<std::decay_t<T>, CProRegTx> || std::is_same_v<std::decay_t<T>, CProUpRegTx>};
const bool is_v24_active{DeploymentActiveAfter(pindexPrev, chainman, Consensus::DEPLOYMENT_V24)};
return ProTxVersion::GetMax(
is_basic_override ? *is_basic_override
: DeploymentActiveAfter(pindexPrev, chainman.GetConsensus(), Consensus::DEPLOYMENT_V19),
is_extaddr_eligible ? is_v24_active : false,
is_multipayout_eligible ? is_v24_active : false);
}
template uint16_t GetMaxFromDeployment<CProRegTx>(gsl::not_null<const CBlockIndex*> pindexPrev,
const ChainstateManager& chainman,
std::optional<bool> is_basic_override);
template uint16_t GetMaxFromDeployment<CProUpServTx>(gsl::not_null<const CBlockIndex*> pindexPrev,
const ChainstateManager& chainman,
std::optional<bool> is_basic_override);
template uint16_t GetMaxFromDeployment<CProUpRegTx>(gsl::not_null<const CBlockIndex*> pindexPrev,
const ChainstateManager& chainman,
std::optional<bool> is_basic_override);
template uint16_t GetMaxFromDeployment<CProUpRevTx>(gsl::not_null<const CBlockIndex*> pindexPrev,
const ChainstateManager& chainman,
std::optional<bool> is_basic_override);
} // namespace ProTxVersion

static bool IsValidPayoutScript(const CScript& script)
{
return script.IsPayToPublicKeyHash() || script.IsPayToScriptHash();
Expand All @@ -60,7 +31,7 @@ bool IsPayoutListTriviallyValid(const MasternodePayoutShares& payouts, const CKe
uint32_t total_reward{0};
std::set<CScript> seen_scripts;
for (const auto& payout : payouts) {
if (payout.reward < CMasternodePayoutShare::MIN_REWARD || payout.reward > CMasternodePayoutShare::MAX_REWARD) {
if (payout.reward < MasternodePayoutShare::MIN_REWARD || payout.reward > MasternodePayoutShare::MAX_REWARD) {
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-payout-reward");
}
total_reward += payout.reward;
Expand All @@ -82,7 +53,7 @@ bool IsPayoutListTriviallyValid(const MasternodePayoutShares& payouts, const CKe
}
}

if (total_reward != CMasternodePayoutShare::MAX_REWARD) {
if (total_reward != MasternodePayoutShare::MAX_REWARD) {
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-payout-reward-sum");
}
return true;
Expand Down Expand Up @@ -132,10 +103,9 @@ bool IsNetInfoTriviallyValid(const ProTx& proTx, TxValidationState& state)
return true;
}

bool CProRegTx::IsTriviallyValid(gsl::not_null<const CBlockIndex*> pindexPrev, const ChainstateManager& chainman,
TxValidationState& state) const
bool CProRegTx::IsTriviallyValid(TxValidationState& state) const
{
if (nVersion == 0 || nVersion > ProTxVersion::GetMaxFromDeployment<decltype(*this)>(pindexPrev, chainman)) {
if (nVersion == 0 || nVersion > ProTxVersion::ExtAddr) {
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-version");
}
if (nVersion < ProTxVersion::BasicBLS && nType == MnType::Evo) {
Expand All @@ -154,7 +124,7 @@ bool CProRegTx::IsTriviallyValid(gsl::not_null<const CBlockIndex*> pindexPrev, c
if (pubKeyOperator.IsLegacy() != (nVersion == ProTxVersion::LegacyBLS)) {
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-operator-pubkey");
}
const auto owner_payouts = GetOwnerPayouts(nVersion, scriptPayout, payouts);
const auto owner_payouts = GetOwnerPayouts(*this);
if (!IsPayoutListTriviallyValid(owner_payouts, keyIDOwner, keyIDVoting, state)) return false;
if (netInfo->CanStorePlatform() != (nVersion >= ProTxVersion::ExtAddr)) {
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-netinfo-version");
Expand Down Expand Up @@ -183,7 +153,7 @@ std::string CProRegTx::MakeSignString() const
// We only include the important stuff in the string form...

CTxDestination dest;
const std::string strPayout = nVersion >= ProTxVersion::MultiPayout
const std::string strPayout = nVersion >= ProTxVersion::ExtAddr
? PayoutListToString(payouts)
: (ExtractDestination(scriptPayout, dest) ? EncodeDestination(dest) : HexStr(scriptPayout));

Expand All @@ -200,7 +170,7 @@ std::string CProRegTx::MakeSignString() const

std::string CProRegTx::ToString() const
{
const std::string payee = PayoutListToString(GetOwnerPayouts(nVersion, scriptPayout, payouts));
const std::string payee = PayoutListToString(GetOwnerPayouts(*this));

return strprintf("CProRegTx(nVersion=%d, nType=%d, collateralOutpoint=%s, netInfo=%s, nOperatorReward=%f, "
"ownerAddress=%s, pubKeyOperator=%s, votingAddress=%s, scriptPayout=%s, platformNodeID=%s%s)\n",
Expand All @@ -212,10 +182,9 @@ std::string CProRegTx::ToString() const
: strprintf(", platformP2PPort=%d, platformHTTPPort=%d", platformP2PPort, platformHTTPPort)));
}

bool CProUpServTx::IsTriviallyValid(gsl::not_null<const CBlockIndex*> pindexPrev, const ChainstateManager& chainman,
TxValidationState& state) const
bool CProUpServTx::IsTriviallyValid(TxValidationState& state) const
{
if (nVersion == 0 || nVersion > ProTxVersion::GetMaxFromDeployment<decltype(*this)>(pindexPrev, chainman)) {
if (nVersion == 0 || nVersion > ProTxVersion::ExtAddr) {
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-version");
}
if (nVersion < ProTxVersion::BasicBLS && nType == MnType::Evo) {
Expand Down Expand Up @@ -257,10 +226,9 @@ std::string CProUpServTx::ToString() const
: strprintf(", platformP2PPort=%d, platformHTTPPort=%d", platformP2PPort, platformHTTPPort)));
}

bool CProUpRegTx::IsTriviallyValid(gsl::not_null<const CBlockIndex*> pindexPrev, const ChainstateManager& chainman,
TxValidationState& state) const
bool CProUpRegTx::IsTriviallyValid(TxValidationState& state) const
{
if (nVersion == 0 || nVersion > ProTxVersion::GetMaxFromDeployment<decltype(*this)>(pindexPrev, chainman)) {
if (nVersion == 0 || nVersion > ProTxVersion::ExtAddr) {
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-version");
}
if (nMode != 0) {
Expand All @@ -273,22 +241,21 @@ bool CProUpRegTx::IsTriviallyValid(gsl::not_null<const CBlockIndex*> pindexPrev,
if (pubKeyOperator.IsLegacy() != (nVersion == ProTxVersion::LegacyBLS)) {
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-operator-pubkey");
}
if (!IsPayoutListTriviallyValid(GetOwnerPayouts(nVersion, scriptPayout, payouts), CKeyID{}, keyIDVoting, state)) return false;
if (!IsPayoutListTriviallyValid(GetOwnerPayouts(*this), CKeyID{}, keyIDVoting, state)) return false;
return true;
}

std::string CProUpRegTx::ToString() const
{
const std::string payee = PayoutListToString(GetOwnerPayouts(nVersion, scriptPayout, payouts));
const std::string payee = PayoutListToString(GetOwnerPayouts(*this));

return strprintf("CProUpRegTx(nVersion=%d, proTxHash=%s, pubKeyOperator=%s, votingAddress=%s, payoutAddress=%s)",
nVersion, proTxHash.ToString(), pubKeyOperator.ToString(), EncodeDestination(PKHash(keyIDVoting)), payee);
}

bool CProUpRevTx::IsTriviallyValid(gsl::not_null<const CBlockIndex*> pindexPrev, const ChainstateManager& chainman,
TxValidationState& state) const
bool CProUpRevTx::IsTriviallyValid(TxValidationState& state) const
{
if (nVersion == 0 || nVersion > ProTxVersion::GetMaxFromDeployment<decltype(*this)>(pindexPrev, chainman)) {
if (nVersion == 0 || nVersion > ProTxVersion::ExtAddr) {
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-protx-version");
}

Expand Down
Loading
Loading