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

feat: implement DIP0026 #5799

Open
wants to merge 15 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
23 changes: 17 additions & 6 deletions src/bloom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,17 @@ bool CBloomFilter::CheckScript(const CScript &script) const
return false;
}

bool CBloomFilter::CheckPayeeSharesScripts(const std::vector<PayoutShare>& payoutShares) const
{
bool scriptCheck = false;
for (const auto& payoutShare : payoutShares) {
if (CheckScript(payoutShare.scriptPayout)) {
scriptCheck = true;
break;
}
}
return scriptCheck;
panleone marked this conversation as resolved.
Show resolved Hide resolved
}
// If the transaction is a special transaction that has a registration
// transaction hash, test the registration transaction hash.
// If the transaction is a special transaction with any public keys or any
Expand All @@ -128,10 +139,10 @@ bool CBloomFilter::CheckSpecialTransactionMatchesAndUpdate(const CTransaction &t
case(TRANSACTION_PROVIDER_REGISTER): {
CProRegTx proTx;
if (GetTxPayload(tx, proTx)) {
if(contains(proTx.collateralOutpoint) ||
contains(proTx.keyIDOwner) ||
contains(proTx.keyIDVoting) ||
CheckScript(proTx.scriptPayout)) {
if (contains(proTx.collateralOutpoint) ||
contains(proTx.keyIDOwner) ||
contains(proTx.keyIDVoting) ||
CheckPayeeSharesScripts(proTx.payoutShares)) {
if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_ALL)
insert(tx.GetHash());
return true;
Expand All @@ -158,8 +169,8 @@ bool CBloomFilter::CheckSpecialTransactionMatchesAndUpdate(const CTransaction &t
if (GetTxPayload(tx, proTx)) {
if(contains(proTx.proTxHash))
return true;
if(contains(proTx.keyIDVoting) ||
CheckScript(proTx.scriptPayout)) {
if (contains(proTx.keyIDVoting) ||
CheckPayeeSharesScripts(proTx.payoutShares)) {
if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_ALL)
insert(proTx.proTxHash);
return true;
Expand Down
2 changes: 2 additions & 0 deletions src/bloom.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class CScript;
class CTransaction;
class CTxOut;
class uint256;
class PayoutShare;

//! 20,000 items with fp rate < 0.1% or 10,000 items and <0.0001%
static constexpr unsigned int MAX_BLOOM_FILTER_SIZE = 36000; // bytes
Expand Down Expand Up @@ -56,6 +57,7 @@ class CBloomFilter

// Check matches for arbitrary script data elements
bool CheckScript(const CScript& script) const;
bool CheckPayeeSharesScripts(const std::vector<PayoutShare>& payoutShares) const;
// Check particular CTxOut helper
bool ProcessTxOut(const CTxOut& txout, const uint256& hash, unsigned int index);
// Check additional matches for special transactions
Expand Down
9 changes: 9 additions & 0 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -829,6 +829,15 @@ class CRegTestParams : public CChainParams {
consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].nFalloffCoeff = 5; // this corresponds to 10 periods
consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].useEHF = true;

consensus.vDeployments[Consensus::DEPLOYMENT_DIP0026].bit = 11;
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0026].nStartTime = 0;
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0026].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0026].nWindowSize = 12;
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0026].nThresholdStart = 9; // 80% of 12
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0026].nThresholdMin = 7; // 60% of 12
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0026].nFalloffCoeff = 5; // this corresponds to 10 periods
consensus.vDeployments[Consensus::DEPLOYMENT_DIP0026].useEHF = true;

panleone marked this conversation as resolved.
Show resolved Hide resolved
// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x00");

Expand Down
6 changes: 3 additions & 3 deletions src/consensus/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,15 @@ enum BuriedDeployment : int16_t
};
constexpr bool ValidDeployment(BuriedDeployment dep) { return DEPLOYMENT_HEIGHTINCB <= dep && dep <= DEPLOYMENT_V19; }

enum DeploymentPos : uint16_t
{
enum DeploymentPos : uint16_t {
panleone marked this conversation as resolved.
Show resolved Hide resolved
DEPLOYMENT_TESTDUMMY,
DEPLOYMENT_V20, // Deployment of EHF, LLMQ Randomness Beacon
DEPLOYMENT_MN_RR, // Deployment of Masternode Reward Location Reallocation
DEPLOYMENT_DIP0026, // Deployment of Multi Payees in a single ProRegTx
// NOTE: Also add new deployments to VersionBitsDeploymentInfo in deploymentinfo.cpp
MAX_VERSION_BITS_DEPLOYMENTS
};
constexpr bool ValidDeployment(DeploymentPos dep) { return DEPLOYMENT_TESTDUMMY <= dep && dep <= DEPLOYMENT_MN_RR; }
constexpr bool ValidDeployment(DeploymentPos dep) { return DEPLOYMENT_TESTDUMMY <= dep && dep <= DEPLOYMENT_DIP0026; }

/**
* Struct for each individual consensus rule change using BIP9.
Expand Down
8 changes: 6 additions & 2 deletions src/deploymentinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@

const struct VBDeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION_BITS_DEPLOYMENTS] = {
{
/*.name =*/ "testdummy",
/*.gbt_force =*/ true,
/*.name =*/"testdummy",
/*.gbt_force =*/true,
panleone marked this conversation as resolved.
Show resolved Hide resolved
},
{
/*.name =*/"v20",
Expand All @@ -19,6 +19,10 @@ const struct VBDeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION_B
/*.name =*/"mn_rr",
/*.gbt_force =*/true,
},
{
/*.name =*/"multi_mn_payee",
/*.gbt_force =*/true,
},
};

std::string DeploymentName(Consensus::BuriedDeployment dep)
Expand Down
13 changes: 7 additions & 6 deletions src/evo/deterministicmns.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -877,7 +877,7 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, gsl::no
newState->pubKeyOperator = proTx.pubKeyOperator;
}
newState->keyIDVoting = proTx.keyIDVoting;
newState->scriptPayout = proTx.scriptPayout;
newState->payoutShares = proTx.payoutShares;

newList.UpdateMN(proTx.proTxHash, newState);

Expand Down Expand Up @@ -1513,7 +1513,8 @@ static std::optional<ProTx> GetValidatedPayload(const CTransaction& tx, gsl::not
return std::nullopt;
}
const bool is_basic_scheme_active{DeploymentActiveAfter(pindexPrev, Params().GetConsensus(), Consensus::DEPLOYMENT_V19)};
if (!ptx.IsTriviallyValid(is_basic_scheme_active, state)) {
const bool is_multi_payout_active{DeploymentActiveAfter(pindexPrev, Params().GetConsensus(), Consensus::DEPLOYMENT_DIP0026)};
if (!ptx.IsTriviallyValid(is_basic_scheme_active, is_multi_payout_active, state)) {
// pass the state returned by the function above
return std::nullopt;
}
Expand Down Expand Up @@ -1706,10 +1707,10 @@ bool CheckProUpRegTx(const CTransaction& tx, gsl::not_null<const CBlockIndex*> p
const auto& ptx{*opt_ptx};

CTxDestination payoutDest;
if (!ExtractDestination(ptx.scriptPayout, payoutDest)) {
// should not happen as we checked script types before
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-payee-dest");
}
const auto& scriptIterator = std::find_if(ptx.payoutShares.begin(), ptx.payoutShares.end(), [&](const auto& payoutShare){
return !ExtractDestination(payoutShare.scriptPayout, payoutDest);
});
if(scriptIterator != ptx.payoutShares.end()) return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-payee-dest");
panleone marked this conversation as resolved.
Show resolved Hide resolved

auto mnList = deterministicMNManager->GetListForBlock(pindexPrev);
auto dmn = mnList.GetMN(ptx.proTxHash);
Expand Down
19 changes: 12 additions & 7 deletions src/evo/dmnstate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ std::string CDeterministicMNState::ToString() const
CTxDestination dest;
std::string payoutAddress = "unknown";
std::string operatorPayoutAddress = "none";
if (ExtractDestination(scriptPayout, dest)) {
if (ExtractDestination(payoutShares[0].scriptPayout, dest)) {
panleone marked this conversation as resolved.
Show resolved Hide resolved
payoutAddress = EncodeDestination(dest);
}
if (ExtractDestination(scriptOperatorPayout, dest)) {
Expand Down Expand Up @@ -52,10 +52,13 @@ UniValue CDeterministicMNState::ToJson(MnType nType) const
obj.pushKV("platformHTTPPort", platformHTTPPort);
}

UniValue payoutArray;
payoutArray.setArray();
CTxDestination dest;
if (ExtractDestination(scriptPayout, dest)) {
obj.pushKV("payoutAddress", EncodeDestination(dest));
for (const auto& payoutShare : payoutShares) {
payoutArray.push_back(payoutShare.ToJson());
}
obj.pushKV("payouts", payoutArray);
obj.pushKV("pubKeyOperator", pubKeyOperator.ToString());
if (ExtractDestination(scriptOperatorPayout, dest)) {
obj.pushKV("operatorPayoutAddress", EncodeDestination(dest));
Expand Down Expand Up @@ -100,11 +103,13 @@ UniValue CDeterministicMNStateDiff::ToJson(MnType nType) const
if (fields & Field_keyIDVoting) {
obj.pushKV("votingAddress", EncodeDestination(PKHash(state.keyIDVoting)));
}
if (fields & Field_scriptPayout) {
CTxDestination dest;
if (ExtractDestination(state.scriptPayout, dest)) {
obj.pushKV("payoutAddress", EncodeDestination(dest));
if (fields & Field_payoutShares) {
UniValue payoutArray;
payoutArray.setArray();
for (const auto& payoutShare : state.payoutShares) {
payoutArray.push_back(payoutShare.ToJson());
}
obj.pushKV("payouts", payoutArray);
}
if (fields & Field_scriptOperatorPayout) {
CTxDestination dest;
Expand Down
22 changes: 14 additions & 8 deletions src/evo/dmnstate.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,8 @@ class CDeterministicMNState
CBLSLazyPublicKey pubKeyOperator;
CKeyID keyIDVoting;
CService addr;
CScript scriptPayout;
// initialized as a vector of length one, in order to deserialize correctly old messages
std::vector<PayoutShare> payoutShares{PayoutShare(CScript())};
CScript scriptOperatorPayout;

uint160 platformNodeID{};
Expand All @@ -170,7 +171,7 @@ class CDeterministicMNState
pubKeyOperator(proTx.pubKeyOperator),
keyIDVoting(proTx.keyIDVoting),
addr(proTx.addr),
scriptPayout(proTx.scriptPayout),
payoutShares(proTx.payoutShares),
platformNodeID(proTx.platformNodeID),
platformP2PPort(proTx.platformP2PPort),
platformHTTPPort(proTx.platformHTTPPort)
Expand All @@ -189,7 +190,7 @@ class CDeterministicMNState
pubKeyOperator(s.pubKeyOperator),
keyIDVoting(s.keyIDVoting),
addr(s.addr),
scriptPayout(s.scriptPayout),
payoutShares({PayoutShare(s.scriptPayout)}),
scriptOperatorPayout(s.scriptOperatorPayout) {}

explicit CDeterministicMNState(const CDeterministicMNState_mntype_format& s) :
Expand All @@ -206,7 +207,7 @@ class CDeterministicMNState
pubKeyOperator(s.pubKeyOperator),
keyIDVoting(s.keyIDVoting),
addr(s.addr),
scriptPayout(s.scriptPayout),
payoutShares({PayoutShare(s.scriptPayout)}),
scriptOperatorPayout(s.scriptOperatorPayout),
platformNodeID(s.platformNodeID),
platformP2PPort(s.platformP2PPort),
Expand Down Expand Up @@ -235,8 +236,13 @@ class CDeterministicMNState
READWRITE(CBLSLazyPublicKeyVersionWrapper(const_cast<CBLSLazyPublicKey&>(obj.pubKeyOperator), obj.nVersion == CProRegTx::LEGACY_BLS_VERSION));
READWRITE(
obj.keyIDVoting,
obj.addr,
obj.scriptPayout,
obj.addr);
if (obj.nVersion < CProRegTx::MULTI_PAYOUT_VERSION) {
READWRITE(obj.payoutShares[0].scriptPayout);
}else{
READWRITE(obj.payoutShares);
}
READWRITE(
obj.scriptOperatorPayout,
obj.platformNodeID,
obj.platformP2PPort,
Expand Down Expand Up @@ -302,7 +308,7 @@ class CDeterministicMNStateDiff
Field_pubKeyOperator = 0x0200,
Field_keyIDVoting = 0x0400,
Field_addr = 0x0800,
Field_scriptPayout = 0x1000,
Field_payoutShares = 0x1000,
Field_scriptOperatorPayout = 0x2000,
Field_nConsecutivePayments = 0x4000,
Field_platformNodeID = 0x8000,
Expand All @@ -324,7 +330,7 @@ class CDeterministicMNStateDiff
DMN_STATE_DIFF_LINE(pubKeyOperator) \
DMN_STATE_DIFF_LINE(keyIDVoting) \
DMN_STATE_DIFF_LINE(addr) \
DMN_STATE_DIFF_LINE(scriptPayout) \
DMN_STATE_DIFF_LINE(payoutShares) \
Copy link

Choose a reason for hiding this comment

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

really surprised it's that simple and does not require any special logic in SERIALIZE_METHODS.

Copy link
Author

Choose a reason for hiding this comment

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

Oh, nice catch! It is not that simple indeed since CDeterministicMNStateDiff does not use the serialization of CDeterministicMNState, but I guess we can use the same trick we did with pubKeyOperator

Copy link
Author

@panleone panleone Jan 8, 2024

Choose a reason for hiding this comment

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

ok, now every std::vector<PayoutShare> is serialized with the same helper class (whose compatibility with older versions is tested in trivially_valid and trivially_invalid unit tests).

CDeterministicMNStateDiff also uses this class + from now on each time it serializes a vector of PayoutShare it serializes also the version.

DMN_STATE_DIFF_LINE(scriptOperatorPayout) \
DMN_STATE_DIFF_LINE(nConsecutivePayments) \
DMN_STATE_DIFF_LINE(platformNodeID) \
Expand Down