From 448cca4a107e2ad9209450af20d38d2afb125ec2 Mon Sep 17 00:00:00 2001
From: jouzo <jdesclercs@gmail.com>
Date: Wed, 14 Dec 2022 14:56:16 +0100
Subject: [PATCH 1/9] Formatting

---
 src/masternodes/rpc_proposals.cpp | 486 +++++++++++++++---------------
 1 file changed, 246 insertions(+), 240 deletions(-)

diff --git a/src/masternodes/rpc_proposals.cpp b/src/masternodes/rpc_proposals.cpp
index 5a1937cfb2..ce264f5c50 100644
--- a/src/masternodes/rpc_proposals.cpp
+++ b/src/masternodes/rpc_proposals.cpp
@@ -1,5 +1,5 @@
-#include <masternodes/mn_rpc.h>
 #include <masternodes/govvariables/attributes.h>
+#include <masternodes/mn_rpc.h>
 
 #include <functional>
 
@@ -9,53 +9,51 @@ struct VotingInfo {
     int32_t votesYes;
 };
 
-UniValue
-proposalToJSON(const CPropId &propId,
-    const CPropObject &prop,
-    const CCustomCSView &view,
-    const std::optional<VotingInfo> votingInfo) {
-
-    auto proposalId = propId.GetHex();
-    auto creationHeight = static_cast<int32_t>(prop.creationHeight);
-    auto title = prop.title;
-    auto context = prop.context;
-    auto contextHash = prop.contextHash;
-    auto type = static_cast<CPropType>(prop.type);
-    auto typeString = CPropTypeToString(type);
-    auto amountValue = ValueFromAmount(prop.nAmount);
-    auto payoutAddress = ScriptToString(prop.address);
-    auto currentCycle   = static_cast<int32_t>(prop.cycle);
-    auto totalCycles = static_cast<int32_t>(prop.nCycles);
-    auto cycleEndHeight = static_cast<int32_t>(prop.cycleEndHeight);
+UniValue proposalToJSON(const CPropId &propId,
+                        const CPropObject &prop,
+                        const CCustomCSView &view,
+                        const std::optional<VotingInfo> votingInfo) {
+    auto proposalId        = propId.GetHex();
+    auto creationHeight    = static_cast<int32_t>(prop.creationHeight);
+    auto title             = prop.title;
+    auto context           = prop.context;
+    auto contextHash       = prop.contextHash;
+    auto type              = static_cast<CPropType>(prop.type);
+    auto typeString        = CPropTypeToString(type);
+    auto amountValue       = ValueFromAmount(prop.nAmount);
+    auto payoutAddress     = ScriptToString(prop.address);
+    auto currentCycle      = static_cast<int32_t>(prop.cycle);
+    auto totalCycles       = static_cast<int32_t>(prop.nCycles);
+    auto cycleEndHeight    = static_cast<int32_t>(prop.cycleEndHeight);
     auto proposalEndHeight = static_cast<int32_t>(prop.proposalEndHeight);
-    auto votingPeriod = static_cast<int32_t>(prop.votingPeriod);
-    bool isEmergency = prop.options & CPropOption::Emergency;
-    auto quorum = prop.quorum;
+    auto votingPeriod      = static_cast<int32_t>(prop.votingPeriod);
+    bool isEmergency       = prop.options & CPropOption::Emergency;
+    auto quorum            = prop.quorum;
     auto approvalThreshold = prop.approvalThreshold;
-    auto status = static_cast<CPropStatusType>(prop.status);
-    auto statusString = CPropStatusToString(status);
-    auto feeTotalValue =  ValueFromAmount(prop.fee);
-    auto feeBurnValue = ValueFromAmount(prop.feeBurnAmount);
+    auto status            = static_cast<CPropStatusType>(prop.status);
+    auto statusString      = CPropStatusToString(status);
+    auto feeTotalValue     = ValueFromAmount(prop.fee);
+    auto feeBurnValue      = ValueFromAmount(prop.feeBurnAmount);
 
-    auto quorumString = strprintf("%d.%02d%%", quorum / 100, quorum % 100);
+    auto quorumString            = strprintf("%d.%02d%%", quorum / 100, quorum % 100);
     auto approvalThresholdString = strprintf("%d.%02d%%", approvalThreshold / 100, approvalThreshold % 100);
 
-    auto votesPossible = -1;
-    auto votesPresent = -1;
-    auto votesPresentPct = -1;
-    auto votesYes = -1;
-    auto votesYesPct = -1;
+    auto votesPossible                = -1;
+    auto votesPresent                 = -1;
+    auto votesPresentPct              = -1;
+    auto votesYes                     = -1;
+    auto votesYesPct                  = -1;
     std::string votesPresentPctString = "-1";
-    std::string votesYesPctString = "-1";
+    std::string votesYesPctString     = "-1";
 
     auto isVotingInfoAvailable = votingInfo.has_value();
     if (isVotingInfoAvailable) {
-        votesPresent = votingInfo->votesPresent;
-        votesYes = votingInfo->votesYes;
+        votesPresent  = votingInfo->votesPresent;
+        votesYes      = votingInfo->votesYes;
         votesPossible = votingInfo->votesPossible;
 
         votesPresentPct = lround(votesPresent * 10000.f / votesPossible);
-        auto valid = votesPresentPct > quorum;
+        auto valid      = votesPresentPct > quorum;
         if (valid) {
             votesYesPct = lround(votesYes * 10000.f / votesPresent);
         }
@@ -66,7 +64,7 @@ proposalToJSON(const CPropId &propId,
         }
 
         votesPresentPctString = strprintf("%d.%02d%%", votesPresentPct / 100, votesPresentPct % 100);
-        votesYesPctString = strprintf("%d.%02d%%", votesYesPct / 100, votesYesPct % 100);
+        votesYesPctString     = strprintf("%d.%02d%%", votesYesPct / 100, votesYesPct % 100);
     }
 
     UniValue ret(UniValue::VOBJ);
@@ -98,8 +96,7 @@ proposalToJSON(const CPropId &propId,
     ret.pushKV("approvalThreshold", approvalThresholdString);
     ret.pushKV("fee", feeTotalValue);
     // ret.pushKV("feeBurn", feeBurnValue);
-    if (prop.options)
-    {
+    if (prop.options) {
         UniValue opt = UniValue(UniValue::VARR);
         if (isEmergency)
             opt.push_back("emergency");
@@ -120,58 +117,71 @@ UniValue proposalVoteToJSON(const CPropId &propId, uint8_t cycle, const uint256
 
 /*
  *  Issued by: any
-*/
-UniValue creategovcfp(const JSONRPCRequest& request)
-{
+ */
+UniValue creategovcfp(const JSONRPCRequest &request) {
     auto pwallet = GetWallet(request);
 
-    RPCHelpMan{"creategovcfp",
-               "\nCreates a Community Fund Proposal" +
-               HelpRequiringPassphrase(pwallet) + "\n",
-               {
-                    {"data", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "data in json-form, containing cfp data",
+    RPCHelpMan{
+        "creategovcfp",
+        "\nCreates a Community Fund Proposal" + HelpRequiringPassphrase(pwallet) + "\n",
+        {
+                                                    {
+                "data",
+                RPCArg::Type::OBJ,
+                RPCArg::Optional::OMITTED_NAMED_ARG,
+                "data in json-form, containing cfp data",
+                {
+                    {"title", RPCArg::Type::STR, RPCArg::Optional::NO, "The title of community fund request"},
+                    {"context", RPCArg::Type::STR, RPCArg::Optional::NO, "The context field of community fund request"},
+                    {"contextHash",
+                     RPCArg::Type::STR,
+                     RPCArg::Optional::OMITTED,
+                     "The hash of the content which context field point to of community fund request"},
+                    {"cycles", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "Defaulted to one cycle"},
+                    {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "Amount in DFI to request"},
+                    {"payoutAddress", RPCArg::Type::STR, RPCArg::Optional::NO, "Any valid address for receiving"},
+                },
+            }, {
+                "inputs",
+                RPCArg::Type::ARR,
+                RPCArg::Optional::OMITTED_NAMED_ARG,
+                "A json array of json objects",
+                {
+                    {
+                        "",
+                        RPCArg::Type::OBJ,
+                        RPCArg::Optional::OMITTED,
+                        "",
                         {
-                            {"title", RPCArg::Type::STR, RPCArg::Optional::NO, "The title of community fund request"},
-                            {"context", RPCArg::Type::STR, RPCArg::Optional::NO, "The context field of community fund request"},
-                            {"contextHash", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "The hash of the content which context field point to of community fund request"},
-                            {"cycles", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "Defaulted to one cycle"},
-                            {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "Amount in DFI to request"},
-                            {"payoutAddress", RPCArg::Type::STR, RPCArg::Optional::NO, "Any valid address for receiving"},
+                            {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
+                            {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
                         },
                     },
-                    {"inputs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "A json array of json objects",
-                        {
-                            {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
-                                 {
-                                         {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
-                                         {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
-                                 },
-                            },
-                        },
-                    },
-               },
-               RPCResult{
-                       "\"hash\"                  (string) The hex-encoded hash of broadcasted transaction\n"
-               },
-               RPCExamples{
-                       HelpExampleCli("creategovcfp", "'{\"title\":\"The cfp title\",\"context\":\"The cfp context\",\"amount\":10,\"payoutAddress\":\"address\"}' '[{\"txid\":\"id\",\"vout\":0}]'")
-                       + HelpExampleRpc("creategovcfp", "'{\"title\":\"The cfp title\",\"context\":\"The cfp context\",\"amount\":10,\"payoutAddress\":\"address\"} '[{\"txid\":\"id\",\"vout\":0}]'")
-               },
-    }.Check(request);
+                },
+            }, },
+        RPCResult{"\"hash\"                  (string) The hex-encoded hash of broadcasted transaction\n"},
+        RPCExamples{
+                                                    HelpExampleCli("creategovcfp",
+                                                    "'{\"title\":\"The cfp title\",\"context\":\"The cfp "
+                           "context\",\"amount\":10,\"payoutAddress\":\"address\"}' '[{\"txid\":\"id\",\"vout\":0}]'") +
+            HelpExampleRpc("creategovcfp",
+                                                    "'{\"title\":\"The cfp title\",\"context\":\"The cfp "
+                           "context\",\"amount\":10,\"payoutAddress\":\"address\"} '[{\"txid\":\"id\",\"vout\":0}]'")},
+    }
+        .Check(request);
 
     if (pwallet->chain().isInitialBlockDownload()) {
-        throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD,
-                           "Cannot create a cfp while still in Initial Block Download");
+        throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Cannot create a cfp while still in Initial Block Download");
     }
     pwallet->BlockUntilSyncedToCurrentChain();
 
-    RPCTypeCheck(request.params, { UniValue::VOBJ, UniValue::VARR }, true);
+    RPCTypeCheck(request.params, {UniValue::VOBJ, UniValue::VARR}, true);
 
     CAmount amount;
     int cycles = 1;
     std::string title, context, contextHash, addressStr;
 
-    const UniValue& data = request.params[0].get_obj();
+    const UniValue &data = request.params[0].get_obj();
 
     if (!data["title"].isNull()) {
         title = data["title"].get_str();
@@ -210,30 +220,30 @@ UniValue creategovcfp(const JSONRPCRequest& request)
     }
 
     CCreatePropMessage pm;
-    pm.type = CPropType::CommunityFundProposal;
-    pm.address = GetScriptForDestination(address);
-    pm.nAmount = amount;
-    pm.nCycles = cycles;
-    pm.title = title;
-    pm.context = context;
+    pm.type        = CPropType::CommunityFundProposal;
+    pm.address     = GetScriptForDestination(address);
+    pm.nAmount     = amount;
+    pm.nCycles     = cycles;
+    pm.title       = title;
+    pm.context     = context;
     pm.contextHash = contextHash;
-    pm.options = 0;
+    pm.options     = 0;
 
     // encode
     CDataStream metadata(DfTxMarker, SER_NETWORK, PROTOCOL_VERSION);
-    metadata << static_cast<unsigned char>(CustomTxType::CreateCfp)
-             << pm;
+    metadata << static_cast<unsigned char>(CustomTxType::CreateCfp) << pm;
 
     CScript scriptMeta;
     scriptMeta << OP_RETURN << ToByteVector(metadata);
 
-    auto targetHeight = pcustomcsview->GetLastHeight() + 1;
+    auto targetHeight    = pcustomcsview->GetLastHeight() + 1;
     const auto txVersion = GetTransactionVersion(targetHeight);
     CMutableTransaction rawTx(txVersion);
 
     CTransactionRef optAuthTx;
     std::set<CScript> auths{pm.address};
-    rawTx.vin = GetAuthInputsSmart(pwallet, rawTx.nVersion, auths, false /*needFoundersAuth*/, optAuthTx, request.params[1]);
+    rawTx.vin =
+        GetAuthInputsSmart(pwallet, rawTx.nVersion, auths, false /*needFoundersAuth*/, optAuthTx, request.params[1]);
 
     auto cfpFee = GetPropsCreationFee(targetHeight, *pcustomcsview, pm);
     rawTx.vout.emplace_back(CTxOut(cfpFee, scriptMeta));
@@ -256,54 +266,63 @@ UniValue creategovcfp(const JSONRPCRequest& request)
     return signsend(rawTx, pwallet, optAuthTx)->GetHash().GetHex();
 }
 
-UniValue creategovvoc(const JSONRPCRequest& request)
-{
+UniValue creategovvoc(const JSONRPCRequest &request) {
     auto pwallet = GetWallet(request);
 
-    RPCHelpMan{"creategovvoc",
-               "\nCreates a Vote of Confidence" +
-               HelpRequiringPassphrase(pwallet) + "\n",
-               {
-                    {"data", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "data in json-form, containing voc data",
-                        {
-                            {"title", RPCArg::Type::STR, RPCArg::Optional::NO, "The title of vote of confidence"},
-                            {"context", RPCArg::Type::STR, RPCArg::Optional::NO, "The context field for vote of confidence"},
-                            {"contextHash", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "The hash of the content which context field point to of vote of confidence request"},
-                            {"emergency", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Is this emergency VOC"},
-                        },
-                    },
-                    {"inputs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "A json array of json objects",
+    RPCHelpMan{
+        "creategovvoc",
+        "\nCreates a Vote of Confidence" + HelpRequiringPassphrase(pwallet) + "\n",
+        {
+                                                    {
+                "data",
+                RPCArg::Type::OBJ,
+                RPCArg::Optional::OMITTED_NAMED_ARG,
+                "data in json-form, containing voc data",
+                {
+                    {"title", RPCArg::Type::STR, RPCArg::Optional::NO, "The title of vote of confidence"},
+                    {"context", RPCArg::Type::STR, RPCArg::Optional::NO, "The context field for vote of confidence"},
+                    {"contextHash",
+                     RPCArg::Type::STR,
+                     RPCArg::Optional::OMITTED,
+                     "The hash of the content which context field point to of vote of confidence request"},
+                    {"emergency", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Is this emergency VOC"},
+                },
+            }, {
+                "inputs",
+                RPCArg::Type::ARR,
+                RPCArg::Optional::OMITTED_NAMED_ARG,
+                "A json array of json objects",
+                {
+                    {
+                        "",
+                        RPCArg::Type::OBJ,
+                        RPCArg::Optional::OMITTED,
+                        "",
                         {
-                            {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
-                                {
-                                    {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
-                                    {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
-                                },
-                            },
+                            {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
+                            {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
                         },
                     },
-               },
-               RPCResult{
-                       "\"hash\"                  (string) The hex-encoded hash of broadcasted transaction\n"
-               },
-               RPCExamples{
-                       HelpExampleCli("creategovvoc", "'The voc title' 'The voc context' '[{\"txid\":\"id\",\"vout\":0}]'")
-                       + HelpExampleRpc("creategovvoc", "'The voc title' 'The voc context' '[{\"txid\":\"id\",\"vout\":0}]'")
-               },
-    }.Check(request);
+                },
+            }, },
+        RPCResult{"\"hash\"                  (string) The hex-encoded hash of broadcasted transaction\n"},
+        RPCExamples{
+                                                    HelpExampleCli("creategovvoc", "'The voc title' 'The voc context' '[{\"txid\":\"id\",\"vout\":0}]'") +
+            HelpExampleRpc("creategovvoc", "'The voc title' 'The voc context' '[{\"txid\":\"id\",\"vout\":0}]'")},
+    }
+        .Check(request);
 
     if (pwallet->chain().isInitialBlockDownload()) {
-        throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD,
-                           "Cannot create a voc while still in Initial Block Download");
+        throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Cannot create a voc while still in Initial Block Download");
     }
     pwallet->BlockUntilSyncedToCurrentChain();
 
-    RPCTypeCheck(request.params, { UniValue::VOBJ, UniValue::VARR }, true);
+    RPCTypeCheck(request.params, {UniValue::VOBJ, UniValue::VARR}, true);
 
     std::string title, context, contextHash;
     bool emergency = false;
 
-    const UniValue& data = request.params[0].get_obj();
+    const UniValue &data = request.params[0].get_obj();
 
     if (!data["title"].isNull()) {
         title = data["title"].get_str();
@@ -320,35 +339,34 @@ UniValue creategovvoc(const JSONRPCRequest& request)
     if (!data["contextHash"].isNull())
         contextHash = data["contextHash"].get_str();
 
-    if (!data["emergency"].isNull())
-    {
+    if (!data["emergency"].isNull()) {
         emergency = data["emergency"].get_bool();
     }
 
     CCreatePropMessage pm;
-    pm.type = CPropType::VoteOfConfidence;
-    pm.nAmount = 0;
-    pm.nCycles = (emergency ? 1 : VOC_CYCLES);
-    pm.title = title;
-    pm.context = context;
+    pm.type        = CPropType::VoteOfConfidence;
+    pm.nAmount     = 0;
+    pm.nCycles     = (emergency ? 1 : VOC_CYCLES);
+    pm.title       = title;
+    pm.context     = context;
     pm.contextHash = contextHash;
-    pm.options = (emergency ? CPropOption::Emergency : 0);
+    pm.options     = (emergency ? CPropOption::Emergency : 0);
 
     // encode
     CDataStream metadata(DfTxMarker, SER_NETWORK, PROTOCOL_VERSION);
-    metadata << static_cast<unsigned char>(CustomTxType::CreateVoc)
-             << pm;
+    metadata << static_cast<unsigned char>(CustomTxType::CreateVoc) << pm;
 
     CScript scriptMeta;
     scriptMeta << OP_RETURN << ToByteVector(metadata);
 
-    auto targetHeight = pcustomcsview->GetLastHeight() + 1;
+    auto targetHeight    = pcustomcsview->GetLastHeight() + 1;
     const auto txVersion = GetTransactionVersion(targetHeight);
     CMutableTransaction rawTx(txVersion);
 
     CTransactionRef optAuthTx;
     std::set<CScript> auths;
-    rawTx.vin = GetAuthInputsSmart(pwallet, rawTx.nVersion, auths, false /*needFoundersAuth*/, optAuthTx, request.params[1]);
+    rawTx.vin =
+        GetAuthInputsSmart(pwallet, rawTx.nVersion, auths, false /*needFoundersAuth*/, optAuthTx, request.params[1]);
 
     auto vocFee = GetPropsCreationFee(targetHeight, *pcustomcsview, pm);
     rawTx.vout.emplace_back(CTxOut(vocFee, scriptMeta));
@@ -371,48 +389,50 @@ UniValue creategovvoc(const JSONRPCRequest& request)
     return signsend(rawTx, pwallet, optAuthTx)->GetHash().GetHex();
 }
 
-UniValue votegov(const JSONRPCRequest& request)
-{
+UniValue votegov(const JSONRPCRequest &request) {
     auto pwallet = GetWallet(request);
 
-    RPCHelpMan{"votegov",
-               "\nVote for community proposal" +
-               HelpRequiringPassphrase(pwallet) + "\n",
-               {
-                       {"proposalId", RPCArg::Type::STR, RPCArg::Optional::NO, "The proposal txid"},
-                       {"masternodeId", RPCArg::Type::STR, RPCArg::Optional::NO, "The masternode id which made the vote"},
-                       {"decision", RPCArg::Type::STR, RPCArg::Optional::NO, "The vote decision (yes/no/neutral)"},
-                       {"inputs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "A json array of json objects",
+    RPCHelpMan{
+        "votegov",
+        "\nVote for community proposal" + HelpRequiringPassphrase(pwallet) + "\n",
+        {
+                                                    {"proposalId", RPCArg::Type::STR, RPCArg::Optional::NO, "The proposal txid"},
+                                                    {"masternodeId", RPCArg::Type::STR, RPCArg::Optional::NO, "The masternode id which made the vote"},
+                                                    {"decision", RPCArg::Type::STR, RPCArg::Optional::NO, "The vote decision (yes/no/neutral)"},
+                                                    {
+                "inputs",
+                RPCArg::Type::ARR,
+                RPCArg::Optional::OMITTED_NAMED_ARG,
+                "A json array of json objects",
+                {
+                    {
+                        "",
+                        RPCArg::Type::OBJ,
+                        RPCArg::Optional::OMITTED,
+                        "",
                         {
-                                {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
-                                 {
-                                         {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
-                                         {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
-                                 },
-                                },
+                            {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
+                            {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
                         },
-                       },
-               },
-               RPCResult{
-                       "\"hash\"                  (string) The hex-encoded hash of broadcasted transaction\n"
-               },
-               RPCExamples{
-                       HelpExampleCli("votegov", "txid masternodeId yes")
-                       + HelpExampleRpc("votegov", "txid masternodeId yes")
-               },
-    }.Check(request);
+                    },
+                },
+            }, },
+        RPCResult{"\"hash\"                  (string) The hex-encoded hash of broadcasted transaction\n"},
+        RPCExamples{HelpExampleCli("votegov", "txid masternodeId yes") +
+                    HelpExampleRpc("votegov", "txid masternodeId yes")},
+    }
+        .Check(request);
 
     if (pwallet->chain().isInitialBlockDownload()) {
-        throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD,
-                           "Cannot vote while still in Initial Block Download");
+        throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Cannot vote while still in Initial Block Download");
     }
     pwallet->BlockUntilSyncedToCurrentChain();
 
-    RPCTypeCheck(request.params, { UniValue::VSTR, UniValue::VSTR, UniValue::VSTR, UniValue::VARR }, true);
+    RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VSTR, UniValue::VSTR, UniValue::VARR}, true);
 
     auto propId = ParseHashV(request.params[0].get_str(), "proposalId");
-    auto mnId = ParseHashV(request.params[1].get_str(), "masternodeId");
-    auto vote = CPropVoteType::VoteNeutral;
+    auto mnId   = ParseHashV(request.params[1].get_str(), "masternodeId");
+    auto vote   = CPropVoteType::VoteNeutral;
 
     auto voteStr = ToLower(request.params[2].get_str());
     if (voteStr == "no") {
@@ -433,26 +453,27 @@ UniValue votegov(const JSONRPCRequest& request)
             throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Proposal <%s> does not exist", propId.GetHex()));
         }
         if (prop->status != CPropStatusType::Voting) {
-            throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Proposal <%s> is not in voting period", propId.GetHex()));
+            throw JSONRPCError(RPC_INVALID_PARAMETER,
+                               strprintf("Proposal <%s> is not in voting period", propId.GetHex()));
         }
         auto node = view.GetMasternode(mnId);
         if (!node) {
             throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("The masternode %s does not exist", mnId.ToString()));
         }
-        ownerDest = node->ownerType == 1 ? CTxDestination(PKHash(node->ownerAuthAddress)) : CTxDestination(WitnessV0KeyHash(node->ownerAuthAddress));
+        ownerDest = node->ownerType == 1 ? CTxDestination(PKHash(node->ownerAuthAddress))
+                                         : CTxDestination(WitnessV0KeyHash(node->ownerAuthAddress));
 
         targetHeight = view.GetLastHeight() + 1;
     }
 
     CPropVoteMessage msg;
-    msg.propId = propId;
+    msg.propId       = propId;
     msg.masternodeId = mnId;
-    msg.vote = vote;
+    msg.vote         = vote;
 
     // encode
     CDataStream metadata(DfTxMarker, SER_NETWORK, PROTOCOL_VERSION);
-    metadata << static_cast<unsigned char>(CustomTxType::Vote)
-             << msg;
+    metadata << static_cast<unsigned char>(CustomTxType::Vote) << msg;
 
     CScript scriptMeta;
     scriptMeta << OP_RETURN << ToByteVector(metadata);
@@ -461,8 +482,9 @@ UniValue votegov(const JSONRPCRequest& request)
     CMutableTransaction rawTx(txVersion);
 
     CTransactionRef optAuthTx;
-    std::set<CScript> auths = { GetScriptForDestination(ownerDest) };
-    rawTx.vin = GetAuthInputsSmart(pwallet, rawTx.nVersion, auths, false /*needFoundersAuth*/, optAuthTx, request.params[3]);
+    std::set<CScript> auths = {GetScriptForDestination(ownerDest)};
+    rawTx.vin =
+        GetAuthInputsSmart(pwallet, rawTx.nVersion, auths, false /*needFoundersAuth*/, optAuthTx, request.params[3]);
 
     rawTx.vout.emplace_back(CTxOut(0, scriptMeta));
 
@@ -479,24 +501,21 @@ UniValue votegov(const JSONRPCRequest& request)
     return signsend(rawTx, pwallet, optAuthTx)->GetHash().GetHex();
 }
 
-UniValue listgovproposalvotes(const JSONRPCRequest& request)
-{
+UniValue listgovproposalvotes(const JSONRPCRequest &request) {
     auto pwallet = GetWallet(request);
-    RPCHelpMan{"listgovproposalvotes",
-               "\nReturns information about proposal votes.\n",
-               {
-                        {"proposalId", RPCArg::Type::STR, RPCArg::Optional::NO, "The proposal id)"},
-                        {"masternode", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "mine/all/id (default = mine)"},
-                        {"cycle", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "cycle: 0 (show current), cycle: N (show cycle N), cycle: -1 (show all) (default = 0)"}
-               },
-               RPCResult{
-                       "{id:{...},...}     (array) Json object with proposal vote information\n"
-               },
-               RPCExamples{
-                       HelpExampleCli("listgovproposalvotes", "txid")
-                       + HelpExampleRpc("listgovproposalvotes", "txid")
-               },
-    }.Check(request);
+    RPCHelpMan{
+        "listgovproposalvotes",
+        "\nReturns information about proposal votes.\n",
+        {{"proposalId", RPCArg::Type::STR, RPCArg::Optional::NO, "The proposal id)"},
+          {"masternode", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "mine/all/id (default = mine)"},
+          {"cycle",
+          RPCArg::Type::NUM,
+          RPCArg::Optional::OMITTED,
+          "cycle: 0 (show current), cycle: N (show cycle N), cycle: -1 (show all) (default = 0)"}},
+        RPCResult{"{id:{...},...}     (array) Json object with proposal vote information\n"},
+        RPCExamples{HelpExampleCli("listgovproposalvotes", "txid") + HelpExampleRpc("listgovproposalvotes", "txid")},
+    }
+        .Check(request);
 
     RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VSTR, UniValue::VNUM}, true);
 
@@ -510,7 +529,7 @@ UniValue listgovproposalvotes(const JSONRPCRequest& request)
             isMine = false;
         } else if (str != "mine") {
             isMine = false;
-            mnId = ParseHashV(str, "masternode");
+            mnId   = ParseHashV(str, "masternode");
         }
     }
     CCustomCSView view(*pcustomcsview);
@@ -520,15 +539,15 @@ UniValue listgovproposalvotes(const JSONRPCRequest& request)
     if (request.params.size() > 2) {
         inputCycle = request.params[2].get_int();
     }
-    if (inputCycle==0){
+    if (inputCycle == 0) {
         auto prop = view.GetProp(propId);
-        if (!prop){
+        if (!prop) {
             throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Proposal <%s> does not exist", propId.GetHex()));
         }
         cycle = prop->cycle;
-    } else if (inputCycle > 0){
+    } else if (inputCycle > 0) {
         cycle = inputCycle;
-    } else if (inputCycle == -1){
+    } else if (inputCycle == -1) {
         cycle = 1;
     } else {
         throw JSONRPCError(RPC_INVALID_PARAMETER, "Incorrect cycle value");
@@ -566,21 +585,17 @@ UniValue listgovproposalvotes(const JSONRPCRequest& request)
     return ret;
 }
 
-UniValue getgovproposal(const JSONRPCRequest& request)
-{
-    RPCHelpMan{"getgovproposal",
-               "\nReturns real time information about proposal state.\n",
-               {
-                        {"proposalId", RPCArg::Type::STR, RPCArg::Optional::NO, "The proposal id)"},
-               },
-               RPCResult{
-                       "{id:{...},...}     (obj) Json object with proposal vote information\n"
-               },
-               RPCExamples{
-                       HelpExampleCli("getgovproposal", "txid")
-                       + HelpExampleRpc("getgovproposal", "txid")
-               },
-    }.Check(request);
+UniValue getgovproposal(const JSONRPCRequest &request) {
+    RPCHelpMan{
+        "getgovproposal",
+        "\nReturns real time information about proposal state.\n",
+        {
+          {"proposalId", RPCArg::Type::STR, RPCArg::Optional::NO, "The proposal id)"},
+          },
+        RPCResult{"{id:{...},...}     (obj) Json object with proposal vote information\n"},
+        RPCExamples{HelpExampleCli("getgovproposal", "txid") + HelpExampleRpc("getgovproposal", "txid")},
+    }
+        .Check(request);
 
     RPCTypeCheck(request.params, {UniValue::VSTR}, true);
 
@@ -632,30 +647,22 @@ UniValue getgovproposal(const JSONRPCRequest& request)
 
     VotingInfo info;
     info.votesPossible = activeMasternodes.size();
-    info.votesPresent = voters;
-    info.votesYes = voteYes;
+    info.votesPresent  = voters;
+    info.votesYes      = voteYes;
 
     return proposalToJSON(propId, *prop, view, info);
 }
 
-UniValue listgovproposals(const JSONRPCRequest& request)
-{
-    RPCHelpMan{"listgovproposals",
-               "\nReturns information about proposals.\n",
-               {
-                        {"type", RPCArg::Type::STR, RPCArg::Optional::OMITTED,
-                                    "cfp/voc/all (default = all)"},
-                        {"status", RPCArg::Type::STR, RPCArg::Optional::OMITTED,
-                                    "voting/rejected/completed/all (default = all)"}
-               },
-               RPCResult{
-                       "{id:{...},...}     (array) Json object with proposals information\n"
-               },
-               RPCExamples{
-                       HelpExampleCli("listgovproposals", "")
-                       + HelpExampleRpc("listgovproposals", "")
-               },
-    }.Check(request);
+UniValue listgovproposals(const JSONRPCRequest &request) {
+    RPCHelpMan{
+        "listgovproposals",
+        "\nReturns information about proposals.\n",
+        {{"type", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "cfp/voc/all (default = all)"},
+          {"status", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "voting/rejected/completed/all (default = all)"}},
+        RPCResult{"{id:{...},...}     (array) Json object with proposals information\n"},
+        RPCExamples{HelpExampleCli("listgovproposals", "") + HelpExampleRpc("listgovproposals", "")},
+    }
+        .Check(request);
 
     RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VSTR}, true);
 
@@ -704,19 +711,18 @@ UniValue listgovproposals(const JSONRPCRequest& request)
     return ret;
 }
 
-static const CRPCCommand commands[] =
-{
-//  category        name                     actor (function)        params
-//  --------------- ----------------------   ---------------------   ----------
-    {"proposals",   "creategovcfp",          &creategovcfp,          {"data", "inputs"} },
-    {"proposals",   "creategovvoc",          &creategovvoc,          {"data", "inputs"} },
-    {"proposals",   "votegov",               &votegov,               {"proposalId", "masternodeId", "decision", "inputs"} },
-    {"proposals",   "listgovproposalvotes",  &listgovproposalvotes,  {"proposalId", "masternode", "cycle"} },
-    {"proposals",   "getgovproposal",        &getgovproposal,        {"proposalId"} },
-    {"proposals",   "listgovproposals",      &listgovproposals,      {"type", "status"} },
+static const CRPCCommand commands[] = {
+  //  category        name                     actor (function)        params
+  //  --------------- ----------------------   ---------------------   ----------
+    {"proposals", "creategovcfp",         &creategovcfp,         {"data", "inputs"}                                  },
+    {"proposals", "creategovvoc",         &creategovvoc,         {"data", "inputs"}                                  },
+    {"proposals", "votegov",              &votegov,              {"proposalId", "masternodeId", "decision", "inputs"}},
+    {"proposals", "listgovproposalvotes", &listgovproposalvotes, {"proposalId", "masternode", "cycle"}               },
+    {"proposals", "getgovproposal",       &getgovproposal,       {"proposalId"}                                      },
+    {"proposals", "listgovproposals",     &listgovproposals,     {"type", "status"}                                  },
 };
 
-void RegisterProposalRPCCommands(CRPCTable& tableRPC) {
+void RegisterProposalRPCCommands(CRPCTable &tableRPC) {
     for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
         tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
 }

From eb62a5dbef099bb1a137dffda2897d8f744f6784 Mon Sep 17 00:00:00 2001
From: jouzo <jdesclercs@gmail.com>
Date: Wed, 14 Dec 2022 14:56:26 +0100
Subject: [PATCH 2/9] Remove overwriting proposal status

---
 src/masternodes/rpc_proposals.cpp | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/src/masternodes/rpc_proposals.cpp b/src/masternodes/rpc_proposals.cpp
index ce264f5c50..df5ada3b97 100644
--- a/src/masternodes/rpc_proposals.cpp
+++ b/src/masternodes/rpc_proposals.cpp
@@ -57,11 +57,6 @@ UniValue proposalToJSON(const CPropId &propId,
         if (valid) {
             votesYesPct = lround(votesYes * 10000.f / votesPresent);
         }
-        if (valid && votesYesPct > approvalThreshold) {
-            statusString = "Completed";
-        } else {
-            statusString = "Rejected";
-        }
 
         votesPresentPctString = strprintf("%d.%02d%%", votesPresentPct / 100, votesPresentPct % 100);
         votesYesPctString     = strprintf("%d.%02d%%", votesYesPct / 100, votesYesPct % 100);

From 710c4fe47afcefd7e9e4eb025edc3552a71c9de7 Mon Sep 17 00:00:00 2001
From: jouzo <jdesclercs@gmail.com>
Date: Wed, 14 Dec 2022 14:56:41 +0100
Subject: [PATCH 3/9] Fix tests

---
 test/functional/feature_on_chain_government.py              | 6 ++++--
 .../functional/feature_on_chain_government_govvar_update.py | 4 ++--
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/test/functional/feature_on_chain_government.py b/test/functional/feature_on_chain_government.py
index 270567459d..af795dc353 100755
--- a/test/functional/feature_on_chain_government.py
+++ b/test/functional/feature_on_chain_government.py
@@ -277,6 +277,7 @@ def run_test(self):
 
         cycle1 = creationHeight + (votingPeriod - creationHeight % votingPeriod) + votingPeriod
         proposalEndHeight = cycle1
+
         # Check results
         result = self.nodes[0].getgovproposal(tx)
         assert_equal(result["proposalId"], tx)
@@ -284,7 +285,7 @@ def run_test(self):
         assert_equal(result["title"], title)
         assert_equal(result["context"], context)
         assert_equal(result["contextHash"], "")
-        assert_equal(result["status"], "Completed")
+        assert_equal(result["status"], "Voting")
         assert_equal(result["type"], "VoteOfConfidence")
         assert_equal(result["currentCycle"], 1)
         assert_equal(result["totalCycles"], 1)
@@ -503,6 +504,7 @@ def run_test(self):
 
         cycle1 = creationHeight + (emergencyPeriod - creationHeight % emergencyPeriod) + emergencyPeriod
         proposalEndHeight = creationHeight + emergencyPeriod
+
         # Check results
         result = self.nodes[0].getgovproposal(tx)
         assert_equal(result["proposalId"], tx)
@@ -510,7 +512,7 @@ def run_test(self):
         assert_equal(result["title"], title)
         assert_equal(result["context"], context)
         assert_equal(result["contextHash"], "")
-        assert_equal(result["status"], "Rejected")
+        assert_equal(result["status"], "Voting")
         assert_equal(result["type"], "VoteOfConfidence")
         assert_equal(result["currentCycle"], 1)
         assert_equal(result["totalCycles"], 1)
diff --git a/test/functional/feature_on_chain_government_govvar_update.py b/test/functional/feature_on_chain_government_govvar_update.py
index 14871ec950..864286d606 100755
--- a/test/functional/feature_on_chain_government_govvar_update.py
+++ b/test/functional/feature_on_chain_government_govvar_update.py
@@ -515,10 +515,10 @@ def test_cfp_state_after_update(self):
 
         # Vote and move to next cycle
         self.nodes[3].votegov(propId, self.mn3, "no")
-        self.nodes[3].generate(VOTING_PERIOD)
+        proposal = self.nodes[0].getgovproposal(propId)
+        self.nodes[3].generate(proposal["proposalEndHeight"] - self.nodes[3].getblockcount())
         self.sync_blocks(timeout=120)
 
-        # First cycle should be completed
         proposal = self.nodes[0].getgovproposal(propId)
         assert_equal(proposal['status'], 'Completed')
 

From 0aae6524d86f2998803bd3283b8e765d5d993574 Mon Sep 17 00:00:00 2001
From: jouzo <jdesclercs@gmail.com>
Date: Wed, 14 Dec 2022 22:33:46 +0100
Subject: [PATCH 4/9] Remove valid check

---
 src/masternodes/rpc_proposals.cpp | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/src/masternodes/rpc_proposals.cpp b/src/masternodes/rpc_proposals.cpp
index df5ada3b97..4ef78b9967 100644
--- a/src/masternodes/rpc_proposals.cpp
+++ b/src/masternodes/rpc_proposals.cpp
@@ -53,10 +53,7 @@ UniValue proposalToJSON(const CPropId &propId,
         votesPossible = votingInfo->votesPossible;
 
         votesPresentPct = lround(votesPresent * 10000.f / votesPossible);
-        auto valid      = votesPresentPct > quorum;
-        if (valid) {
-            votesYesPct = lround(votesYes * 10000.f / votesPresent);
-        }
+        votesYesPct     = lround(votesYes * 10000.f / votesPresent);
 
         votesPresentPctString = strprintf("%d.%02d%%", votesPresentPct / 100, votesPresentPct % 100);
         votesYesPctString     = strprintf("%d.%02d%%", votesYesPct / 100, votesYesPct % 100);

From bddcc2f507295bb141791d33ef81f5c8d7ff76f0 Mon Sep 17 00:00:00 2001
From: jouzo <jdesclercs@gmail.com>
Date: Tue, 6 Dec 2022 10:27:03 +0100
Subject: [PATCH 5/9] Fix ForEachCycleProp returning early

---
 src/validation.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/validation.cpp b/src/validation.cpp
index e7616fe88e..a0a6a0e103 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -4208,7 +4208,7 @@ void CChainState::ProcessProposalEvents(const CBlockIndex* pindex, CCustomCSView
 
     std::set<uint256> activeMasternodes;
     cache.ForEachCycleProp([&](CPropId const& propId, CPropObject const& prop) {
-        if (prop.status != CPropStatusType::Voting) return false;
+        if (prop.status != CPropStatusType::Voting) return true;
 
         if (activeMasternodes.empty()) {
             cache.ForEachMasternode([&](uint256 const & mnId, CMasternode node) {

From b357b93686be018f0fb7d932c635bdf270383493 Mon Sep 17 00:00:00 2001
From: jouzo <jdesclercs@gmail.com>
Date: Fri, 23 Dec 2022 12:06:58 +0100
Subject: [PATCH 6/9] Format proposals.cpp

---
 src/masternodes/proposals.cpp | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/src/masternodes/proposals.cpp b/src/masternodes/proposals.cpp
index 6d5fd22d93..43158dbfc0 100644
--- a/src/masternodes/proposals.cpp
+++ b/src/masternodes/proposals.cpp
@@ -53,12 +53,12 @@ Res CPropsView::CreateProp(const CPropId &propId, uint32_t height, const CCreate
     bool emergency = prop.options & CPropOption::Emergency;
     auto type      = static_cast<CPropType>(prop.type);
 
-    prop.creationHeight     = height;
-    prop.votingPeriod       = (emergency ? GetEmergencyPeriodFromAttributes(type) : GetVotingPeriodFromAttributes());
-    prop.approvalThreshold  = GetApprovalThresholdFromAttributes(type);
-    prop.quorum             = GetQuorumFromAttributes(type, emergency);
-    prop.fee                = fee;
-    prop.feeBurnAmount      = MultiplyAmounts(fee, GetFeeBurnPctFromAttributes());
+    prop.creationHeight    = height;
+    prop.votingPeriod      = (emergency ? GetEmergencyPeriodFromAttributes(type) : GetVotingPeriodFromAttributes());
+    prop.approvalThreshold = GetApprovalThresholdFromAttributes(type);
+    prop.quorum            = GetQuorumFromAttributes(type, emergency);
+    prop.fee               = fee;
+    prop.feeBurnAmount     = MultiplyAmounts(fee, GetFeeBurnPctFromAttributes());
 
     auto key = std::make_pair(uint8_t(CPropStatusType::Voting), propId);
     WriteBy<ByStatus>(key, static_cast<uint8_t>(1));
@@ -120,8 +120,8 @@ Res CPropsView::UpdatePropCycle(const CPropId &propId, uint8_t cycle) {
     bool emergency = prop->options & CPropOption::Emergency;
     auto type      = static_cast<CPropType>(prop->type);
 
-    prop->approvalThreshold  = GetApprovalThresholdFromAttributes(type);
-    prop->quorum             = GetQuorumFromAttributes(type, emergency);
+    prop->approvalThreshold = GetApprovalThresholdFromAttributes(type);
+    prop->quorum            = GetQuorumFromAttributes(type, emergency);
     WriteBy<ByType>(propId, *prop);
 
     return Res::Ok();

From ab39d089b7183f5d3b3d1ce24c9e16d8abcf77aa Mon Sep 17 00:00:00 2001
From: jouzo <jdesclercs@gmail.com>
Date: Fri, 23 Dec 2022 12:07:23 +0100
Subject: [PATCH 7/9] Remove UpdatePropCycle range guard

---
 src/masternodes/proposals.cpp | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/src/masternodes/proposals.cpp b/src/masternodes/proposals.cpp
index 43158dbfc0..bcfabb99ff 100644
--- a/src/masternodes/proposals.cpp
+++ b/src/masternodes/proposals.cpp
@@ -101,9 +101,6 @@ std::optional<CPropObject> CPropsView::GetProp(const CPropId &propId) {
 }
 
 Res CPropsView::UpdatePropCycle(const CPropId &propId, uint8_t cycle) {
-    if (cycle < 1 || cycle > MAX_CYCLES)
-        return Res::Err("Cycle out of range");
-
     auto key    = std::make_pair(uint8_t(CPropStatusType::Voting), propId);
     auto pcycle = ReadBy<ByStatus, uint8_t>(key);
     if (!pcycle)

From 305c0af44f152e21f7f6e5804f1f04f01a991edc Mon Sep 17 00:00:00 2001
From: Mihailo Milenkovic <mihailo.milenkovic84@gmail.com>
Date: Fri, 23 Dec 2022 12:35:29 +0100
Subject: [PATCH 8/9] Add attribute for cfp max cycles

---
 src/masternodes/govvariables/attributes.cpp | 5 ++++-
 src/masternodes/govvariables/attributes.h   | 1 +
 src/masternodes/mn_checks.cpp               | 9 +++++++--
 3 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/src/masternodes/govvariables/attributes.cpp b/src/masternodes/govvariables/attributes.cpp
index 392a03ba0e..26266f97f6 100644
--- a/src/masternodes/govvariables/attributes.cpp
+++ b/src/masternodes/govvariables/attributes.cpp
@@ -205,6 +205,7 @@ const std::map<uint8_t, std::map<std::string, uint8_t>> &ATTRIBUTES::allowedKeys
              {"voc_approval_threshold", GovernanceKeys::VOCApprovalThreshold},
              {"quorum", GovernanceKeys::Quorum},
              {"voting_period", GovernanceKeys::VotingPeriod},
+             {"cfo_max_cycles", GovernanceKeys::CFPMaxCycles},
          }},
     };
     return keys;
@@ -297,6 +298,7 @@ const std::map<uint8_t, std::map<uint8_t, std::string>> &ATTRIBUTES::displayKeys
              {GovernanceKeys::VOCApprovalThreshold, "voc_approval_threshold"},
              {GovernanceKeys::Quorum, "quorum"},
              {GovernanceKeys::VotingPeriod, "voting_period"},
+             {GovernanceKeys::CFPMaxCycles, "cfp_max_cycles"},
          }},
     };
     return keys;
@@ -607,6 +609,7 @@ const std::map<uint8_t, std::map<uint8_t, std::function<ResVal<CAttributeValue>(
                  {GovernanceKeys::VOCApprovalThreshold, VerifyPct},
                  {GovernanceKeys::Quorum, VerifyPct},
                  {GovernanceKeys::VotingPeriod, VerifyUInt32},
+                 {GovernanceKeys::CFPMaxCycles, VerifyUInt32},
              }},
     };
     return parsers;
@@ -819,7 +822,7 @@ Res ATTRIBUTES::ProcessVariable(const std::string &key,
                     typeKey != GovernanceKeys::VOCFee && typeKey != GovernanceKeys::VOCApprovalThreshold &&
                     typeKey != GovernanceKeys::VOCEmergencyPeriod && typeKey != GovernanceKeys::VOCEmergencyFee &&
                     typeKey != GovernanceKeys::VOCEmergencyQuorum && typeKey != GovernanceKeys::Quorum &&
-                    typeKey != GovernanceKeys::VotingPeriod)
+                    typeKey != GovernanceKeys::VotingPeriod && typeKey != GovernanceKeys::CFPMaxCycles)
                     return Res::Err("Unsupported key for Governance Proposal section - {%d}", typeKey);
             } else {
                 return Res::Err("Unsupported Governance ID");
diff --git a/src/masternodes/govvariables/attributes.h b/src/masternodes/govvariables/attributes.h
index 575b9a5e01..380330c9e1 100644
--- a/src/masternodes/govvariables/attributes.h
+++ b/src/masternodes/govvariables/attributes.h
@@ -99,6 +99,7 @@ enum GovernanceKeys : uint8_t {
     Quorum                  = 'j',
     VotingPeriod            = 'k',
     VOCEmergencyQuorum      = 'l',
+    CFPMaxCycles            = 'm',
 };
 
 enum TokenKeys : uint8_t {
diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp
index 67bff3dd9d..03acb69e64 100644
--- a/src/masternodes/mn_checks.cpp
+++ b/src/masternodes/mn_checks.cpp
@@ -4430,8 +4430,13 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor {
         if (obj.contextHash.size() > MAX_PROP_CONTEXT_SIZE)
             return Res::Err("proposal context hash cannot be more than %d bytes", MAX_PROP_CONTEXT_SIZE);
 
-        if (obj.nCycles < 1 || obj.nCycles > MAX_CYCLES)
-            return Res::Err("proposal cycles can be between 1 and %d", int(MAX_CYCLES));
+        auto attributes = mnview.GetAttributes();
+        assert(attributes);
+        CDataStructureV0 cfpMaxCycles{AttributeTypes::Governance, GovernanceIDs::Proposals, GovernanceKeys::CFPMaxCycles};
+        auto maxCycles = attributes->GetValue(cfpMaxCycles, static_cast<uint32_t>(MAX_CYCLES));
+
+        if (obj.nCycles < 1 || obj.nCycles > maxCycles )
+            return Res::Err("proposal cycles can be between 1 and %d", maxCycles);
 
         if ((obj.options & CPropOption::Emergency)) {
             if (obj.nCycles != 1) {

From e1137416a2a03dc2fb6b01c91ba66b94c18f6192 Mon Sep 17 00:00:00 2001
From: Jouzo <15011228+Jouzo@users.noreply.github.com>
Date: Fri, 23 Dec 2022 12:42:19 +0100
Subject: [PATCH 9/9] Fix typo

---
 src/masternodes/govvariables/attributes.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/masternodes/govvariables/attributes.cpp b/src/masternodes/govvariables/attributes.cpp
index 26266f97f6..3601797d78 100644
--- a/src/masternodes/govvariables/attributes.cpp
+++ b/src/masternodes/govvariables/attributes.cpp
@@ -205,7 +205,7 @@ const std::map<uint8_t, std::map<std::string, uint8_t>> &ATTRIBUTES::allowedKeys
              {"voc_approval_threshold", GovernanceKeys::VOCApprovalThreshold},
              {"quorum", GovernanceKeys::Quorum},
              {"voting_period", GovernanceKeys::VotingPeriod},
-             {"cfo_max_cycles", GovernanceKeys::CFPMaxCycles},
+             {"cfp_max_cycles", GovernanceKeys::CFPMaxCycles},
          }},
     };
     return keys;